[libc][NFC] Introduce a Sign type for FPBits (#78500)

Another patch is needed to cover `DyadicFloat` and `NormalFloat`
constructors.
This commit is contained in:
Guillaume Chatelet 2024-01-18 13:40:49 +01:00 committed by GitHub
parent 9acc404230
commit 11ec512f44
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
67 changed files with 427 additions and 372 deletions

View File

@ -20,23 +20,23 @@ namespace fputil {
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
LIBC_INLINE T abs(T x) {
FPBits<T> bits(x);
bits.set_sign(0);
bits.set_sign(Sign::POS);
return T(bits);
}
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
LIBC_INLINE T fmin(T x, T y) {
FPBits<T> bitx(x), bity(y);
const FPBits<T> bitx(x), bity(y);
if (bitx.is_nan()) {
return y;
} else if (bity.is_nan()) {
return x;
} else if (bitx.get_sign() != bity.get_sign()) {
} else if (bitx.sign() != bity.sign()) {
// To make sure that fmin(+0, -0) == -0 == fmin(-0, +0), whenever x and
// y has different signs and both are not NaNs, we return the number
// with negative sign.
return (bitx.get_sign() ? x : y);
return (bitx.is_neg()) ? x : y;
} else {
return (x < y ? x : y);
}
@ -50,11 +50,11 @@ LIBC_INLINE T fmax(T x, T y) {
return y;
} else if (bity.is_nan()) {
return x;
} else if (bitx.get_sign() != bity.get_sign()) {
} else if (bitx.sign() != bity.sign()) {
// To make sure that fmax(+0, -0) == +0 == fmax(-0, +0), whenever x and
// y has different signs and both are not NaNs, we return the number
// with positive sign.
return (bitx.get_sign() ? y : x);
return (bitx.is_neg() ? y : x);
} else {
return (x > y ? x : y);
}

View File

@ -43,13 +43,14 @@ LIBC_INLINE T remquo(T x, T y, int &q) {
return x;
}
bool result_sign = (xbits.get_sign() == ybits.get_sign() ? false : true);
const Sign result_sign =
(xbits.sign() == ybits.sign() ? Sign::POS : Sign::NEG);
// Once we know the sign of the result, we can just operate on the absolute
// values. The correct sign can be applied to the result after the result
// is evaluated.
xbits.set_sign(0);
ybits.set_sign(0);
xbits.set_sign(Sign::POS);
ybits.set_sign(Sign::POS);
NormalFloat<T> normalx(xbits), normaly(ybits);
int exp = normalx.exponent - normaly.exponent;
@ -72,7 +73,7 @@ LIBC_INLINE T remquo(T x, T y, int &q) {
mx = n - my;
if (mx == 0) {
q = result_sign ? -q : q;
q = result_sign.is_neg() ? -q : q;
return LIBC_NAMESPACE::fputil::copysign(T(0.0), x);
}
}
@ -107,7 +108,7 @@ LIBC_INLINE T remquo(T x, T y, int &q) {
native_remainder = -native_remainder;
}
q = result_sign ? -q : q;
q = result_sign.is_neg() ? -q : q;
if (native_remainder == T(0.0))
return LIBC_NAMESPACE::fputil::copysign(T(0.0), x);
return native_remainder;

View File

@ -31,6 +31,32 @@ enum class FPType {
X86_Binary80,
};
// A type to interact with floating point type signs.
// This may be moved outside of 'fputil' if useful.
struct Sign {
LIBC_INLINE constexpr bool is_pos() const { return !is_negative; }
LIBC_INLINE constexpr bool is_neg() const { return is_negative; }
LIBC_INLINE friend constexpr bool operator==(Sign a, Sign b) {
return a.is_negative == b.is_negative;
}
LIBC_INLINE friend constexpr bool operator!=(Sign a, Sign b) {
return !(a == b);
}
static const Sign POS;
static const Sign NEG;
private:
LIBC_INLINE constexpr explicit Sign(bool is_negative)
: is_negative(is_negative) {}
bool is_negative;
};
LIBC_INLINE_VAR constexpr Sign Sign::NEG = Sign(true);
LIBC_INLINE_VAR constexpr Sign Sign::POS = Sign(false);
// The classes hierarchy is as follows:
//
// ┌───────────────────┐
@ -273,9 +299,9 @@ protected:
return encode(exp) | encode(sig);
}
LIBC_INLINE static constexpr StorageType encode(bool sign, BiasedExponent exp,
LIBC_INLINE static constexpr StorageType encode(Sign sign, BiasedExponent exp,
Significand sig) {
if (sign)
if (sign.is_neg())
return SIGN_MASK | encode(exp, sig);
return encode(exp, sig);
}
@ -309,12 +335,12 @@ protected:
StorageType bits = 0;
public:
LIBC_INLINE constexpr bool get_sign() const {
return (bits & SIGN_MASK) != 0;
LIBC_INLINE constexpr Sign sign() const {
return (bits & SIGN_MASK) ? Sign::NEG : Sign::POS;
}
LIBC_INLINE constexpr void set_sign(bool signVal) {
if (get_sign() != signVal)
LIBC_INLINE constexpr void set_sign(Sign signVal) {
if (sign() != signVal)
bits ^= SIGN_MASK;
}
@ -363,6 +389,9 @@ public:
LIBC_INLINE constexpr bool is_zero() const {
return (bits & EXP_SIG_MASK) == 0;
}
LIBC_INLINE constexpr bool is_neg() const { return sign().is_neg(); }
LIBC_INLINE constexpr bool is_pos() const { return sign().is_pos(); }
};
namespace internal {
@ -421,35 +450,37 @@ public:
return is_finite() && !is_subnormal();
}
LIBC_INLINE static constexpr StorageType zero(bool sign = false) {
LIBC_INLINE static constexpr StorageType zero(Sign sign = Sign::POS) {
return encode(sign, BiasedExponent::BITS_ALL_ZEROES(), Significand::ZERO());
}
LIBC_INLINE static constexpr StorageType one(bool sign = false) {
LIBC_INLINE static constexpr StorageType one(Sign sign = Sign::POS) {
return encode(sign, Exponent::ZERO(), Significand::ZERO());
}
LIBC_INLINE static constexpr StorageType min_subnormal(bool sign = false) {
LIBC_INLINE static constexpr StorageType
min_subnormal(Sign sign = Sign::POS) {
return encode(sign, BiasedExponent::BITS_ALL_ZEROES(), Significand::LSB());
}
LIBC_INLINE static constexpr StorageType max_subnormal(bool sign = false) {
LIBC_INLINE static constexpr StorageType
max_subnormal(Sign sign = Sign::POS) {
return encode(sign, BiasedExponent::BITS_ALL_ZEROES(),
Significand::BITS_ALL_ONES());
}
LIBC_INLINE static constexpr StorageType min_normal(bool sign = false) {
LIBC_INLINE static constexpr StorageType min_normal(Sign sign = Sign::POS) {
return encode(sign, Exponent::MIN(), Significand::ZERO());
}
LIBC_INLINE static constexpr StorageType max_normal(bool sign = false) {
LIBC_INLINE static constexpr StorageType max_normal(Sign sign = Sign::POS) {
return encode(sign, Exponent::MAX(), Significand::BITS_ALL_ONES());
}
LIBC_INLINE static constexpr StorageType inf(bool sign = false) {
LIBC_INLINE static constexpr StorageType inf(Sign sign = Sign::POS) {
return encode(sign, BiasedExponent::BITS_ALL_ONES(), Significand::ZERO());
}
LIBC_INLINE static constexpr StorageType build_nan(bool sign = false,
LIBC_INLINE static constexpr StorageType build_nan(Sign sign = Sign::POS,
StorageType v = 0) {
return encode(sign, BiasedExponent::BITS_ALL_ONES(),
(v ? Significand(v) : (Significand::MSB() >> 1)));
}
LIBC_INLINE static constexpr StorageType build_quiet_nan(bool sign = false,
StorageType v = 0) {
LIBC_INLINE static constexpr StorageType
build_quiet_nan(Sign sign = Sign::POS, StorageType v = 0) {
return encode(sign, BiasedExponent::BITS_ALL_ONES(),
Significand::MSB() | Significand(v));
}
@ -539,36 +570,38 @@ public:
return get_implicit_bit();
}
LIBC_INLINE static constexpr StorageType zero(bool sign = false) {
LIBC_INLINE static constexpr StorageType zero(Sign sign = Sign::POS) {
return encode(sign, BiasedExponent::BITS_ALL_ZEROES(), Significand::ZERO());
}
LIBC_INLINE static constexpr StorageType one(bool sign = false) {
LIBC_INLINE static constexpr StorageType one(Sign sign = Sign::POS) {
return encode(sign, Exponent::ZERO(), Significand::MSB());
}
LIBC_INLINE static constexpr StorageType min_subnormal(bool sign = false) {
LIBC_INLINE static constexpr StorageType
min_subnormal(Sign sign = Sign::POS) {
return encode(sign, BiasedExponent::BITS_ALL_ZEROES(), Significand::LSB());
}
LIBC_INLINE static constexpr StorageType max_subnormal(bool sign = false) {
LIBC_INLINE static constexpr StorageType
max_subnormal(Sign sign = Sign::POS) {
return encode(sign, BiasedExponent::BITS_ALL_ZEROES(),
Significand::BITS_ALL_ONES() ^ Significand::MSB());
}
LIBC_INLINE static constexpr StorageType min_normal(bool sign = false) {
LIBC_INLINE static constexpr StorageType min_normal(Sign sign = Sign::POS) {
return encode(sign, Exponent::MIN(), Significand::MSB());
}
LIBC_INLINE static constexpr StorageType max_normal(bool sign = false) {
LIBC_INLINE static constexpr StorageType max_normal(Sign sign = Sign::POS) {
return encode(sign, Exponent::MAX(), Significand::BITS_ALL_ONES());
}
LIBC_INLINE static constexpr StorageType inf(bool sign = false) {
LIBC_INLINE static constexpr StorageType inf(Sign sign = Sign::POS) {
return encode(sign, BiasedExponent::BITS_ALL_ONES(), Significand::MSB());
}
LIBC_INLINE static constexpr StorageType build_nan(bool sign = false,
LIBC_INLINE static constexpr StorageType build_nan(Sign sign = Sign::POS,
StorageType v = 0) {
return encode(sign, BiasedExponent::BITS_ALL_ONES(),
Significand::MSB() |
(v ? Significand(v) : (Significand::MSB() >> 2)));
}
LIBC_INLINE static constexpr StorageType build_quiet_nan(bool sign = false,
StorageType v = 0) {
LIBC_INLINE static constexpr StorageType
build_quiet_nan(Sign sign = Sign::POS, StorageType v = 0) {
return encode(sign, BiasedExponent::BITS_ALL_ONES(),
Significand::MSB() | (Significand::MSB() >> 1) |
Significand(v));
@ -642,10 +675,10 @@ template <typename T> struct FPBits : public internal::FPRep<get_fp_type<T>()> {
// Constants.
static constexpr int MAX_BIASED_EXPONENT = (1 << EXP_LEN) - 1;
static constexpr StorageType MIN_NORMAL = UP::min_normal(false);
static constexpr StorageType MAX_NORMAL = UP::max_normal(false);
static constexpr StorageType MIN_SUBNORMAL = UP::min_subnormal(false);
static constexpr StorageType MAX_SUBNORMAL = UP::max_subnormal(false);
static constexpr StorageType MIN_NORMAL = UP::min_normal(Sign::POS);
static constexpr StorageType MAX_NORMAL = UP::max_normal(Sign::POS);
static constexpr StorageType MIN_SUBNORMAL = UP::min_subnormal(Sign::POS);
static constexpr StorageType MAX_SUBNORMAL = UP::max_subnormal(Sign::POS);
// Constructors.
LIBC_INLINE constexpr FPBits() = default;
@ -675,45 +708,46 @@ template <typename T> struct FPBits : public internal::FPRep<get_fp_type<T>()> {
// Methods below this are used by tests.
LIBC_INLINE static constexpr T zero(bool sign = false) {
LIBC_INLINE static constexpr T one(Sign sign = Sign::POS) {
return FPBits(UP::one(sign)).get_val();
}
LIBC_INLINE static constexpr T zero(Sign sign = Sign::POS) {
return FPBits(UP::zero(sign)).get_val();
}
LIBC_INLINE static constexpr T neg_zero() { return zero(true); }
LIBC_INLINE static constexpr T inf(bool sign = false) {
LIBC_INLINE static constexpr T inf(Sign sign = Sign::POS) {
return FPBits(UP::inf(sign)).get_val();
}
LIBC_INLINE static constexpr T neg_inf() { return inf(true); }
LIBC_INLINE static constexpr T min_normal() {
return FPBits(UP::min_normal(false)).get_val();
return FPBits(UP::min_normal(Sign::POS)).get_val();
}
LIBC_INLINE static constexpr T max_normal() {
return FPBits(UP::max_normal(false)).get_val();
return FPBits(UP::max_normal(Sign::POS)).get_val();
}
LIBC_INLINE static constexpr T min_denormal() {
return FPBits(UP::min_subnormal(false)).get_val();
return FPBits(UP::min_subnormal(Sign::POS)).get_val();
}
LIBC_INLINE static constexpr T max_denormal() {
return FPBits(UP::max_subnormal(false)).get_val();
return FPBits(UP::max_subnormal(Sign::POS)).get_val();
}
LIBC_INLINE static constexpr T build_nan(StorageType v) {
return FPBits(UP::build_nan(false, v)).get_val();
return FPBits(UP::build_nan(Sign::POS, v)).get_val();
}
LIBC_INLINE static constexpr T build_quiet_nan(StorageType v) {
return FPBits(UP::build_quiet_nan(false, v)).get_val();
LIBC_INLINE static constexpr T build_quiet_nan(StorageType v,
Sign sign = Sign::POS) {
return FPBits(UP::build_quiet_nan(sign, v)).get_val();
}
// TODO: Use an uint32_t for 'biased_exp'.
LIBC_INLINE static constexpr FPBits<T>
create_value(bool sign, StorageType biased_exp, StorageType mantissa) {
create_value(Sign sign, StorageType biased_exp, StorageType mantissa) {
static_assert(get_fp_type<T>() != FPType::X86_Binary80,
"This function is not tested for X86 Extended Precision");
return FPBits(UP::encode(

View File

@ -49,13 +49,13 @@ LIBC_INLINE T modf(T x, T &iptr) {
return x;
} else if (bits.is_inf()) {
iptr = x;
return bits.get_sign() ? T(FPBits<T>::neg_zero()) : T(FPBits<T>::zero());
return T(FPBits<T>::zero(bits.sign()));
} else {
iptr = trunc(x);
if (x == iptr) {
// If x is already an integer value, then return zero with the right
// sign.
return bits.get_sign() ? T(FPBits<T>::neg_zero()) : T(FPBits<T>::zero());
return T(FPBits<T>::zero(bits.sign()));
} else {
return x - iptr;
}
@ -65,7 +65,7 @@ LIBC_INLINE T modf(T x, T &iptr) {
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
LIBC_INLINE T copysign(T x, T y) {
FPBits<T> xbits(x);
xbits.set_sign(FPBits<T>(y).get_sign());
xbits.set_sign(FPBits<T>(y).sign());
return T(xbits);
}
@ -103,12 +103,12 @@ LIBC_INLINE T logb(T x) {
if (bits.is_zero()) {
// TODO(Floating point exception): Raise div-by-zero exception.
// TODO(errno): POSIX requires setting errno to ERANGE.
return T(FPBits<T>::neg_inf());
return T(FPBits<T>::inf(Sign::NEG));
} else if (bits.is_nan()) {
return x;
} else if (bits.is_inf()) {
// Return positive infinity.
return T(FPBits<T>::inf());
return T(FPBits<T>::inf(Sign::POS));
}
NormalFloat<T> normal(bits);
@ -131,11 +131,11 @@ LIBC_INLINE T ldexp(T x, int exp) {
// calculating the limit.
int exp_limit = FPBits<T>::MAX_BIASED_EXPONENT + FPBits<T>::FRACTION_LEN + 1;
if (exp > exp_limit)
return bits.get_sign() ? T(FPBits<T>::neg_inf()) : T(FPBits<T>::inf());
return T(FPBits<T>::inf(bits.sign()));
// Similarly on the negative side we return zero early if |exp| is too small.
if (exp < -exp_limit)
return bits.get_sign() ? T(FPBits<T>::neg_zero()) : T(FPBits<T>::zero());
return T(FPBits<T>::zero(bits.sign()));
// For all other values, NormalFloat to T conversion handles it the right way.
NormalFloat<T> normal(bits);
@ -173,7 +173,7 @@ LIBC_INLINE T nextafter(T from, U to) {
}
} else {
int_val = FPBits<T>::MIN_SUBNORMAL;
if (to_bits.get_sign())
if (to_bits.is_neg())
int_val |= FPBits<T>::SIGN_MASK;
}

View File

@ -40,12 +40,8 @@ LIBC_INLINE T trunc(T x) {
return x;
// If the exponent is such that abs(x) is less than 1, then return 0.
if (exponent <= -1) {
if (bits.get_sign())
return T(-0.0);
else
return T(0.0);
}
if (exponent <= -1)
return T(FPBits<T>::zero(bits.sign()));
int trim_size = FPBits<T>::FRACTION_LEN - exponent;
bits.set_mantissa((bits.get_mantissa() >> trim_size) << trim_size);
@ -60,7 +56,7 @@ LIBC_INLINE T ceil(T x) {
if (bits.is_inf_or_nan() || bits.is_zero())
return x;
bool is_neg = bits.get_sign();
bool is_neg = bits.is_neg();
int exponent = bits.get_exponent();
// If the exponent is greater than the most negative mantissa
@ -93,7 +89,7 @@ LIBC_INLINE T ceil(T x) {
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
LIBC_INLINE T floor(T x) {
FPBits<T> bits(x);
if (bits.get_sign()) {
if (bits.is_neg()) {
return -ceil(-x);
} else {
return trunc(x);
@ -109,7 +105,6 @@ LIBC_INLINE T round(T x) {
if (bits.is_inf_or_nan() || bits.is_zero())
return x;
bool is_neg = bits.get_sign();
int exponent = bits.get_exponent();
// If the exponent is greater than the most negative mantissa
@ -119,18 +114,12 @@ LIBC_INLINE T round(T x) {
if (exponent == -1) {
// Absolute value of x is greater than equal to 0.5 but less than 1.
if (is_neg)
return T(-1.0);
else
return T(1.0);
return T(FPBits<T>::one(bits.sign()));
}
if (exponent <= -2) {
// Absolute value of x is less than 0.5.
if (is_neg)
return T(-0.0);
else
return T(0.0);
return T(FPBits<T>::zero(bits.sign()));
}
uint32_t trim_size = FPBits<T>::FRACTION_LEN - exponent;
@ -148,7 +137,7 @@ LIBC_INLINE T round(T x) {
// same as the trunc value.
return trunc_value;
} else {
return is_neg ? trunc_value - T(1.0) : trunc_value + T(1.0);
return bits.is_neg() ? trunc_value - T(1.0) : trunc_value + T(1.0);
}
}
@ -161,7 +150,7 @@ LIBC_INLINE T round_using_current_rounding_mode(T x) {
if (bits.is_inf_or_nan() || bits.is_zero())
return x;
bool is_neg = bits.get_sign();
bool is_neg = bits.is_neg();
int exponent = bits.get_exponent();
int rounding_mode = quick_get_round();
@ -247,18 +236,18 @@ LIBC_INLINE I rounded_float_to_signed_integer(F x) {
if (bits.is_inf_or_nan()) {
set_domain_error_and_raise_invalid();
return bits.get_sign() ? INTEGER_MIN : INTEGER_MAX;
return bits.is_neg() ? INTEGER_MIN : INTEGER_MAX;
}
int exponent = bits.get_exponent();
constexpr int EXPONENT_LIMIT = sizeof(I) * 8 - 1;
if (exponent > EXPONENT_LIMIT) {
set_domain_error_and_raise_invalid();
return bits.get_sign() ? INTEGER_MIN : INTEGER_MAX;
return bits.is_neg() ? INTEGER_MIN : INTEGER_MAX;
} else if (exponent == EXPONENT_LIMIT) {
if (bits.get_sign() == 0 || bits.get_mantissa() != 0) {
if (bits.is_pos() || bits.get_mantissa() != 0) {
set_domain_error_and_raise_invalid();
return bits.get_sign() ? INTEGER_MIN : INTEGER_MAX;
return bits.is_neg() ? INTEGER_MIN : INTEGER_MAX;
}
// If the control reaches here, then it means that the rounded
// value is the most negative number for the signed integer type I.

View File

@ -44,10 +44,10 @@ template <typename T> struct NormalFloat {
static_assert(sizeof(StorageType) * 8 >= FPBits<T>::FRACTION_LEN + 1,
"Bad type for mantissa in NormalFloat.");
bool sign;
Sign sign = Sign::POS;
LIBC_INLINE NormalFloat(int32_t e, StorageType m, bool s)
: exponent(e), mantissa(m), sign(s) {
: exponent(e), mantissa(m), sign(s ? Sign::NEG : Sign::POS) {
if (mantissa >= ONE)
return;
@ -64,20 +64,21 @@ template <typename T> struct NormalFloat {
// Returns -1 is this number is less than |other|, 0 if this number is equal
// to |other|, and 1 if this number is greater than |other|.
LIBC_INLINE int cmp(const NormalFloat<T> &other) const {
const int result = sign.is_neg() ? -1 : 1;
if (sign != other.sign)
return sign ? -1 : 1;
return result;
if (exponent > other.exponent) {
return sign ? -1 : 1;
return result;
} else if (exponent == other.exponent) {
if (mantissa > other.mantissa)
return sign ? -1 : 1;
return result;
else if (mantissa == other.mantissa)
return 0;
else
return sign ? 1 : -1;
return -result;
} else {
return sign ? 1 : -1;
return -result;
}
}
@ -95,7 +96,7 @@ template <typename T> struct NormalFloat {
// Max exponent is of the form 0xFF...E. That is why -2 and not -1.
constexpr int MAX_EXPONENT_VALUE = (1 << FPBits<T>::EXP_LEN) - 2;
if (biased_exponent > MAX_EXPONENT_VALUE) {
return sign ? T(FPBits<T>::neg_inf()) : T(FPBits<T>::inf());
return T(FPBits<T>::inf(sign));
}
FPBits<T> result(T(0.0));
@ -141,7 +142,7 @@ template <typename T> struct NormalFloat {
private:
LIBC_INLINE void init_from_bits(FPBits<T> bits) {
sign = bits.get_sign();
sign = bits.sign();
if (bits.is_inf_or_nan() || bits.is_zero()) {
// Ignore special bit patterns. Implementations deal with them separately
@ -175,7 +176,7 @@ private:
template <>
LIBC_INLINE void
NormalFloat<long double>::init_from_bits(FPBits<long double> bits) {
sign = bits.get_sign();
sign = bits.sign();
if (bits.is_inf_or_nan() || bits.is_zero()) {
// Ignore special bit patterns. Implementations deal with them separately
@ -214,7 +215,7 @@ template <> LIBC_INLINE NormalFloat<long double>::operator long double() const {
// Max exponent is of the form 0xFF...E. That is why -2 and not -1.
constexpr int MAX_EXPONENT_VALUE = (1 << LDBits::EXP_LEN) - 2;
if (biased_exponent > MAX_EXPONENT_VALUE) {
return sign ? LDBits::neg_inf() : LDBits::inf();
return LDBits::inf(sign);
}
FPBits<long double> result(0.0l);

View File

@ -33,7 +33,7 @@ namespace LIBC_NAMESPACE::fputil {
template <size_t Bits> struct DyadicFloat {
using MantissaType = LIBC_NAMESPACE::cpp::UInt<Bits>;
bool sign = false;
Sign sign = Sign::POS;
int exponent = 0;
MantissaType mantissa = MantissaType(0);
@ -43,14 +43,14 @@ template <size_t Bits> struct DyadicFloat {
DyadicFloat(T x) {
static_assert(FPBits<T>::FRACTION_LEN < Bits);
FPBits<T> x_bits(x);
sign = x_bits.get_sign();
sign = x_bits.sign();
exponent = x_bits.get_exponent() - FPBits<T>::FRACTION_LEN;
mantissa = MantissaType(x_bits.get_explicit_mantissa());
normalize();
}
constexpr DyadicFloat(bool s, int e, MantissaType m)
: sign(s), exponent(e), mantissa(m) {
: sign(s ? Sign::NEG : Sign::POS), exponent(e), mantissa(m) {
normalize();
}
@ -172,7 +172,7 @@ template <size_t Bits> struct DyadicFloat {
new_mant >>= (-exponent);
}
if (sign) {
if (sign.is_neg()) {
new_mant = (~new_mant) + 1;
}
@ -251,7 +251,7 @@ template <size_t Bits>
constexpr DyadicFloat<Bits> quick_mul(DyadicFloat<Bits> a,
DyadicFloat<Bits> b) {
DyadicFloat<Bits> result;
result.sign = (a.sign != b.sign);
result.sign = (a.sign != b.sign) ? Sign::NEG : Sign::POS;
result.exponent = a.exponent + b.exponent + int(Bits);
if (!(a.mantissa.is_zero() || b.mantissa.is_zero())) {

View File

@ -35,13 +35,16 @@ using ZeroPaddedHexFmt = IntegerToString<
// floating encoding.
template <typename T> LIBC_INLINE cpp::string str(fputil::FPBits<T> x) {
using StorageType = typename fputil::FPBits<T>::StorageType;
using Sign = fputil::Sign;
if (x.is_nan())
return "(NaN)";
if (x.is_inf())
return x.get_sign() ? "(-Infinity)" : "(+Infinity)";
return x.is_neg() ? "(-Infinity)" : "(+Infinity)";
const auto sign_char = [](bool sign) -> char { return sign ? '1' : '0'; };
const auto sign_char = [](Sign sign) -> char {
return sign.is_neg() ? '1' : '0';
};
cpp::string s;
@ -49,7 +52,7 @@ template <typename T> LIBC_INLINE cpp::string str(fputil::FPBits<T> x) {
s += bits.view();
s += " = (S: ";
s += sign_char(x.get_sign());
s += sign_char(x.sign());
s += ", E: ";
const details::ZeroPaddedHexFmt<uint16_t> exponent(x.get_biased_exponent());
@ -57,7 +60,7 @@ template <typename T> LIBC_INLINE cpp::string str(fputil::FPBits<T> x) {
if constexpr (fputil::get_fp_type<T>() == fputil::FPType::X86_Binary80) {
s += ", I: ";
s += sign_char(x.get_implicit_bit());
s += sign_char(x.get_implicit_bit() ? Sign::NEG : Sign::POS);
}
s += ", M: ";

View File

@ -64,7 +64,7 @@ template <> LIBC_INLINE float fma<float>(float x, float y, float z) {
// Update sticky bits if t != 0.0 and the least (52 - 23 - 1 = 28) bits are
// zero.
if (!t.is_zero() && ((bit_sum.get_mantissa() & 0xfff'ffffULL) == 0)) {
if (bit_sum.get_sign() != t.get_sign()) {
if (bit_sum.sign() != t.sign()) {
bit_sum.set_mantissa(bit_sum.get_mantissa() + 1);
} else if (bit_sum.get_mantissa()) {
bit_sum.set_mantissa(bit_sum.get_mantissa() - 1);
@ -118,10 +118,8 @@ template <> LIBC_INLINE double fma<double>(double x, double y, double z) {
}
FPBits x_bits(x), y_bits(y), z_bits(z);
bool x_sign = x_bits.get_sign();
bool y_sign = y_bits.get_sign();
bool z_sign = z_bits.get_sign();
bool prod_sign = x_sign != y_sign;
const Sign z_sign = z_bits.sign();
Sign prod_sign = (x_bits.sign() == y_bits.sign()) ? Sign::POS : Sign::NEG;
x_exp += x_bits.get_biased_exponent();
y_exp += y_bits.get_biased_exponent();
z_exp += z_bits.get_biased_exponent();
@ -248,27 +246,26 @@ template <> LIBC_INLINE double fma<double>(double x, double y, double z) {
}
} else {
// Return +0.0 when there is exact cancellation, i.e., x*y == -z exactly.
prod_sign = false;
prod_sign = Sign::POS;
}
// Finalize the result.
int round_mode = fputil::quick_get_round();
if (LIBC_UNLIKELY(r_exp >= FPBits::MAX_BIASED_EXPONENT)) {
if ((round_mode == FE_TOWARDZERO) ||
(round_mode == FE_UPWARD && prod_sign) ||
(round_mode == FE_DOWNWARD && !prod_sign)) {
(round_mode == FE_UPWARD && prod_sign.is_neg()) ||
(round_mode == FE_DOWNWARD && prod_sign.is_pos())) {
result = FPBits::MAX_NORMAL;
return prod_sign ? -cpp::bit_cast<double>(result)
: cpp::bit_cast<double>(result);
return prod_sign.is_neg() ? -cpp::bit_cast<double>(result)
: cpp::bit_cast<double>(result);
}
return prod_sign ? static_cast<double>(FPBits::neg_inf())
: static_cast<double>(FPBits::inf());
return static_cast<double>(FPBits::inf(prod_sign));
}
// Remove hidden bit and append the exponent field and sign bit.
result = (result & FPBits::FRACTION_MASK) |
(static_cast<uint64_t>(r_exp) << FPBits::FRACTION_LEN);
if (prod_sign) {
if (prod_sign.is_neg()) {
result |= FPBits::SIGN_MASK;
}
@ -276,8 +273,8 @@ template <> LIBC_INLINE double fma<double>(double x, double y, double z) {
if (round_mode == FE_TONEAREST) {
if (round_bit && (sticky_bits || ((result & 1) != 0)))
++result;
} else if ((round_mode == FE_UPWARD && !prod_sign) ||
(round_mode == FE_DOWNWARD && prod_sign)) {
} else if ((round_mode == FE_UPWARD && prod_sign.is_pos()) ||
(round_mode == FE_DOWNWARD && prod_sign.is_neg())) {
if (round_bit || sticky_bits)
++result;
}

View File

@ -308,9 +308,9 @@ public:
if (T out; Wrapper::pre_check(x, y, out))
return out;
FPB sx(x), sy(y);
bool sign = sx.get_sign();
sx.set_sign(false);
sy.set_sign(false);
Sign sign = sx.sign();
sx.set_sign(Sign::POS);
sy.set_sign(Sign::POS);
FPB result = eval_internal(sx, sy);
result.set_sign(sign);
return result.get_val();

View File

@ -77,7 +77,7 @@ LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, T> sqrt(T x) {
FPBits<T> bits(x);
if (bits.is_inf_or_nan()) {
if (bits.get_sign() && (bits.get_mantissa() == 0)) {
if (bits.is_neg() && (bits.get_mantissa() == 0)) {
// sqrt(-Inf) = NaN
return FPBits<T>::build_quiet_nan(ONE >> 1);
} else {
@ -89,7 +89,7 @@ LIBC_INLINE cpp::enable_if_t<cpp::is_floating_point_v<T>, T> sqrt(T x) {
// sqrt(+0) = +0
// sqrt(-0) = -0
return x;
} else if (bits.get_sign()) {
} else if (bits.is_neg()) {
// sqrt( negative numbers ) = NaN
return FPBits<T>::build_quiet_nan(ONE >> 1);
} else {

View File

@ -43,7 +43,7 @@ LIBC_INLINE long double sqrt(long double x) {
FPBits<long double> bits(x);
if (bits.is_inf_or_nan()) {
if (bits.get_sign() && (bits.get_mantissa() == 0)) {
if (bits.is_neg() && (bits.get_mantissa() == 0)) {
// sqrt(-Inf) = NaN
return LDBits::build_quiet_nan(ONE >> 1);
} else {
@ -55,7 +55,7 @@ LIBC_INLINE long double sqrt(long double x) {
// sqrt(+0) = +0
// sqrt(-0) = -0
return x;
} else if (bits.get_sign()) {
} else if (bits.is_neg()) {
// sqrt( negative numbers ) = NaN
return LDBits::build_quiet_nan(ONE >> 1);
} else {

View File

@ -412,7 +412,6 @@ LIBC_INLINE uint32_t mul_shift_mod_1e9(const FPBits::StorageType mantissa,
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
class FloatToString {
fputil::FPBits<T> float_bits;
bool is_negative;
int exponent;
FPBits::StorageType mantissa;
@ -421,14 +420,11 @@ class FloatToString {
public:
LIBC_INLINE constexpr FloatToString(T init_float) : float_bits(init_float) {
is_negative = float_bits.get_sign();
exponent = float_bits.get_explicit_exponent();
mantissa = float_bits.get_explicit_mantissa();
// Adjust for the width of the mantissa.
exponent -= FRACTION_LEN;
// init_convert();
}
LIBC_INLINE constexpr bool is_nan() { return float_bits.is_nan(); }

View File

@ -1072,6 +1072,7 @@ template <class T>
LIBC_INLINE StrToNumResult<T> strtofloatingpoint(const char *__restrict src) {
using FPBits = typename fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
using Sign = fputil::Sign;
FPBits result = FPBits();
bool seen_digit = false;
@ -1087,7 +1088,7 @@ LIBC_INLINE StrToNumResult<T> strtofloatingpoint(const char *__restrict src) {
}
if (sign == '-') {
result.set_sign(true);
result.set_sign(Sign::NEG);
}
static constexpr char DECIMAL_POINT = '.';
@ -1165,22 +1166,13 @@ LIBC_INLINE StrToNumResult<T> strtofloatingpoint(const char *__restrict src) {
index = left_paren;
}
}
if (result.get_sign()) {
result = FPBits(result.build_quiet_nan(nan_mantissa));
result.set_sign(true);
} else {
result = FPBits(result.build_quiet_nan(nan_mantissa));
}
result = FPBits(result.build_quiet_nan(nan_mantissa, result.sign()));
}
} else if (tolower(src[index]) == 'i') { // INF
if (tolower(src[index + 1]) == inf_string[1] &&
tolower(src[index + 2]) == inf_string[2]) {
seen_digit = true;
if (result.get_sign())
result = FPBits(result.neg_inf());
else
result = FPBits(result.inf());
result = FPBits(result.inf(result.sign()));
if (tolower(src[index + 3]) == inf_string[3] &&
tolower(src[index + 4]) == inf_string[4] &&
tolower(src[index + 5]) == inf_string[5] &&

View File

@ -38,6 +38,7 @@ static constexpr fputil::ExceptValues<float, N_EXCEPTS> ACOSF_EXCEPTS = {{
LLVM_LIBC_FUNCTION(float, acosf, (float x)) {
using FPBits = typename fputil::FPBits<float>;
using Sign = fputil::Sign;
FPBits xbits(x);
uint32_t x_uint = xbits.uintval();
uint32_t x_abs = xbits.uintval() & 0x7fff'ffffU;
@ -109,7 +110,7 @@ LLVM_LIBC_FUNCTION(float, acosf, (float x)) {
// acos(x) = pi - acos(-x)
// which is reduced to the postive case.
xbits.set_sign(false);
xbits.set_sign(Sign::POS);
double xd = static_cast<double>(xbits.get_val());
double u = fputil::multiply_add(-0.5, xd, 0.5);
double cv = 2 * fputil::sqrt(u);

View File

@ -44,6 +44,7 @@ static constexpr fputil::ExceptValues<float, N_EXCEPTS> ASINF_EXCEPTS_HI = {{
LLVM_LIBC_FUNCTION(float, asinf, (float x)) {
using FPBits = typename fputil::FPBits<float>;
using Sign = fputil::Sign;
FPBits xbits(x);
uint32_t x_uint = xbits.uintval();
uint32_t x_abs = xbits.uintval() & 0x7fff'ffffU;
@ -139,7 +140,7 @@ LLVM_LIBC_FUNCTION(float, asinf, (float x)) {
// |x| <= 0.5:
// asin(x) ~ pi/2 - 2 * sqrt(u) * P(u),
xbits.set_sign(false);
xbits.set_sign(Sign::POS);
double sign = SIGN[x_sign];
double xd = static_cast<double>(xbits.get_val());
double u = fputil::multiply_add(-0.5, xd, 0.5);

View File

@ -17,18 +17,20 @@ namespace LIBC_NAMESPACE {
LLVM_LIBC_FUNCTION(float, atanf, (float x)) {
using FPBits = typename fputil::FPBits<float>;
using Sign = fputil::Sign;
// x == 0.0
if (LIBC_UNLIKELY(x == 0.0f))
return x;
FPBits xbits(x);
bool sign = xbits.get_sign();
xbits.set_sign(false);
Sign sign = xbits.sign();
xbits.set_sign(Sign::POS);
if (LIBC_UNLIKELY(xbits.is_inf_or_nan())) {
if (xbits.is_inf())
return static_cast<float>(opt_barrier(sign ? -M_MATH_PI_2 : M_MATH_PI_2));
return static_cast<float>(
opt_barrier(sign.is_neg() ? -M_MATH_PI_2 : M_MATH_PI_2));
else
return x;
}
@ -45,7 +47,7 @@ LLVM_LIBC_FUNCTION(float, atanf, (float x)) {
// |x| == 1.8670953512191772
if (LIBC_UNLIKELY(xbits.uintval() == 0x3feefcfbU)) {
int rounding_mode = fputil::quick_get_round();
if (sign) {
if (sign.is_neg()) {
if (rounding_mode == FE_DOWNWARD) {
// -1.0790828466415405
return FPBits(0xbf8a1f63U).get_val();

View File

@ -15,8 +15,9 @@ namespace LIBC_NAMESPACE {
LLVM_LIBC_FUNCTION(float, atanhf, (float x)) {
using FPBits = typename fputil::FPBits<float>;
using Sign = fputil::Sign;
FPBits xbits(x);
bool sign = xbits.get_sign();
Sign sign = xbits.sign();
uint32_t x_abs = xbits.abs().uintval();
// |x| >= 1.0

View File

@ -42,8 +42,9 @@ static constexpr fputil::ExceptValues<float, N_EXCEPTS> COSF_EXCEPTS{{
LLVM_LIBC_FUNCTION(float, cosf, (float x)) {
using FPBits = typename fputil::FPBits<float>;
using Sign = fputil::Sign;
FPBits xbits(x);
xbits.set_sign(false);
xbits.set_sign(Sign::POS);
uint32_t x_abs = xbits.uintval();
double xd = static_cast<double>(xbits.get_val());

View File

@ -17,8 +17,9 @@ namespace LIBC_NAMESPACE {
LLVM_LIBC_FUNCTION(float, coshf, (float x)) {
using FPBits = typename fputil::FPBits<float>;
using Sign = fputil::Sign;
FPBits xbits(x);
xbits.set_sign(false);
xbits.set_sign(Sign::POS);
x = xbits.get_val();
uint32_t x_u = xbits.uintval();

View File

@ -140,7 +140,7 @@ LLVM_LIBC_FUNCTION(float, erff, (float x)) {
const float ONE[2] = {1.0f, -1.0f};
const float SMALL[2] = {-0x1.0p-25f, 0x1.0p-25f};
int sign = static_cast<int>(xbits.get_sign());
int sign = xbits.is_neg() ? 1 : 0;
if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) {
return (x_abs > 0x7f80'0000) ? x : ONE[sign];

View File

@ -48,7 +48,7 @@ LIBC_INLINE float exp10f(float x) {
return 0.0f;
}
// x >= log10(2^128) or nan
if (!xbits.get_sign() && (x_u >= 0x421a'209bU)) {
if (xbits.is_pos() && (x_u >= 0x421a'209bU)) {
// x is finite
if (x_u < 0x7f80'0000U) {
int rounding = fputil::quick_get_round();

View File

@ -71,7 +71,7 @@ LIBC_INLINE float exp2f(float x) {
}
// x >= 128
if (!xbits.get_sign()) {
if (xbits.is_pos()) {
// x is finite
if (x_u < 0x7f80'0000U) {
int rounding = fputil::quick_get_round();

View File

@ -56,7 +56,7 @@ LLVM_LIBC_FUNCTION(float, expf, (float x)) {
return 0.0f;
}
// x >= 89 or nan
if (!xbits.get_sign() && (xbits.uintval() >= 0x42b2'0000)) {
if (xbits.is_pos() && (xbits.uintval() >= 0x42b2'0000)) {
// x is finite
if (xbits.uintval() < 0x7f80'0000U) {
int rounding = fputil::quick_get_round();

View File

@ -275,9 +275,10 @@ double set_exceptional(double x) {
LLVM_LIBC_FUNCTION(double, expm1, (double x)) {
using FPBits = typename fputil::FPBits<double>;
using Sign = fputil::Sign;
FPBits xbits(x);
bool x_sign = xbits.get_sign();
bool x_is_neg = xbits.is_neg();
uint64_t x_u = xbits.uintval();
// Upper bound: max normal number = 2^1023 * (2 - 2^-52)
@ -392,11 +393,11 @@ LLVM_LIBC_FUNCTION(double, expm1, (double x)) {
// -2^(-hi)
double one_scaled =
FPBits::create_value(true, FPBits::EXP_BIAS - hi, 0).get_val();
FPBits::create_value(Sign::NEG, FPBits::EXP_BIAS - hi, 0).get_val();
// 2^(mid1 + mid2) - 2^(-hi)
DoubleDouble hi_part = x_sign ? fputil::exact_add(one_scaled, exp_mid.hi)
: fputil::exact_add(exp_mid.hi, one_scaled);
DoubleDouble hi_part = x_is_neg ? fputil::exact_add(one_scaled, exp_mid.hi)
: fputil::exact_add(exp_mid.hi, one_scaled);
hi_part.lo += exp_mid.lo;
@ -437,7 +438,9 @@ LLVM_LIBC_FUNCTION(double, expm1, (double x)) {
double lo = fputil::multiply_add(p, mid_lo, hi_part.lo);
uint64_t err = x_sign ? (static_cast<uint64_t>(-hi) << 52) : 0;
// TODO: The following line leaks encoding abstraction. Use FPBits methods
// instead.
uint64_t err = x_is_neg ? (static_cast<uint64_t>(-hi) << 52) : 0;
double err_d = cpp::bit_cast<double>(ERR_D + err);

View File

@ -51,7 +51,7 @@ LLVM_LIBC_FUNCTION(float, expm1f, (float x)) {
// When |x| > 25*log(2), or nan
if (LIBC_UNLIKELY(x_abs >= 0x418a'a123U)) {
// x < log(2^-25)
if (xbits.get_sign()) {
if (xbits.is_neg()) {
// exp(-Inf) = 0
if (xbits.is_inf())
return -1.0f;

View File

@ -38,18 +38,19 @@ extern const double ATAN_K[5];
// x should be positive, normal finite value
LIBC_INLINE double atan_eval(double x) {
using FPB = fputil::FPBits<double>;
using Sign = fputil::Sign;
// Added some small value to umin and umax mantissa to avoid possible rounding
// errors.
FPB::StorageType umin =
FPB::create_value(false, FPB::EXP_BIAS - ATAN_T_BITS - 1,
FPB::create_value(Sign::POS, FPB::EXP_BIAS - ATAN_T_BITS - 1,
0x100000000000UL)
.uintval();
FPB::StorageType umax =
FPB::create_value(false, FPB::EXP_BIAS + ATAN_T_BITS, 0xF000000000000UL)
FPB::create_value(Sign::POS, FPB::EXP_BIAS + ATAN_T_BITS,
0xF000000000000UL)
.uintval();
FPB bs(x);
bool sign = bs.get_sign();
auto x_abs = bs.abs().uintval();
if (x_abs <= umin) {
@ -64,7 +65,7 @@ LIBC_INLINE double atan_eval(double x) {
double pe = LIBC_NAMESPACE::fputil::polyeval(
one_over_x2, ATAN_K[0], ATAN_K[1], ATAN_K[2], ATAN_K[3]);
return fputil::multiply_add(pe, one_over_x_m,
sign ? (-M_MATH_PI_2) : (M_MATH_PI_2));
bs.is_neg() ? (-M_MATH_PI_2) : (M_MATH_PI_2));
}
double pos_x = FPB(x_abs).get_val();
@ -86,7 +87,7 @@ LIBC_INLINE double atan_eval(double x) {
result = M_MATH_PI_2 - fputil::multiply_add(pe, v, ATAN_T[val - 1]);
else
result = fputil::multiply_add(pe, v, ATAN_T[val - 1]);
return sign ? -result : result;
return bs.is_neg() ? -result : result;
}
// > Q = fpminimax(asin(x)/x, [|0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20|],

View File

@ -747,9 +747,9 @@ LLVM_LIBC_FUNCTION(double, log, (double x)) {
// return -Inf and raise FE_DIVBYZERO.
fputil::set_errno_if_required(ERANGE);
fputil::raise_except_if_required(FE_DIVBYZERO);
return static_cast<double>(FPBits_t::neg_inf());
return static_cast<double>(FPBits_t::inf(fputil::Sign::NEG));
}
if (xbits.get_sign() && !xbits.is_nan()) {
if (xbits.is_neg() && !xbits.is_nan()) {
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_INVALID);
return FPBits_t::build_quiet_nan(0);

View File

@ -748,9 +748,9 @@ LLVM_LIBC_FUNCTION(double, log10, (double x)) {
// return -Inf and raise FE_DIVBYZERO.
fputil::set_errno_if_required(ERANGE);
fputil::raise_except_if_required(FE_DIVBYZERO);
return static_cast<double>(FPBits_t::neg_inf());
return static_cast<double>(FPBits_t::inf(fputil::Sign::NEG));
}
if (xbits.get_sign() && !xbits.is_nan()) {
if (xbits.is_neg() && !xbits.is_nan()) {
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_INVALID);
return FPBits_t::build_quiet_nan(0);

View File

@ -165,9 +165,9 @@ LLVM_LIBC_FUNCTION(float, log10f, (float x)) {
// Return -inf and raise FE_DIVBYZERO
fputil::set_errno_if_required(ERANGE);
fputil::raise_except_if_required(FE_DIVBYZERO);
return static_cast<float>(FPBits::neg_inf());
return static_cast<float>(FPBits::inf(fputil::Sign::NEG));
}
if (xbits.get_sign() && !xbits.is_nan()) {
if (xbits.is_neg() && !xbits.is_nan()) {
// Return NaN and raise FE_INVALID
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_INVALID);

View File

@ -892,9 +892,9 @@ LLVM_LIBC_FUNCTION(double, log1p, (double x)) {
// x = -1.0
fputil::set_errno_if_required(ERANGE);
fputil::raise_except_if_required(FE_DIVBYZERO);
return static_cast<double>(FPBits_t::neg_inf());
return static_cast<double>(FPBits_t::inf(fputil::Sign::NEG));
}
if (xbits.get_sign() && !xbits.is_nan()) {
if (xbits.is_neg() && !xbits.is_nan()) {
// x < -1.0
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_INVALID);

View File

@ -44,7 +44,7 @@ LIBC_INLINE float log(double x) {
uint64_t x_u = xbits.uintval();
if (LIBC_UNLIKELY(x_u > FPBits::MAX_NORMAL)) {
if (xbits.get_sign() && !xbits.is_nan()) {
if (xbits.is_neg() && !xbits.is_nan()) {
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_INVALID);
return fputil::FPBits<float>::build_quiet_nan(0);
@ -106,7 +106,7 @@ LLVM_LIBC_FUNCTION(float, log1pf, (float x)) {
case 0xbf800000U: // x = -1.0
fputil::set_errno_if_required(ERANGE);
fputil::raise_except_if_required(FE_DIVBYZERO);
return static_cast<float>(fputil::FPBits<float>::neg_inf());
return static_cast<float>(fputil::FPBits<float>::inf(fputil::Sign::NEG));
#ifndef LIBC_TARGET_CPU_HAS_FMA
case 0x4cc1c80bU: // x = 0x1.839016p+26f
return fputil::round_result_slightly_down(0x1.26fc04p+4f);

View File

@ -869,9 +869,9 @@ LLVM_LIBC_FUNCTION(double, log2, (double x)) {
// return -Inf and raise FE_DIVBYZERO.
fputil::set_errno_if_required(ERANGE);
fputil::raise_except_if_required(FE_DIVBYZERO);
return static_cast<double>(FPBits_t::neg_inf());
return static_cast<double>(FPBits_t::inf(fputil::Sign::NEG));
}
if (xbits.get_sign() && !xbits.is_nan()) {
if (xbits.is_neg() && !xbits.is_nan()) {
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_INVALID);
return FPBits_t::build_quiet_nan(0);

View File

@ -72,9 +72,9 @@ LLVM_LIBC_FUNCTION(float, log2f, (float x)) {
if (xbits.is_zero()) {
fputil::set_errno_if_required(ERANGE);
fputil::raise_except_if_required(FE_DIVBYZERO);
return static_cast<float>(FPBits::neg_inf());
return static_cast<float>(FPBits::inf(fputil::Sign::NEG));
}
if (xbits.get_sign() && !xbits.is_nan()) {
if (xbits.is_neg() && !xbits.is_nan()) {
fputil::set_errno_if_required(EDOM);
fputil::raise_except(FE_INVALID);
return FPBits::build_quiet_nan(0);

View File

@ -84,7 +84,7 @@ LLVM_LIBC_FUNCTION(float, logf, (float x)) {
// Return -inf and raise FE_DIVBYZERO
fputil::set_errno_if_required(ERANGE);
fputil::raise_except_if_required(FE_DIVBYZERO);
return static_cast<float>(FPBits::neg_inf());
return static_cast<float>(FPBits::inf(fputil::Sign::NEG));
}
// Normalize denormal inputs.
xbits = FPBits(xbits.get_val() * 0x1.0p23f);
@ -117,9 +117,9 @@ LLVM_LIBC_FUNCTION(float, logf, (float x)) {
// Return -inf and raise FE_DIVBYZERO
fputil::set_errno_if_required(ERANGE);
fputil::raise_except_if_required(FE_DIVBYZERO);
return static_cast<float>(FPBits::neg_inf());
return static_cast<float>(FPBits::inf(fputil::Sign::NEG));
}
if (xbits.get_sign() && !xbits.is_nan()) {
if (xbits.is_neg() && !xbits.is_nan()) {
// Return NaN and raise FE_INVALID
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_INVALID);

View File

@ -424,6 +424,7 @@ LIBC_INLINE bool larger_exponent(double a, double b) {
double powf_double_double(int idx_x, double dx, double y6, double lo6_hi,
const DoubleDouble &exp2_hi_mid) {
using DoubleBits = typename fputil::FPBits<double>;
using Sign = fputil::Sign;
// Perform a second range reduction step:
// idx2 = round(2^14 * (dx + 2^-8)) = round ( dx * 2^14 + 2^6)
// dx2 = (1 + dx) * r2 - 1
@ -495,8 +496,8 @@ double powf_double_double(int idx_x, double dx, double y6, double lo6_hi,
// Round to odd.
uint64_t r_bits = cpp::bit_cast<uint64_t>(r.hi);
if (LIBC_UNLIKELY(((r_bits & 0xfff'ffff) == 0) && (r.lo != 0.0))) {
bool hi_sign = DoubleBits(r.hi).get_sign();
bool lo_sign = DoubleBits(r.lo).get_sign();
Sign hi_sign = DoubleBits(r.hi).sign();
Sign lo_sign = DoubleBits(r.lo).sign();
if (hi_sign == lo_sign) {
++r_bits;
} else if ((r_bits & DoubleBits::FRACTION_MASK) > 0) {
@ -512,6 +513,7 @@ double powf_double_double(int idx_x, double dx, double y6, double lo6_hi,
LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) {
using FloatBits = typename fputil::FPBits<float>;
using DoubleBits = typename fputil::FPBits<double>;
using Sign = fputil::Sign;
FloatBits xbits(x), ybits(y);
uint32_t x_u = xbits.uintval();
@ -605,28 +607,28 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) {
return generic::exp10f(y);
}
bool x_sign = x_u >= FloatBits::SIGN_MASK;
const bool x_is_neg = x_u >= FloatBits::SIGN_MASK;
switch (x_abs) {
case 0x0000'0000: { // x = +-0.0f
bool x_sign = (x_u >= FloatBits::SIGN_MASK);
bool out_sign = x_sign && is_odd_integer(FloatBits(y_u).get_val());
const bool out_is_neg =
x_is_neg && is_odd_integer(FloatBits(y_u).get_val());
if (y_u > 0x8000'0000U) {
// pow(0, negative number) = inf
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_DIVBYZERO);
return FloatBits::inf(out_sign);
return FloatBits::inf(out_is_neg ? Sign::NEG : Sign::POS);
}
// pow(0, positive number) = 0
return out_sign ? -0.0f : 0.0f;
return out_is_neg ? -0.0f : 0.0f;
}
case 0x7f80'0000: { // x = +-Inf
bool x_sign = (x_u >= FloatBits::SIGN_MASK);
bool out_sign = x_sign && is_odd_integer(FloatBits(y_u).get_val());
const bool out_is_neg =
x_is_neg && is_odd_integer(FloatBits(y_u).get_val());
if (y_u >= FloatBits::SIGN_MASK) {
return out_sign ? -0.0f : 0.0f;
return out_is_neg ? -0.0f : 0.0f;
}
return FloatBits::inf(out_sign);
return FloatBits::inf(out_is_neg ? Sign::NEG : Sign::POS);
}
}
@ -643,7 +645,7 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) {
}
// x is finite and negative, and y is a finite integer.
if (x_sign) {
if (x_is_neg) {
if (is_integer(y)) {
x = -x;
if (is_odd_integer(y)) {

View File

@ -128,10 +128,10 @@ LLVM_LIBC_FUNCTION(float, sinf, (float x)) {
if (LIBC_UNLIKELY(x_abs == 0x4619'9998U)) { // x = 0x1.33333p13
float r = -0x1.63f4bap-2f;
int rounding = fputil::quick_get_round();
bool sign = xbits.get_sign();
if ((rounding == FE_DOWNWARD && !sign) || (rounding == FE_UPWARD && sign))
if ((rounding == FE_DOWNWARD && xbits.is_pos()) ||
(rounding == FE_UPWARD && xbits.is_neg()))
r = -0x1.63f4bcp-2f;
return xbits.get_sign() ? -r : r;
return xbits.is_neg() ? -r : r;
}
if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) {

View File

@ -53,9 +53,8 @@ LLVM_LIBC_FUNCTION(float, sinhf, (float x)) {
if (xbits.is_inf())
return x;
bool sign = xbits.get_sign();
int rounding = fputil::quick_get_round();
if (sign) {
if (xbits.is_neg()) {
if (LIBC_UNLIKELY(rounding == FE_UPWARD || rounding == FE_TOWARDZERO))
return -FPBits::max_normal();
} else {
@ -66,7 +65,7 @@ LLVM_LIBC_FUNCTION(float, sinhf, (float x)) {
fputil::set_errno_if_required(ERANGE);
fputil::raise_except_if_required(FE_OVERFLOW);
return x + FPBits::inf(sign);
return x + FPBits::inf(xbits.sign());
}
// sinh(x) = (e^x - e^(-x)) / 2.

View File

@ -25,6 +25,8 @@ LLVM_LIBC_FUNCTION(float, tanhf, (float x)) {
FPBits xbits(x);
uint32_t x_abs = xbits.abs().uintval();
const int sign_index = xbits.is_neg() ? 1 : 0;
// When |x| >= 15, or x is inf or nan, or |x| <= 0.078125
if (LIBC_UNLIKELY((x_abs >= 0x4170'0000U) || (x_abs <= 0x3da0'0000U))) {
if (x_abs <= 0x3da0'0000U) {
@ -57,13 +59,10 @@ LLVM_LIBC_FUNCTION(float, tanhf, (float x)) {
constexpr float SIGNS[2][2] = {{1.0f, -0x1.0p-25f}, {-1.0f, 0x1.0p-25f}};
bool sign = xbits.get_sign();
int idx = static_cast<int>(sign);
if (LIBC_UNLIKELY(xbits.is_inf()))
return SIGNS[idx][0];
return SIGNS[sign_index][0];
return SIGNS[idx][0] + SIGNS[idx][1];
return SIGNS[sign_index][0] + SIGNS[sign_index][1];
}
// Range reduction: e^(2x) = 2^(hi + mid) * e^lo
@ -83,7 +82,7 @@ LLVM_LIBC_FUNCTION(float, tanhf, (float x)) {
constexpr double HALF_WAY[2] = {-0.5, 0.5};
mk = static_cast<int>(
fputil::multiply_add(xd, -LOG2_E_EXP2_6, HALF_WAY[xbits.get_sign()]));
fputil::multiply_add(xd, -LOG2_E_EXP2_6, HALF_WAY[sign_index]));
k = static_cast<double>(-mk);
#endif // LIBC_TARGET_CPU_HAS_NEAREST_INT
// -hi = floor(-k * 2^(-MID_BITS))

View File

@ -49,7 +49,7 @@ constexpr char DECIMAL_POINT = '.';
enum class RoundDirection { Up, Down, Even };
LIBC_INLINE RoundDirection get_round_direction(int last_digit, bool truncated,
bool is_negative) {
fputil::Sign sign) {
switch (fputil::quick_get_round()) {
case FE_TONEAREST:
// Round to nearest, if it's exactly halfway then round to even.
@ -59,18 +59,18 @@ LIBC_INLINE RoundDirection get_round_direction(int last_digit, bool truncated,
return !truncated ? RoundDirection::Even : RoundDirection::Up;
}
case FE_DOWNWARD:
if (is_negative && (truncated || last_digit > 0)) {
if (sign.is_neg() && (truncated || last_digit > 0)) {
return RoundDirection::Up;
} else {
return RoundDirection::Down;
}
case FE_UPWARD:
if (!is_negative && (truncated || last_digit > 0)) {
if (sign.is_pos() && (truncated || last_digit > 0)) {
return RoundDirection::Up;
} else {
return RoundDirection::Down;
}
return is_negative ? RoundDirection::Down : RoundDirection::Up;
return sign.is_neg() ? RoundDirection::Down : RoundDirection::Up;
case FE_TOWARDZERO:
return RoundDirection::Down;
default:
@ -474,12 +474,11 @@ LIBC_INLINE int convert_float_decimal_typed(Writer *writer,
fputil::FPBits<T> float_bits) {
// signed because later we use -FRACTION_LEN
constexpr int32_t FRACTION_LEN = fputil::FPBits<T>::FRACTION_LEN;
bool is_negative = float_bits.get_sign();
int exponent = float_bits.get_explicit_exponent();
char sign_char = 0;
if (is_negative)
if (float_bits.is_neg())
sign_char = '-';
else if ((to_conv.flags & FormatFlags::FORCE_SIGN) == FormatFlags::FORCE_SIGN)
sign_char = '+'; // FORCE_SIGN has precedence over SPACE_PREFIX
@ -567,7 +566,7 @@ LIBC_INLINE int convert_float_decimal_typed(Writer *writer,
const bool truncated = !zero_after_digits(
exponent - FRACTION_LEN, precision,
float_bits.get_explicit_mantissa(), FRACTION_LEN);
round = get_round_direction(last_digit, truncated, is_negative);
round = get_round_direction(last_digit, truncated, float_bits.sign());
RET_IF_RESULT_NEGATIVE(
float_writer.write_last_block(digits, maximum, round));
@ -587,7 +586,6 @@ LIBC_INLINE int convert_float_dec_exp_typed(Writer *writer,
fputil::FPBits<T> float_bits) {
// signed because later we use -FRACTION_LEN
constexpr int32_t FRACTION_LEN = fputil::FPBits<T>::FRACTION_LEN;
bool is_negative = float_bits.get_sign();
int exponent = float_bits.get_explicit_exponent();
StorageType mantissa = float_bits.get_explicit_mantissa();
@ -595,7 +593,7 @@ LIBC_INLINE int convert_float_dec_exp_typed(Writer *writer,
char sign_char = 0;
if (is_negative)
if (float_bits.is_neg())
sign_char = '-';
else if ((to_conv.flags & FormatFlags::FORCE_SIGN) == FormatFlags::FORCE_SIGN)
sign_char = '+'; // FORCE_SIGN has precedence over SPACE_PREFIX
@ -735,7 +733,7 @@ LIBC_INLINE int convert_float_dec_exp_typed(Writer *writer,
float_bits.get_explicit_mantissa(), FRACTION_LEN);
}
}
round = get_round_direction(last_digit, truncated, is_negative);
round = get_round_direction(last_digit, truncated, float_bits.sign());
RET_IF_RESULT_NEGATIVE(float_writer.write_last_block(
digits, maximum, round, final_exponent, a + 'E' - 'A'));
@ -750,7 +748,6 @@ LIBC_INLINE int convert_float_dec_auto_typed(Writer *writer,
fputil::FPBits<T> float_bits) {
// signed because later we use -FRACTION_LEN
constexpr int32_t FRACTION_LEN = fputil::FPBits<T>::FRACTION_LEN;
bool is_negative = float_bits.get_sign();
int exponent = float_bits.get_explicit_exponent();
StorageType mantissa = float_bits.get_explicit_mantissa();
@ -983,7 +980,7 @@ LIBC_INLINE int convert_float_dec_auto_typed(Writer *writer,
}
}
round = get_round_direction(last_digit, truncated, is_negative);
round = get_round_direction(last_digit, truncated, float_bits.sign());
bool round_up;
if (round == RoundDirection::Up) {

View File

@ -41,7 +41,7 @@ LIBC_INLINE int convert_float_hex_exp(Writer *writer,
fraction_bits = LDBits::FRACTION_LEN;
LDBits::StorageType float_raw = to_conv.conv_val_raw;
LDBits float_bits(float_raw);
is_negative = float_bits.get_sign();
is_negative = float_bits.is_neg();
exponent = float_bits.get_explicit_exponent();
mantissa = float_bits.get_explicit_mantissa();
is_inf_or_nan = float_bits.is_inf_or_nan();
@ -51,7 +51,7 @@ LIBC_INLINE int convert_float_hex_exp(Writer *writer,
LBits::StorageType float_raw =
static_cast<LBits::StorageType>(to_conv.conv_val_raw);
LBits float_bits(float_raw);
is_negative = float_bits.get_sign();
is_negative = float_bits.is_neg();
exponent = float_bits.get_explicit_exponent();
mantissa = float_bits.get_explicit_mantissa();
is_inf_or_nan = float_bits.is_inf_or_nan();

View File

@ -32,13 +32,13 @@ LIBC_INLINE int convert_inf_nan(Writer *writer, const FormatSection &to_conv) {
if (to_conv.length_modifier == LengthModifier::L) {
fputil::FPBits<long double>::StorageType float_raw = to_conv.conv_val_raw;
fputil::FPBits<long double> float_bits(float_raw);
is_negative = float_bits.get_sign();
is_negative = float_bits.is_neg();
mantissa = float_bits.get_mantissa();
} else {
fputil::FPBits<double>::StorageType float_raw =
static_cast<fputil::FPBits<double>::StorageType>(to_conv.conv_val_raw);
fputil::FPBits<double> float_bits(float_raw);
is_negative = float_bits.get_sign();
is_negative = float_bits.is_neg();
mantissa = float_bits.get_mantissa();
}

View File

@ -63,14 +63,15 @@ template <TestCond C, typename T> FPMatcher<T, C> getMatcher(T expectedValue) {
template <typename T> struct FPTest : public Test {
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
using Sign = LIBC_NAMESPACE::fputil::Sign;
static constexpr StorageType STORAGE_MAX =
LIBC_NAMESPACE::cpp::numeric_limits<StorageType>::max();
static constexpr T zero = FPBits::zero();
static constexpr T neg_zero = FPBits::neg_zero();
static constexpr T zero = FPBits::zero(Sign::POS);
static constexpr T neg_zero = FPBits::zero(Sign::NEG);
static constexpr T aNaN = FPBits::build_quiet_nan(1);
static constexpr T sNaN = FPBits::build_nan(1);
static constexpr T inf = FPBits::inf();
static constexpr T neg_inf = FPBits::neg_inf();
static constexpr T inf = FPBits::inf(Sign::POS);
static constexpr T neg_inf = FPBits::inf(Sign::NEG);
static constexpr T min_normal = FPBits::min_normal();
static constexpr T max_normal = FPBits::max_normal();
static constexpr T min_denormal = FPBits::min_denormal();
@ -91,14 +92,15 @@ template <typename T> struct FPTest : public Test {
#define DECLARE_SPECIAL_CONSTANTS(T) \
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>; \
using StorageType = typename FPBits::StorageType; \
using Sign = LIBC_NAMESPACE::fputil::Sign; \
static constexpr StorageType STORAGE_MAX = \
LIBC_NAMESPACE::cpp::numeric_limits<StorageType>::max(); \
const T zero = FPBits::zero(); \
const T neg_zero = FPBits::neg_zero(); \
const T zero = FPBits::zero(Sign::POS); \
const T neg_zero = FPBits::zero(Sign::NEG); \
const T aNaN = FPBits::build_quiet_nan(1); \
const T sNaN = FPBits::build_nan(1); \
const T inf = FPBits::inf(); \
const T neg_inf = FPBits::neg_inf(); \
const T inf = FPBits::inf(Sign::POS); \
const T neg_inf = FPBits::inf(Sign::NEG); \
const T min_normal = FPBits::min_normal(); \
const T max_normal = FPBits::max_normal(); \
const T min_denormal = FPBits::min_denormal(); \

View File

@ -11,6 +11,7 @@
#include "test/UnitTest/Test.h"
using LIBC_NAMESPACE::fputil::FPBits;
using LIBC_NAMESPACE::fputil::Sign;
TEST(LlvmLibcFPBitsTest, FPType_IEEE754_Binary16) {
using LIBC_NAMESPACE::fputil::FPType;
@ -228,15 +229,17 @@ TEST(LlvmLibcFPBitsTest, FPType_IEEE754_Binary128) {
TEST(LlvmLibcFPBitsTest, FloatType) {
using FloatBits = FPBits<float>;
EXPECT_STREQ(LIBC_NAMESPACE::str(FloatBits(FloatBits::inf())).c_str(),
"(+Infinity)");
EXPECT_STREQ(LIBC_NAMESPACE::str(FloatBits(FloatBits::neg_inf())).c_str(),
"(-Infinity)");
EXPECT_STREQ(
LIBC_NAMESPACE::str(FloatBits(FloatBits::inf(Sign::POS))).c_str(),
"(+Infinity)");
EXPECT_STREQ(
LIBC_NAMESPACE::str(FloatBits(FloatBits::inf(Sign::NEG))).c_str(),
"(-Infinity)");
EXPECT_STREQ(LIBC_NAMESPACE::str(FloatBits(FloatBits::build_nan(1))).c_str(),
"(NaN)");
FloatBits zero(0.0f);
EXPECT_EQ(zero.get_sign(), false);
EXPECT_TRUE(zero.is_pos());
EXPECT_EQ(zero.get_biased_exponent(), static_cast<uint16_t>(0));
EXPECT_EQ(zero.get_mantissa(), static_cast<uint32_t>(0));
EXPECT_EQ(zero.uintval(), static_cast<uint32_t>(0x00000000));
@ -244,7 +247,7 @@ TEST(LlvmLibcFPBitsTest, FloatType) {
"0x00000000 = (S: 0, E: 0x0000, M: 0x00000000)");
FloatBits negzero(-0.0f);
EXPECT_EQ(negzero.get_sign(), true);
EXPECT_TRUE(negzero.is_neg());
EXPECT_EQ(negzero.get_biased_exponent(), static_cast<uint16_t>(0));
EXPECT_EQ(negzero.get_mantissa(), static_cast<uint32_t>(0));
EXPECT_EQ(negzero.uintval(), static_cast<uint32_t>(0x80000000));
@ -252,7 +255,7 @@ TEST(LlvmLibcFPBitsTest, FloatType) {
"0x80000000 = (S: 1, E: 0x0000, M: 0x00000000)");
FloatBits one(1.0f);
EXPECT_EQ(one.get_sign(), false);
EXPECT_TRUE(one.is_pos());
EXPECT_EQ(one.get_biased_exponent(), static_cast<uint16_t>(0x7F));
EXPECT_EQ(one.get_mantissa(), static_cast<uint32_t>(0));
EXPECT_EQ(one.uintval(), static_cast<uint32_t>(0x3F800000));
@ -260,7 +263,7 @@ TEST(LlvmLibcFPBitsTest, FloatType) {
"0x3F800000 = (S: 0, E: 0x007F, M: 0x00000000)");
FloatBits negone(-1.0f);
EXPECT_EQ(negone.get_sign(), true);
EXPECT_TRUE(negone.is_neg());
EXPECT_EQ(negone.get_biased_exponent(), static_cast<uint16_t>(0x7F));
EXPECT_EQ(negone.get_mantissa(), static_cast<uint32_t>(0));
EXPECT_EQ(negone.uintval(), static_cast<uint32_t>(0xBF800000));
@ -268,7 +271,7 @@ TEST(LlvmLibcFPBitsTest, FloatType) {
"0xBF800000 = (S: 1, E: 0x007F, M: 0x00000000)");
FloatBits num(1.125f);
EXPECT_EQ(num.get_sign(), false);
EXPECT_TRUE(num.is_pos());
EXPECT_EQ(num.get_biased_exponent(), static_cast<uint16_t>(0x7F));
EXPECT_EQ(num.get_mantissa(), static_cast<uint32_t>(0x00100000));
EXPECT_EQ(num.uintval(), static_cast<uint32_t>(0x3F900000));
@ -276,7 +279,7 @@ TEST(LlvmLibcFPBitsTest, FloatType) {
"0x3F900000 = (S: 0, E: 0x007F, M: 0x00100000)");
FloatBits negnum(-1.125f);
EXPECT_EQ(negnum.get_sign(), true);
EXPECT_TRUE(negnum.is_neg());
EXPECT_EQ(negnum.get_biased_exponent(), static_cast<uint16_t>(0x7F));
EXPECT_EQ(negnum.get_mantissa(), static_cast<uint32_t>(0x00100000));
EXPECT_EQ(negnum.uintval(), static_cast<uint32_t>(0xBF900000));
@ -290,16 +293,18 @@ TEST(LlvmLibcFPBitsTest, FloatType) {
TEST(LlvmLibcFPBitsTest, DoubleType) {
using DoubleBits = FPBits<double>;
EXPECT_STREQ(LIBC_NAMESPACE::str(DoubleBits(DoubleBits::inf())).c_str(),
"(+Infinity)");
EXPECT_STREQ(LIBC_NAMESPACE::str(DoubleBits(DoubleBits::neg_inf())).c_str(),
"(-Infinity)");
EXPECT_STREQ(
LIBC_NAMESPACE::str(DoubleBits(DoubleBits::inf(Sign::POS))).c_str(),
"(+Infinity)");
EXPECT_STREQ(
LIBC_NAMESPACE::str(DoubleBits(DoubleBits::inf(Sign::NEG))).c_str(),
"(-Infinity)");
EXPECT_STREQ(
LIBC_NAMESPACE::str(DoubleBits(DoubleBits::build_nan(1))).c_str(),
"(NaN)");
DoubleBits zero(0.0);
EXPECT_EQ(zero.get_sign(), false);
EXPECT_TRUE(zero.is_pos());
EXPECT_EQ(zero.get_biased_exponent(), static_cast<uint16_t>(0x0000));
EXPECT_EQ(zero.get_mantissa(), static_cast<uint64_t>(0x0000000000000000));
EXPECT_EQ(zero.uintval(), static_cast<uint64_t>(0x0000000000000000));
@ -307,7 +312,7 @@ TEST(LlvmLibcFPBitsTest, DoubleType) {
"0x0000000000000000 = (S: 0, E: 0x0000, M: 0x0000000000000000)");
DoubleBits negzero(-0.0);
EXPECT_EQ(negzero.get_sign(), true);
EXPECT_TRUE(negzero.is_neg());
EXPECT_EQ(negzero.get_biased_exponent(), static_cast<uint16_t>(0x0000));
EXPECT_EQ(negzero.get_mantissa(), static_cast<uint64_t>(0x0000000000000000));
EXPECT_EQ(negzero.uintval(), static_cast<uint64_t>(0x8000000000000000));
@ -315,7 +320,7 @@ TEST(LlvmLibcFPBitsTest, DoubleType) {
"0x8000000000000000 = (S: 1, E: 0x0000, M: 0x0000000000000000)");
DoubleBits one(1.0);
EXPECT_EQ(one.get_sign(), false);
EXPECT_TRUE(one.is_pos());
EXPECT_EQ(one.get_biased_exponent(), static_cast<uint16_t>(0x03FF));
EXPECT_EQ(one.get_mantissa(), static_cast<uint64_t>(0x0000000000000000));
EXPECT_EQ(one.uintval(), static_cast<uint64_t>(0x3FF0000000000000));
@ -323,7 +328,7 @@ TEST(LlvmLibcFPBitsTest, DoubleType) {
"0x3FF0000000000000 = (S: 0, E: 0x03FF, M: 0x0000000000000000)");
DoubleBits negone(-1.0);
EXPECT_EQ(negone.get_sign(), true);
EXPECT_TRUE(negone.is_neg());
EXPECT_EQ(negone.get_biased_exponent(), static_cast<uint16_t>(0x03FF));
EXPECT_EQ(negone.get_mantissa(), static_cast<uint64_t>(0x0000000000000000));
EXPECT_EQ(negone.uintval(), static_cast<uint64_t>(0xBFF0000000000000));
@ -331,7 +336,7 @@ TEST(LlvmLibcFPBitsTest, DoubleType) {
"0xBFF0000000000000 = (S: 1, E: 0x03FF, M: 0x0000000000000000)");
DoubleBits num(1.125);
EXPECT_EQ(num.get_sign(), false);
EXPECT_TRUE(num.is_pos());
EXPECT_EQ(num.get_biased_exponent(), static_cast<uint16_t>(0x03FF));
EXPECT_EQ(num.get_mantissa(), static_cast<uint64_t>(0x0002000000000000));
EXPECT_EQ(num.uintval(), static_cast<uint64_t>(0x3FF2000000000000));
@ -339,7 +344,7 @@ TEST(LlvmLibcFPBitsTest, DoubleType) {
"0x3FF2000000000000 = (S: 0, E: 0x03FF, M: 0x0002000000000000)");
DoubleBits negnum(-1.125);
EXPECT_EQ(negnum.get_sign(), true);
EXPECT_TRUE(negnum.is_neg());
EXPECT_EQ(negnum.get_biased_exponent(), static_cast<uint16_t>(0x03FF));
EXPECT_EQ(negnum.get_mantissa(), static_cast<uint64_t>(0x0002000000000000));
EXPECT_EQ(negnum.uintval(), static_cast<uint64_t>(0xBFF2000000000000));
@ -358,17 +363,19 @@ TEST(LlvmLibcFPBitsTest, X86LongDoubleType) {
return; // The tests for the "double" type cover for this case.
EXPECT_STREQ(
LIBC_NAMESPACE::str(LongDoubleBits(LongDoubleBits::inf())).c_str(),
LIBC_NAMESPACE::str(LongDoubleBits(LongDoubleBits::inf(Sign::POS)))
.c_str(),
"(+Infinity)");
EXPECT_STREQ(
LIBC_NAMESPACE::str(LongDoubleBits(LongDoubleBits::neg_inf())).c_str(),
LIBC_NAMESPACE::str(LongDoubleBits(LongDoubleBits::inf(Sign::NEG)))
.c_str(),
"(-Infinity)");
EXPECT_STREQ(
LIBC_NAMESPACE::str(LongDoubleBits(LongDoubleBits::build_nan(1))).c_str(),
"(NaN)");
LongDoubleBits zero(0.0l);
EXPECT_EQ(zero.get_sign(), false);
EXPECT_TRUE(zero.is_pos());
EXPECT_EQ(zero.get_biased_exponent(), static_cast<uint16_t>(0x0000));
EXPECT_EQ(zero.get_mantissa(), static_cast<UInt128>(0x0000000000000000)
<< 64);
@ -379,7 +386,7 @@ TEST(LlvmLibcFPBitsTest, X86LongDoubleType) {
"(S: 0, E: 0x0000, I: 0, M: 0x00000000000000000000000000000000)");
LongDoubleBits negzero(-0.0l);
EXPECT_EQ(negzero.get_sign(), true);
EXPECT_TRUE(negzero.is_neg());
EXPECT_EQ(negzero.get_biased_exponent(), static_cast<uint16_t>(0x0000));
EXPECT_EQ(negzero.get_mantissa(), static_cast<UInt128>(0x0000000000000000)
<< 64);
@ -390,7 +397,7 @@ TEST(LlvmLibcFPBitsTest, X86LongDoubleType) {
"(S: 1, E: 0x0000, I: 0, M: 0x00000000000000000000000000000000)");
LongDoubleBits one(1.0l);
EXPECT_EQ(one.get_sign(), false);
EXPECT_TRUE(one.is_pos());
EXPECT_EQ(one.get_biased_exponent(), static_cast<uint16_t>(0x3FFF));
EXPECT_EQ(one.get_mantissa(), static_cast<UInt128>(0x0000000000000000) << 64);
EXPECT_EQ(one.uintval(), static_cast<UInt128>(0x3FFF8) << 60);
@ -400,7 +407,7 @@ TEST(LlvmLibcFPBitsTest, X86LongDoubleType) {
"(S: 0, E: 0x3FFF, I: 1, M: 0x00000000000000000000000000000000)");
LongDoubleBits negone(-1.0l);
EXPECT_EQ(negone.get_sign(), true);
EXPECT_TRUE(negone.is_neg());
EXPECT_EQ(negone.get_biased_exponent(), static_cast<uint16_t>(0x3FFF));
EXPECT_EQ(negone.get_mantissa(), static_cast<UInt128>(0x0000000000000000)
<< 64);
@ -411,7 +418,7 @@ TEST(LlvmLibcFPBitsTest, X86LongDoubleType) {
"(S: 1, E: 0x3FFF, I: 1, M: 0x00000000000000000000000000000000)");
LongDoubleBits num(1.125l);
EXPECT_EQ(num.get_sign(), false);
EXPECT_TRUE(num.is_pos());
EXPECT_EQ(num.get_biased_exponent(), static_cast<uint16_t>(0x3FFF));
EXPECT_EQ(num.get_mantissa(), static_cast<UInt128>(0x1) << 60);
EXPECT_EQ(num.uintval(), static_cast<UInt128>(0x3FFF9) << 60);
@ -421,7 +428,7 @@ TEST(LlvmLibcFPBitsTest, X86LongDoubleType) {
"(S: 0, E: 0x3FFF, I: 1, M: 0x00000000000000001000000000000000)");
LongDoubleBits negnum(-1.125l);
EXPECT_EQ(negnum.get_sign(), true);
EXPECT_TRUE(negnum.is_neg());
EXPECT_EQ(negnum.get_biased_exponent(), static_cast<uint16_t>(0x3FFF));
EXPECT_EQ(negnum.get_mantissa(), static_cast<UInt128>(0x1) << 60);
EXPECT_EQ(negnum.uintval(), static_cast<UInt128>(0xBFFF9) << 60);
@ -441,17 +448,19 @@ TEST(LlvmLibcFPBitsTest, LongDoubleType) {
using LongDoubleBits = FPBits<long double>;
EXPECT_STREQ(
LIBC_NAMESPACE::str(LongDoubleBits(LongDoubleBits::inf())).c_str(),
LIBC_NAMESPACE::str(LongDoubleBits(LongDoubleBits::inf(Sign::POS)))
.c_str(),
"(+Infinity)");
EXPECT_STREQ(
LIBC_NAMESPACE::str(LongDoubleBits(LongDoubleBits::neg_inf())).c_str(),
LIBC_NAMESPACE::str(LongDoubleBits(LongDoubleBits::inf(Sign::NEG)))
.c_str(),
"(-Infinity)");
EXPECT_STREQ(
LIBC_NAMESPACE::str(LongDoubleBits(LongDoubleBits::build_nan(1))).c_str(),
"(NaN)");
LongDoubleBits zero(0.0l);
EXPECT_EQ(zero.get_sign(), false);
EXPECT_TRUE(zero.is_pos());
EXPECT_EQ(zero.get_biased_exponent(), static_cast<uint16_t>(0x0000));
EXPECT_EQ(zero.get_mantissa(), static_cast<UInt128>(0x0000000000000000)
<< 64);
@ -461,7 +470,7 @@ TEST(LlvmLibcFPBitsTest, LongDoubleType) {
"(S: 0, E: 0x0000, M: 0x00000000000000000000000000000000)");
LongDoubleBits negzero(-0.0l);
EXPECT_EQ(negzero.get_sign(), true);
EXPECT_TRUE(negzero.is_neg());
EXPECT_EQ(negzero.get_biased_exponent(), static_cast<uint16_t>(0x0000));
EXPECT_EQ(negzero.get_mantissa(), static_cast<UInt128>(0x0000000000000000)
<< 64);
@ -471,7 +480,7 @@ TEST(LlvmLibcFPBitsTest, LongDoubleType) {
"(S: 1, E: 0x0000, M: 0x00000000000000000000000000000000)");
LongDoubleBits one(1.0l);
EXPECT_EQ(one.get_sign(), false);
EXPECT_TRUE(one.is_pos());
EXPECT_EQ(one.get_biased_exponent(), static_cast<uint16_t>(0x3FFF));
EXPECT_EQ(one.get_mantissa(), static_cast<UInt128>(0x0000000000000000) << 64);
EXPECT_EQ(one.uintval(), static_cast<UInt128>(0x3FFF) << 112);
@ -480,7 +489,7 @@ TEST(LlvmLibcFPBitsTest, LongDoubleType) {
"(S: 0, E: 0x3FFF, M: 0x00000000000000000000000000000000)");
LongDoubleBits negone(-1.0l);
EXPECT_EQ(negone.get_sign(), true);
EXPECT_TRUE(negone.is_neg());
EXPECT_EQ(negone.get_biased_exponent(), static_cast<uint16_t>(0x3FFF));
EXPECT_EQ(negone.get_mantissa(), static_cast<UInt128>(0x0000000000000000)
<< 64);
@ -490,7 +499,7 @@ TEST(LlvmLibcFPBitsTest, LongDoubleType) {
"(S: 1, E: 0x3FFF, M: 0x00000000000000000000000000000000)");
LongDoubleBits num(1.125l);
EXPECT_EQ(num.get_sign(), false);
EXPECT_TRUE(num.is_pos());
EXPECT_EQ(num.get_biased_exponent(), static_cast<uint16_t>(0x3FFF));
EXPECT_EQ(num.get_mantissa(), static_cast<UInt128>(0x2) << 108);
EXPECT_EQ(num.uintval(), static_cast<UInt128>(0x3FFF2) << 108);
@ -499,7 +508,7 @@ TEST(LlvmLibcFPBitsTest, LongDoubleType) {
"(S: 0, E: 0x3FFF, M: 0x00002000000000000000000000000000)");
LongDoubleBits negnum(-1.125l);
EXPECT_EQ(negnum.get_sign(), true);
EXPECT_TRUE(negnum.is_neg());
EXPECT_EQ(negnum.get_biased_exponent(), static_cast<uint16_t>(0x3FFF));
EXPECT_EQ(negnum.get_mantissa(), static_cast<UInt128>(0x2) << 108);
EXPECT_EQ(negnum.uintval(), static_cast<UInt128>(0xBFFF2) << 108);
@ -517,17 +526,18 @@ TEST(LlvmLibcFPBitsTest, LongDoubleType) {
TEST(LlvmLibcFPBitsTest, Float128Type) {
using Float128Bits = FPBits<float128>;
EXPECT_STREQ(LIBC_NAMESPACE::str(Float128Bits(Float128Bits::inf())).c_str(),
"(+Infinity)");
EXPECT_STREQ(
LIBC_NAMESPACE::str(Float128Bits(Float128Bits::neg_inf())).c_str(),
LIBC_NAMESPACE::str(Float128Bits(Float128Bits::inf(Sign::POS))).c_str(),
"(+Infinity)");
EXPECT_STREQ(
LIBC_NAMESPACE::str(Float128Bits(Float128Bits::inf(Sign::NEG))).c_str(),
"(-Infinity)");
EXPECT_STREQ(
LIBC_NAMESPACE::str(Float128Bits(Float128Bits::build_nan(1))).c_str(),
"(NaN)");
Float128Bits zero(Float128Bits::zero());
EXPECT_EQ(zero.get_sign(), false);
EXPECT_TRUE(zero.is_pos());
EXPECT_EQ(zero.get_biased_exponent(), static_cast<uint16_t>(0x0000));
EXPECT_EQ(zero.get_mantissa(), static_cast<UInt128>(0x0000000000000000)
<< 64);
@ -536,8 +546,8 @@ TEST(LlvmLibcFPBitsTest, Float128Type) {
"0x00000000000000000000000000000000 = "
"(S: 0, E: 0x0000, M: 0x00000000000000000000000000000000)");
Float128Bits negzero(Float128Bits::neg_zero());
EXPECT_EQ(negzero.get_sign(), true);
Float128Bits negzero(Float128Bits::zero(Sign::NEG));
EXPECT_TRUE(negzero.is_neg());
EXPECT_EQ(negzero.get_biased_exponent(), static_cast<uint16_t>(0x0000));
EXPECT_EQ(negzero.get_mantissa(), static_cast<UInt128>(0x0000000000000000)
<< 64);
@ -547,7 +557,7 @@ TEST(LlvmLibcFPBitsTest, Float128Type) {
"(S: 1, E: 0x0000, M: 0x00000000000000000000000000000000)");
Float128Bits one(float128(1.0));
EXPECT_EQ(one.get_sign(), false);
EXPECT_TRUE(one.is_pos());
EXPECT_EQ(one.get_biased_exponent(), static_cast<uint16_t>(0x3FFF));
EXPECT_EQ(one.get_mantissa(), static_cast<UInt128>(0x0000000000000000) << 64);
EXPECT_EQ(one.uintval(), static_cast<UInt128>(0x3FFF) << 112);
@ -556,7 +566,7 @@ TEST(LlvmLibcFPBitsTest, Float128Type) {
"(S: 0, E: 0x3FFF, M: 0x00000000000000000000000000000000)");
Float128Bits negone(float128(-1.0));
EXPECT_EQ(negone.get_sign(), true);
EXPECT_TRUE(negone.is_neg());
EXPECT_EQ(negone.get_biased_exponent(), static_cast<uint16_t>(0x3FFF));
EXPECT_EQ(negone.get_mantissa(), static_cast<UInt128>(0x0000000000000000)
<< 64);
@ -566,7 +576,7 @@ TEST(LlvmLibcFPBitsTest, Float128Type) {
"(S: 1, E: 0x3FFF, M: 0x00000000000000000000000000000000)");
Float128Bits num(float128(1.125));
EXPECT_EQ(num.get_sign(), false);
EXPECT_TRUE(num.is_pos());
EXPECT_EQ(num.get_biased_exponent(), static_cast<uint16_t>(0x3FFF));
EXPECT_EQ(num.get_mantissa(), static_cast<UInt128>(0x2) << 108);
EXPECT_EQ(num.uintval(), static_cast<UInt128>(0x3FFF2) << 108);
@ -575,7 +585,7 @@ TEST(LlvmLibcFPBitsTest, Float128Type) {
"(S: 0, E: 0x3FFF, M: 0x00002000000000000000000000000000)");
Float128Bits negnum(float128(-1.125));
EXPECT_EQ(negnum.get_sign(), true);
EXPECT_TRUE(negnum.is_neg());
EXPECT_EQ(negnum.get_biased_exponent(), static_cast<uint16_t>(0x3FFF));
EXPECT_EQ(negnum.get_mantissa(), static_cast<UInt128>(0x2) << 108);
EXPECT_EQ(negnum.uintval(), static_cast<UInt128>(0xBFFF2) << 108);

View File

@ -18,6 +18,13 @@ public:
using FuncPtr = T (*)(T, T);
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
using Sign = LIBC_NAMESPACE::fputil::Sign;
const T inf = T(FPBits::inf(Sign::POS));
const T neg_inf = T(FPBits::inf(Sign::NEG));
const T zero = T(FPBits::zero(Sign::POS));
const T neg_zero = T(FPBits::zero(Sign::NEG));
const T nan = T(FPBits::build_quiet_nan(1));
void test_na_n_arg(FuncPtr func) {
EXPECT_FP_EQ(nan, func(nan, inf));
@ -72,13 +79,4 @@ public:
}
}
}
private:
// constexpr does not work on FPBits yet, so we cannot have these constants as
// static.
const T nan = T(FPBits::build_quiet_nan(1));
const T inf = T(FPBits::inf());
const T neg_inf = T(FPBits::neg_inf());
const T zero = T(FPBits::zero());
const T neg_zero = T(FPBits::neg_zero());
};

View File

@ -23,11 +23,13 @@ private:
using Func = T (*)(T, T, T);
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
using Sign = LIBC_NAMESPACE::fputil::Sign;
const T inf = T(FPBits::inf(Sign::POS));
const T neg_inf = T(FPBits::inf(Sign::NEG));
const T zero = T(FPBits::zero(Sign::POS));
const T neg_zero = T(FPBits::zero(Sign::NEG));
const T nan = T(FPBits::build_quiet_nan(1));
const T inf = T(FPBits::inf());
const T neg_inf = T(FPBits::neg_inf());
const T zero = T(FPBits::zero());
const T neg_zero = T(FPBits::neg_zero());
StorageType get_random_bit_pattern() {
StorageType bits{0};

View File

@ -23,12 +23,13 @@ class HypotTestTemplate : public LIBC_NAMESPACE::testing::Test {
private:
using Func = T (*)(T, T);
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
using Sign = LIBC_NAMESPACE::fputil::Sign;
using StorageType = typename FPBits::StorageType;
const T nan = FPBits::build_quiet_nan(1);
const T inf = FPBits::inf();
const T neg_inf = FPBits::neg_inf();
const T neg_inf = FPBits::inf(Sign::NEG);
const T zero = FPBits::zero();
const T neg_zero = FPBits::neg_zero();
const T neg_zero = FPBits::zero(Sign::NEG);
const T max_normal = FPBits::max_normal();
const T min_normal = FPBits::min_normal();
const T max_subnormal = FPBits::max_denormal();

View File

@ -25,11 +25,12 @@ public:
template <typename T>
void test_special_numbers(typename ILogbFunc<T>::Func func) {
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
using Sign = LIBC_NAMESPACE::fputil::Sign;
EXPECT_EQ(FP_ILOGB0, func(T(FPBits::zero())));
EXPECT_EQ(FP_ILOGB0, func(T(FPBits::neg_zero())));
EXPECT_EQ(FP_ILOGB0, func(T(FPBits::zero(Sign::NEG))));
EXPECT_EQ(FP_ILOGBNAN, func(T(FPBits::build_quiet_nan(1))));
EXPECT_EQ(INT_MAX, func(T(FPBits::inf())));
EXPECT_EQ(INT_MAX, func(T(FPBits::neg_inf())));
EXPECT_EQ(INT_MAX, func(T(FPBits::inf(Sign::NEG))));
}
template <typename T>

View File

@ -23,15 +23,17 @@ class LdExpTestTemplate : public LIBC_NAMESPACE::testing::Test {
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
using NormalFloat = LIBC_NAMESPACE::fputil::NormalFloat<T>;
using StorageType = typename FPBits::StorageType;
using Sign = LIBC_NAMESPACE::fputil::Sign;
const T inf = T(FPBits::inf(Sign::POS));
const T neg_inf = T(FPBits::inf(Sign::NEG));
const T zero = T(FPBits::zero(Sign::POS));
const T neg_zero = T(FPBits::zero(Sign::NEG));
const T nan = T(FPBits::build_quiet_nan(1));
// A normalized mantissa to be used with tests.
static constexpr StorageType MANTISSA = NormalFloat::ONE + 0x1234;
const T zero = T(FPBits::zero());
const T neg_zero = T(FPBits::neg_zero());
const T inf = T(FPBits::inf());
const T neg_inf = T(FPBits::neg_inf());
const T nan = T(FPBits::build_quiet_nan(1));
public:
typedef T (*LdExpFunc)(T, int);

View File

@ -21,12 +21,14 @@ template <typename T>
class NextAfterTestTemplate : public LIBC_NAMESPACE::testing::Test {
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
using Sign = LIBC_NAMESPACE::fputil::Sign;
const T zero = T(FPBits::zero());
const T neg_zero = T(FPBits::neg_zero());
const T inf = T(FPBits::inf());
const T neg_inf = T(FPBits::neg_inf());
const T inf = T(FPBits::inf(Sign::POS));
const T neg_inf = T(FPBits::inf(Sign::NEG));
const T zero = T(FPBits::zero(Sign::POS));
const T neg_zero = T(FPBits::zero(Sign::NEG));
const T nan = T(FPBits::build_quiet_nan(1));
const StorageType min_subnormal = FPBits::MIN_SUBNORMAL;
const StorageType max_subnormal = FPBits::MAX_SUBNORMAL;
const StorageType min_normal = FPBits::MIN_NORMAL;

View File

@ -32,11 +32,12 @@ public:
private:
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
using Sign = LIBC_NAMESPACE::fputil::Sign;
const T zero = T(FPBits::zero());
const T neg_zero = T(FPBits::neg_zero());
const T inf = T(FPBits::inf());
const T neg_inf = T(FPBits::neg_inf());
const T inf = T(FPBits::inf(Sign::POS));
const T neg_inf = T(FPBits::inf(Sign::NEG));
const T zero = T(FPBits::zero(Sign::POS));
const T neg_zero = T(FPBits::zero(Sign::NEG));
const T nan = T(FPBits::build_quiet_nan(1));
static inline mpfr::RoundingMode to_mpfr_rounding_mode(int mode) {

View File

@ -22,11 +22,12 @@ template <typename T>
class RemQuoTestTemplate : public LIBC_NAMESPACE::testing::Test {
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
using Sign = LIBC_NAMESPACE::fputil::Sign;
const T zero = T(FPBits::zero());
const T neg_zero = T(FPBits::neg_zero());
const T inf = T(FPBits::inf());
const T neg_inf = T(FPBits::neg_inf());
const T inf = T(FPBits::inf(Sign::POS));
const T neg_inf = T(FPBits::inf(Sign::NEG));
const T zero = T(FPBits::zero(Sign::POS));
const T neg_zero = T(FPBits::zero(Sign::NEG));
const T nan = T(FPBits::build_quiet_nan(1));
public:

View File

@ -31,11 +31,12 @@ public:
private:
using FPBits = LIBC_NAMESPACE::fputil::FPBits<F>;
using StorageType = typename FPBits::StorageType;
using Sign = LIBC_NAMESPACE::fputil::Sign;
const F zero = F(FPBits::zero());
const F neg_zero = F(FPBits::neg_zero());
const F neg_zero = F(FPBits::zero(Sign::NEG));
const F inf = F(FPBits::inf());
const F neg_inf = F(FPBits::neg_inf());
const F neg_inf = F(FPBits::inf(Sign::NEG));
const F nan = F(FPBits::build_quiet_nan(1));
static constexpr I INTEGER_MIN = I(1) << (sizeof(I) * 8 - 1);
static constexpr I INTEGER_MAX = -(INTEGER_MIN + 1);
@ -127,7 +128,7 @@ public:
// is set.
FPBits bits(F(1.0));
bits.set_biased_exponent(EXPONENT_LIMIT + FPBits::EXP_BIAS);
bits.set_sign(1);
bits.set_sign(Sign::NEG);
bits.set_mantissa(0);
F x = F(bits);
@ -191,7 +192,7 @@ public:
// is set.
FPBits bits(F(1.0));
bits.set_biased_exponent(EXPONENT_LIMIT + FPBits::EXP_BIAS);
bits.set_sign(1);
bits.set_sign(Sign::NEG);
bits.set_mantissa(FPBits::FRACTION_MASK);
F x = F(bits);

View File

@ -22,6 +22,7 @@ using LlvmLibcAtanhfTest = LIBC_NAMESPACE::testing::FPTest<float>;
namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
TEST_F(LlvmLibcAtanhfTest, SpecialNumbers) {
using Sign = LIBC_NAMESPACE::fputil::Sign;
libc_errno = 0;
LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanhf(aNaN));
@ -57,7 +58,7 @@ TEST_F(LlvmLibcAtanhfTest, SpecialNumbers) {
EXPECT_MATH_ERRNO(EDOM);
LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
bt.set_sign(true);
bt.set_sign(Sign::NEG);
EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanhf(bt.get_val()));
EXPECT_FP_EXCEPTION(FE_INVALID);
EXPECT_MATH_ERRNO(EDOM);
@ -77,7 +78,7 @@ TEST_F(LlvmLibcAtanhfTest, SpecialNumbers) {
EXPECT_FP_EXCEPTION(FE_INVALID);
EXPECT_MATH_ERRNO(EDOM);
bt.set_sign(true);
bt.set_sign(Sign::NEG);
EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanhf(neg_inf));
EXPECT_FP_EXCEPTION(FE_INVALID);
EXPECT_MATH_ERRNO(EDOM);

View File

@ -18,6 +18,13 @@ public:
using FuncPtr = T (*)(T, T);
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
using Sign = LIBC_NAMESPACE::fputil::Sign;
const T inf = T(FPBits::inf(Sign::POS));
const T neg_inf = T(FPBits::inf(Sign::NEG));
const T zero = T(FPBits::zero(Sign::POS));
const T neg_zero = T(FPBits::zero(Sign::NEG));
const T nan = T(FPBits::build_quiet_nan(1));
void test_na_n_arg(FuncPtr func) {
EXPECT_FP_EQ(nan, func(nan, inf));
@ -72,13 +79,4 @@ public:
}
}
}
private:
// constexpr does not work on FPBits yet, so we cannot have these constants as
// static.
const T nan = T(FPBits::build_quiet_nan(1));
const T inf = T(FPBits::inf());
const T neg_inf = T(FPBits::neg_inf());
const T zero = T(FPBits::zero());
const T neg_zero = T(FPBits::neg_zero());
};

View File

@ -19,11 +19,13 @@ private:
using Func = T (*)(T, T, T);
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
using Sign = LIBC_NAMESPACE::fputil::Sign;
const T inf = T(FPBits::inf(Sign::POS));
const T neg_inf = T(FPBits::inf(Sign::NEG));
const T zero = T(FPBits::zero(Sign::POS));
const T neg_zero = T(FPBits::zero(Sign::NEG));
const T nan = T(FPBits::build_quiet_nan(1));
const T inf = T(FPBits::inf());
const T neg_inf = T(FPBits::neg_inf());
const T zero = T(FPBits::zero());
const T neg_zero = T(FPBits::neg_zero());
public:
void test_special_numbers(Func func) {

View File

@ -21,11 +21,13 @@ private:
using Func = T (*)(T, T);
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
using Sign = LIBC_NAMESPACE::fputil::Sign;
const T nan = FPBits::build_quiet_nan(1);
const T inf = FPBits::inf();
const T neg_inf = FPBits::neg_inf();
const T zero = FPBits::zero();
const T neg_zero = FPBits::neg_zero();
const T inf = FPBits::inf(Sign::POS);
const T neg_inf = FPBits::inf(Sign::NEG);
const T zero = FPBits::zero(Sign::POS);
const T neg_zero = FPBits::zero(Sign::NEG);
const T max_normal = FPBits::max_normal();
const T min_normal = FPBits::min_normal();
const T max_subnormal = FPBits::max_denormal();

View File

@ -25,11 +25,12 @@ public:
template <typename T>
void test_special_numbers(typename ILogbFunc<T>::Func func) {
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
EXPECT_EQ(FP_ILOGB0, func(T(FPBits::zero())));
EXPECT_EQ(FP_ILOGB0, func(T(FPBits::neg_zero())));
using Sign = LIBC_NAMESPACE::fputil::Sign;
EXPECT_EQ(FP_ILOGB0, func(T(FPBits::zero(Sign::POS))));
EXPECT_EQ(FP_ILOGB0, func(T(FPBits::zero(Sign::NEG))));
EXPECT_EQ(FP_ILOGBNAN, func(T(FPBits::build_quiet_nan(1))));
EXPECT_EQ(INT_MAX, func(T(FPBits::inf())));
EXPECT_EQ(INT_MAX, func(T(FPBits::neg_inf())));
EXPECT_EQ(INT_MAX, func(T(FPBits::inf(Sign::POS))));
EXPECT_EQ(INT_MAX, func(T(FPBits::inf(Sign::NEG))));
}
template <typename T>

View File

@ -23,15 +23,17 @@ class LdExpTestTemplate : public LIBC_NAMESPACE::testing::Test {
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
using NormalFloat = LIBC_NAMESPACE::fputil::NormalFloat<T>;
using StorageType = typename FPBits::StorageType;
using Sign = LIBC_NAMESPACE::fputil::Sign;
const T inf = T(FPBits::inf(Sign::POS));
const T neg_inf = T(FPBits::inf(Sign::NEG));
const T zero = T(FPBits::zero(Sign::POS));
const T neg_zero = T(FPBits::zero(Sign::NEG));
const T nan = T(FPBits::build_quiet_nan(1));
// A normalized mantissa to be used with tests.
static constexpr StorageType MANTISSA = NormalFloat::ONE + 0x1234;
const T zero = T(FPBits::zero());
const T neg_zero = T(FPBits::neg_zero());
const T inf = T(FPBits::inf());
const T neg_inf = T(FPBits::neg_inf());
const T nan = T(FPBits::build_quiet_nan(1));
public:
typedef T (*LdExpFunc)(T, int);

View File

@ -32,12 +32,14 @@ template <typename T>
class NextAfterTestTemplate : public LIBC_NAMESPACE::testing::Test {
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
using Sign = LIBC_NAMESPACE::fputil::Sign;
const T zero = T(FPBits::zero());
const T neg_zero = T(FPBits::neg_zero());
const T inf = T(FPBits::inf());
const T neg_inf = T(FPBits::neg_inf());
const T inf = T(FPBits::inf(Sign::POS));
const T neg_inf = T(FPBits::inf(Sign::NEG));
const T zero = T(FPBits::zero(Sign::POS));
const T neg_zero = T(FPBits::zero(Sign::NEG));
const T nan = T(FPBits::build_quiet_nan(1));
const StorageType min_subnormal = FPBits::MIN_SUBNORMAL;
const StorageType max_subnormal = FPBits::MAX_SUBNORMAL;
const StorageType min_normal = FPBits::MIN_NORMAL;

View File

@ -34,15 +34,16 @@ class NextTowardTestTemplate : public LIBC_NAMESPACE::testing::Test {
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
using ToFPBits = LIBC_NAMESPACE::fputil::FPBits<long double>;
using StorageType = typename FPBits::StorageType;
using Sign = LIBC_NAMESPACE::fputil::Sign;
const T zero = T(FPBits::zero());
const T neg_zero = T(FPBits::neg_zero());
const T inf = T(FPBits::inf());
const T neg_inf = T(FPBits::neg_inf());
const T inf = T(FPBits::inf(Sign::POS));
const T neg_inf = T(FPBits::inf(Sign::NEG));
const T zero = T(FPBits::zero(Sign::POS));
const T neg_zero = T(FPBits::zero(Sign::NEG));
const T nan = T(FPBits::build_quiet_nan(1));
const long double to_zero = ToFPBits::zero();
const long double to_neg_zero = ToFPBits::neg_zero();
const long double to_neg_zero = ToFPBits::zero(Sign::NEG);
const long double to_nan = ToFPBits::build_quiet_nan(1);
const StorageType min_subnormal = FPBits::MIN_SUBNORMAL;

View File

@ -29,11 +29,12 @@ public:
private:
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
using Sign = LIBC_NAMESPACE::fputil::Sign;
const T zero = T(FPBits::zero());
const T neg_zero = T(FPBits::neg_zero());
const T inf = T(FPBits::inf());
const T neg_inf = T(FPBits::neg_inf());
const T inf = T(FPBits::inf(Sign::POS));
const T neg_inf = T(FPBits::inf(Sign::NEG));
const T zero = T(FPBits::zero(Sign::POS));
const T neg_zero = T(FPBits::zero(Sign::NEG));
const T nan = T(FPBits::build_quiet_nan(1));
public:

View File

@ -19,11 +19,12 @@ template <typename T>
class RemQuoTestTemplate : public LIBC_NAMESPACE::testing::Test {
using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
using Sign = LIBC_NAMESPACE::fputil::Sign;
const T zero = T(FPBits::zero());
const T neg_zero = T(FPBits::neg_zero());
const T inf = T(FPBits::inf());
const T neg_inf = T(FPBits::neg_inf());
const T inf = T(FPBits::inf(Sign::POS));
const T neg_inf = T(FPBits::inf(Sign::NEG));
const T zero = T(FPBits::zero(Sign::POS));
const T neg_zero = T(FPBits::zero(Sign::NEG));
const T nan = T(FPBits::build_quiet_nan(1));
public:

View File

@ -28,11 +28,12 @@ public:
private:
using FPBits = LIBC_NAMESPACE::fputil::FPBits<F>;
using StorageType = typename FPBits::StorageType;
using Sign = LIBC_NAMESPACE::fputil::Sign;
const F zero = F(LIBC_NAMESPACE::fputil::FPBits<F>::zero());
const F neg_zero = F(LIBC_NAMESPACE::fputil::FPBits<F>::neg_zero());
const F inf = F(LIBC_NAMESPACE::fputil::FPBits<F>::inf());
const F neg_inf = F(LIBC_NAMESPACE::fputil::FPBits<F>::neg_inf());
const F zero = F(LIBC_NAMESPACE::fputil::FPBits<F>::zero(Sign::POS));
const F neg_zero = F(LIBC_NAMESPACE::fputil::FPBits<F>::zero(Sign::NEG));
const F inf = F(LIBC_NAMESPACE::fputil::FPBits<F>::inf(Sign::POS));
const F neg_inf = F(LIBC_NAMESPACE::fputil::FPBits<F>::inf(Sign::NEG));
const F nan = F(LIBC_NAMESPACE::fputil::FPBits<F>::build_quiet_nan(1));
static constexpr I INTEGER_MIN = I(1) << (sizeof(I) * 8 - 1);
static constexpr I INTEGER_MAX = -(INTEGER_MIN + 1);

View File

@ -19,6 +19,7 @@
using LlvmLibcAtanhfTest = LIBC_NAMESPACE::testing::FPTest<float>;
TEST_F(LlvmLibcAtanhfTest, SpecialNumbers) {
using Sign = LIBC_NAMESPACE::fputil::Sign;
libc_errno = 0;
LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT);
@ -50,7 +51,7 @@ TEST_F(LlvmLibcAtanhfTest, SpecialNumbers) {
FE_INVALID);
EXPECT_MATH_ERRNO(EDOM);
bt.set_sign(true);
bt.set_sign(Sign::NEG);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(LIBC_NAMESPACE::atanhf(bt.get_val()),
FE_INVALID);
EXPECT_MATH_ERRNO(EDOM);
@ -64,7 +65,7 @@ TEST_F(LlvmLibcAtanhfTest, SpecialNumbers) {
EXPECT_FP_IS_NAN_WITH_EXCEPTION(LIBC_NAMESPACE::atanhf(inf), FE_INVALID);
EXPECT_MATH_ERRNO(EDOM);
bt.set_sign(true);
bt.set_sign(Sign::NEG);
EXPECT_FP_IS_NAN_WITH_EXCEPTION(LIBC_NAMESPACE::atanhf(neg_inf), FE_INVALID);
EXPECT_MATH_ERRNO(EDOM);
}

View File

@ -88,7 +88,7 @@ public:
EXPECT_EQ(str_end - inputString, expectedStrLen);
EXPECT_EQ(actual_fp.uintval(), expected_fp.uintval());
EXPECT_EQ(actual_fp.get_sign(), expected_fp.get_sign());
EXPECT_EQ(actual_fp.is_neg(), expected_fp.is_neg());
EXPECT_EQ(actual_fp.get_exponent(), expected_fp.get_exponent());
EXPECT_EQ(actual_fp.get_mantissa(), expected_fp.get_mantissa());
EXPECT_EQ(libc_errno, expected_errno);

View File

@ -32,7 +32,7 @@ TEST(LlvmLibcDifftime, SmokeTest) {
static_cast<long double>(result));
EXPECT_EQ(actual_fp.uintval(), expected_fp.uintval());
EXPECT_EQ(actual_fp.get_sign(), expected_fp.get_sign());
EXPECT_EQ(actual_fp.is_neg(), expected_fp.is_neg());
EXPECT_EQ(actual_fp.get_exponent(), expected_fp.get_exponent());
EXPECT_EQ(actual_fp.get_mantissa(), expected_fp.get_mantissa());
}