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

Guillaume Chatelet via libc-commits libc-commits at lists.llvm.org
Thu Jan 18 02:43:18 PST 2024


https://github.com/gchatelet updated https://github.com/llvm/llvm-project/pull/78500

>From 0e41c24f5f78374e7a2816dc886d338eff3b092b Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Wed, 17 Jan 2024 20:29:47 +0000
Subject: [PATCH 01/10] [libc][NFC] Introduce a Sign type for FPBits

Another patch is needed to cover `DyadicFloat` and `NormalFloat` constructors.
---
 libc/src/__support/FPUtil/BasicOperations.h   |  12 +-
 .../FPUtil/DivisionAndRemainderOperations.h   |   6 +-
 libc/src/__support/FPUtil/FPBits.h            | 118 +++++++++++-------
 .../__support/FPUtil/ManipulationFunctions.h  |  12 +-
 .../FPUtil/NearestIntegerOperations.h         |  18 +--
 libc/src/__support/FPUtil/NormalFloat.h       |  23 ++--
 libc/src/__support/FPUtil/dyadic_float.h      |  10 +-
 libc/src/__support/FPUtil/fpbits_str.h        |   6 +-
 libc/src/__support/FPUtil/generic/FMA.h       |   8 +-
 libc/src/__support/FPUtil/generic/FMod.h      |   6 +-
 libc/src/__support/FPUtil/generic/sqrt.h      |   4 +-
 .../FPUtil/generic/sqrt_80_bit_long_double.h  |   4 +-
 libc/src/__support/float_to_string.h          |   2 +-
 libc/src/__support/str_to_float.h             |  16 +--
 libc/src/math/generic/acosf.cpp               |   3 +-
 libc/src/math/generic/asinf.cpp               |   3 +-
 libc/src/math/generic/atanf.cpp               |  10 +-
 libc/src/math/generic/atanhf.cpp              |   3 +-
 libc/src/math/generic/cosf.cpp                |   3 +-
 libc/src/math/generic/coshf.cpp               |   3 +-
 libc/src/math/generic/erff.cpp                |   2 +-
 libc/src/math/generic/exp10f_impl.h           |   2 +-
 libc/src/math/generic/exp2f_impl.h            |   2 +-
 libc/src/math/generic/expf.cpp                |   2 +-
 libc/src/math/generic/expm1.cpp               |  11 +-
 libc/src/math/generic/expm1f.cpp              |   2 +-
 libc/src/math/generic/inv_trigf_utils.h       |  11 +-
 libc/src/math/generic/log.cpp                 |   2 +-
 libc/src/math/generic/log10.cpp               |   2 +-
 libc/src/math/generic/log10f.cpp              |   2 +-
 libc/src/math/generic/log1p.cpp               |   2 +-
 libc/src/math/generic/log1pf.cpp              |   2 +-
 libc/src/math/generic/log2.cpp                |   2 +-
 libc/src/math/generic/log2f.cpp               |   2 +-
 libc/src/math/generic/logf.cpp                |   2 +-
 libc/src/math/generic/powf.cpp                |  26 ++--
 libc/src/math/generic/sinf.cpp                |   6 +-
 libc/src/math/generic/sinhf.cpp               |   5 +-
 libc/src/math/generic/tanhf.cpp               |  11 +-
 .../stdio/printf_core/float_dec_converter.h   |  22 ++--
 .../stdio/printf_core/float_hex_converter.h   |   4 +-
 .../printf_core/float_inf_nan_converter.h     |   4 +-
 .../test/src/__support/FPUtil/fpbits_test.cpp |  60 ++++-----
 libc/test/src/math/RoundToIntegerTest.h       |   5 +-
 libc/test/src/math/atanhf_test.cpp            |   5 +-
 libc/test/src/math/smoke/atanhf_test.cpp      |   5 +-
 libc/test/src/stdlib/strtold_test.cpp         |   2 +-
 libc/test/src/time/difftime_test.cpp          |   2 +-
 48 files changed, 256 insertions(+), 219 deletions(-)

diff --git a/libc/src/__support/FPUtil/BasicOperations.h b/libc/src/__support/FPUtil/BasicOperations.h
index 2ec61517b0b808..4015edb1b65372 100644
--- a/libc/src/__support/FPUtil/BasicOperations.h
+++ b/libc/src/__support/FPUtil/BasicOperations.h
@@ -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);
   }
diff --git a/libc/src/__support/FPUtil/DivisionAndRemainderOperations.h b/libc/src/__support/FPUtil/DivisionAndRemainderOperations.h
index 65bbe6b099dd00..d3401b10a7cab8 100644
--- a/libc/src/__support/FPUtil/DivisionAndRemainderOperations.h
+++ b/libc/src/__support/FPUtil/DivisionAndRemainderOperations.h
@@ -43,13 +43,13 @@ LIBC_INLINE T remquo(T x, T y, int &q) {
     return x;
   }
 
-  bool result_sign = (xbits.get_sign() == ybits.get_sign() ? false : true);
+  bool result_sign = (xbits.is_neg() == ybits.is_neg() ? false : true);
 
   // 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;
diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h
index 4309a535abd079..6a94798973e634 100644
--- a/libc/src/__support/FPUtil/FPBits.h
+++ b/libc/src/__support/FPUtil/FPBits.h
@@ -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 explicit Sign(bool is_negative)
+      : is_negative(is_negative) {}
+
+  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:
+  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 @@ struct FPRepBase : public internal::FPLayout<fp_type> {
     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 @@ struct FPRepBase : public internal::FPLayout<fp_type> {
   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 @@ struct FPRepBase : public internal::FPLayout<fp_type> {
   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 @@ template <FPType fp_type> struct FPRep : public FPRepBase<fp_type> {
     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 @@ struct FPRep<FPType::X86_Binary80> : public FPRepBase<FPType::X86_Binary80> {
     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 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 neg_zero() { return zero(Sign::NEG); }
 
-  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 neg_inf() { return inf(Sign::NEG); }
 
   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(
diff --git a/libc/src/__support/FPUtil/ManipulationFunctions.h b/libc/src/__support/FPUtil/ManipulationFunctions.h
index 42433b9b8442db..e0bd251883e20b 100644
--- a/libc/src/__support/FPUtil/ManipulationFunctions.h
+++ b/libc/src/__support/FPUtil/ManipulationFunctions.h
@@ -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 bits.is_neg() ? T(FPBits<T>::neg_zero()) : T(FPBits<T>::zero());
   } 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 bits.is_neg() ? T(FPBits<T>::neg_zero()) : T(FPBits<T>::zero());
     } 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);
 }
 
@@ -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 bits.is_neg() ? T(FPBits<T>::neg_inf()) : T(FPBits<T>::inf());
 
   // 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 bits.is_neg() ? T(FPBits<T>::neg_zero()) : T(FPBits<T>::zero());
 
   // 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;
   }
 
diff --git a/libc/src/__support/FPUtil/NearestIntegerOperations.h b/libc/src/__support/FPUtil/NearestIntegerOperations.h
index 64c44e0b3a0c44..e32b4d27a7a1df 100644
--- a/libc/src/__support/FPUtil/NearestIntegerOperations.h
+++ b/libc/src/__support/FPUtil/NearestIntegerOperations.h
@@ -41,7 +41,7 @@ LIBC_INLINE T trunc(T x) {
 
   // If the exponent is such that abs(x) is less than 1, then return 0.
   if (exponent <= -1) {
-    if (bits.get_sign())
+    if (bits.is_neg())
       return T(-0.0);
     else
       return T(0.0);
@@ -60,7 +60,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 +93,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 +109,7 @@ LIBC_INLINE T round(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
@@ -161,7 +161,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 +247,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_neg() == 0 || 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.
diff --git a/libc/src/__support/FPUtil/NormalFloat.h b/libc/src/__support/FPUtil/NormalFloat.h
index e70c89a7dbe15a..39376bfcba0319 100644
--- a/libc/src/__support/FPUtil/NormalFloat.h
+++ b/libc/src/__support/FPUtil/NormalFloat.h
@@ -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(Sign(s)) {
     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 @@ template <typename T> struct NormalFloat {
 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);
diff --git a/libc/src/__support/FPUtil/dyadic_float.h b/libc/src/__support/FPUtil/dyadic_float.h
index ccd3c69bf3db2a..3cc3890b65a01b 100644
--- a/libc/src/__support/FPUtil/dyadic_float.h
+++ b/libc/src/__support/FPUtil/dyadic_float.h
@@ -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(Sign(s)), 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())) {
diff --git a/libc/src/__support/FPUtil/fpbits_str.h b/libc/src/__support/FPUtil/fpbits_str.h
index 50019f32b2c446..b48def8b1cdcf4 100644
--- a/libc/src/__support/FPUtil/fpbits_str.h
+++ b/libc/src/__support/FPUtil/fpbits_str.h
@@ -39,9 +39,9 @@ template <typename T> LIBC_INLINE cpp::string str(fputil::FPBits<T> x) {
   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 = [](bool is_neg) -> char { return is_neg ? '1' : '0'; };
 
   cpp::string s;
 
@@ -49,7 +49,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.is_neg());
 
   s += ", E: ";
   const details::ZeroPaddedHexFmt<uint16_t> exponent(x.get_biased_exponent());
diff --git a/libc/src/__support/FPUtil/generic/FMA.h b/libc/src/__support/FPUtil/generic/FMA.h
index b88089ee679f28..db1cc0a4716f74 100644
--- a/libc/src/__support/FPUtil/generic/FMA.h
+++ b/libc/src/__support/FPUtil/generic/FMA.h
@@ -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,9 +118,9 @@ 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 x_sign = x_bits.is_neg();
+  bool y_sign = y_bits.is_neg();
+  bool z_sign = z_bits.is_neg();
   bool prod_sign = x_sign != y_sign;
   x_exp += x_bits.get_biased_exponent();
   y_exp += y_bits.get_biased_exponent();
diff --git a/libc/src/__support/FPUtil/generic/FMod.h b/libc/src/__support/FPUtil/generic/FMod.h
index d12be7bb14d07a..f4000b97751efc 100644
--- a/libc/src/__support/FPUtil/generic/FMod.h
+++ b/libc/src/__support/FPUtil/generic/FMod.h
@@ -308,9 +308,9 @@ class FMod {
     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();
diff --git a/libc/src/__support/FPUtil/generic/sqrt.h b/libc/src/__support/FPUtil/generic/sqrt.h
index 7d56462a168564..f273b678edf527 100644
--- a/libc/src/__support/FPUtil/generic/sqrt.h
+++ b/libc/src/__support/FPUtil/generic/sqrt.h
@@ -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 {
diff --git a/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h b/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h
index 8815a18cfbc393..4fe9b49ff41cf0 100644
--- a/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h
+++ b/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h
@@ -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 {
diff --git a/libc/src/__support/float_to_string.h b/libc/src/__support/float_to_string.h
index 52442608798a5f..f0d712f06e637f 100644
--- a/libc/src/__support/float_to_string.h
+++ b/libc/src/__support/float_to_string.h
@@ -421,7 +421,7 @@ class FloatToString {
 
 public:
   LIBC_INLINE constexpr FloatToString(T init_float) : float_bits(init_float) {
-    is_negative = float_bits.get_sign();
+    is_negative = float_bits.is_neg();
     exponent = float_bits.get_explicit_exponent();
     mantissa = float_bits.get_explicit_mantissa();
 
diff --git a/libc/src/__support/str_to_float.h b/libc/src/__support/str_to_float.h
index f2d4ec7fb11f8b..dd7dfc730ea2cc 100644
--- a/libc/src/__support/str_to_float.h
+++ b/libc/src/__support/str_to_float.h
@@ -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] &&
diff --git a/libc/src/math/generic/acosf.cpp b/libc/src/math/generic/acosf.cpp
index 2a9b2a6852fe9e..67832596a67fba 100644
--- a/libc/src/math/generic/acosf.cpp
+++ b/libc/src/math/generic/acosf.cpp
@@ -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);
diff --git a/libc/src/math/generic/asinf.cpp b/libc/src/math/generic/asinf.cpp
index 51eefe984b6779..bc0d27c1eebc5d 100644
--- a/libc/src/math/generic/asinf.cpp
+++ b/libc/src/math/generic/asinf.cpp
@@ -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);
diff --git a/libc/src/math/generic/atanf.cpp b/libc/src/math/generic/atanf.cpp
index f2e4f8bb93b6f9..e0f8a1bfc2ecc9 100644
--- a/libc/src/math/generic/atanf.cpp
+++ b/libc/src/math/generic/atanf.cpp
@@ -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();
diff --git a/libc/src/math/generic/atanhf.cpp b/libc/src/math/generic/atanhf.cpp
index df5f53f392cf30..fd6f5c96b6b4e6 100644
--- a/libc/src/math/generic/atanhf.cpp
+++ b/libc/src/math/generic/atanhf.cpp
@@ -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
diff --git a/libc/src/math/generic/cosf.cpp b/libc/src/math/generic/cosf.cpp
index 67b60de03024fb..89333ab19e89f9 100644
--- a/libc/src/math/generic/cosf.cpp
+++ b/libc/src/math/generic/cosf.cpp
@@ -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());
diff --git a/libc/src/math/generic/coshf.cpp b/libc/src/math/generic/coshf.cpp
index 4a55b6940ff8c2..3b01852e9f544a 100644
--- a/libc/src/math/generic/coshf.cpp
+++ b/libc/src/math/generic/coshf.cpp
@@ -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();
diff --git a/libc/src/math/generic/erff.cpp b/libc/src/math/generic/erff.cpp
index 333ca197dbedb5..f120d5646e0439 100644
--- a/libc/src/math/generic/erff.cpp
+++ b/libc/src/math/generic/erff.cpp
@@ -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];
diff --git a/libc/src/math/generic/exp10f_impl.h b/libc/src/math/generic/exp10f_impl.h
index a2ec5391ba50a7..2861659a6e57e0 100644
--- a/libc/src/math/generic/exp10f_impl.h
+++ b/libc/src/math/generic/exp10f_impl.h
@@ -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();
diff --git a/libc/src/math/generic/exp2f_impl.h b/libc/src/math/generic/exp2f_impl.h
index e6fd65264c721e..86360840b96e6f 100644
--- a/libc/src/math/generic/exp2f_impl.h
+++ b/libc/src/math/generic/exp2f_impl.h
@@ -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();
diff --git a/libc/src/math/generic/expf.cpp b/libc/src/math/generic/expf.cpp
index d0bb681df9e9dd..88d408994fe427 100644
--- a/libc/src/math/generic/expf.cpp
+++ b/libc/src/math/generic/expf.cpp
@@ -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();
diff --git a/libc/src/math/generic/expm1.cpp b/libc/src/math/generic/expm1.cpp
index 8ab341d55a226e..3d343a99d1c288 100644
--- a/libc/src/math/generic/expm1.cpp
+++ b/libc/src/math/generic/expm1.cpp
@@ -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,7 @@ 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;
+  uint64_t err = x_is_neg ? (static_cast<uint64_t>(-hi) << 52) : 0;
 
   double err_d = cpp::bit_cast<double>(ERR_D + err);
 
diff --git a/libc/src/math/generic/expm1f.cpp b/libc/src/math/generic/expm1f.cpp
index 3739a7bbbaa84c..c6e0663ec46c3f 100644
--- a/libc/src/math/generic/expm1f.cpp
+++ b/libc/src/math/generic/expm1f.cpp
@@ -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;
diff --git a/libc/src/math/generic/inv_trigf_utils.h b/libc/src/math/generic/inv_trigf_utils.h
index 4e85d4ae08d571..20f912de2ac008 100644
--- a/libc/src/math/generic/inv_trigf_utils.h
+++ b/libc/src/math/generic/inv_trigf_utils.h
@@ -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|],
diff --git a/libc/src/math/generic/log.cpp b/libc/src/math/generic/log.cpp
index 8f22fdea93217f..859b32ddb77c41 100644
--- a/libc/src/math/generic/log.cpp
+++ b/libc/src/math/generic/log.cpp
@@ -749,7 +749,7 @@ LLVM_LIBC_FUNCTION(double, log, (double x)) {
       fputil::raise_except_if_required(FE_DIVBYZERO);
       return static_cast<double>(FPBits_t::neg_inf());
     }
-    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);
diff --git a/libc/src/math/generic/log10.cpp b/libc/src/math/generic/log10.cpp
index df82f24dc6967c..12a51b7182e6a2 100644
--- a/libc/src/math/generic/log10.cpp
+++ b/libc/src/math/generic/log10.cpp
@@ -750,7 +750,7 @@ LLVM_LIBC_FUNCTION(double, log10, (double x)) {
       fputil::raise_except_if_required(FE_DIVBYZERO);
       return static_cast<double>(FPBits_t::neg_inf());
     }
-    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);
diff --git a/libc/src/math/generic/log10f.cpp b/libc/src/math/generic/log10f.cpp
index da69f7f5ad4d9e..40122391d1b6b4 100644
--- a/libc/src/math/generic/log10f.cpp
+++ b/libc/src/math/generic/log10f.cpp
@@ -167,7 +167,7 @@ LLVM_LIBC_FUNCTION(float, log10f, (float x)) {
       fputil::raise_except_if_required(FE_DIVBYZERO);
       return static_cast<float>(FPBits::neg_inf());
     }
-    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);
diff --git a/libc/src/math/generic/log1p.cpp b/libc/src/math/generic/log1p.cpp
index 74eed6ceeb28dc..caa8b2e4d0b4cc 100644
--- a/libc/src/math/generic/log1p.cpp
+++ b/libc/src/math/generic/log1p.cpp
@@ -894,7 +894,7 @@ LLVM_LIBC_FUNCTION(double, log1p, (double x)) {
           fputil::raise_except_if_required(FE_DIVBYZERO);
           return static_cast<double>(FPBits_t::neg_inf());
         }
-        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);
diff --git a/libc/src/math/generic/log1pf.cpp b/libc/src/math/generic/log1pf.cpp
index 891700d5ed08c8..eadb3435abb975 100644
--- a/libc/src/math/generic/log1pf.cpp
+++ b/libc/src/math/generic/log1pf.cpp
@@ -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);
diff --git a/libc/src/math/generic/log2.cpp b/libc/src/math/generic/log2.cpp
index 1427d1934db900..5ef2d100bf758b 100644
--- a/libc/src/math/generic/log2.cpp
+++ b/libc/src/math/generic/log2.cpp
@@ -871,7 +871,7 @@ LLVM_LIBC_FUNCTION(double, log2, (double x)) {
       fputil::raise_except_if_required(FE_DIVBYZERO);
       return static_cast<double>(FPBits_t::neg_inf());
     }
-    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);
diff --git a/libc/src/math/generic/log2f.cpp b/libc/src/math/generic/log2f.cpp
index 07dedba85e6273..4bd40522ce2dac 100644
--- a/libc/src/math/generic/log2f.cpp
+++ b/libc/src/math/generic/log2f.cpp
@@ -74,7 +74,7 @@ LLVM_LIBC_FUNCTION(float, log2f, (float x)) {
       fputil::raise_except_if_required(FE_DIVBYZERO);
       return static_cast<float>(FPBits::neg_inf());
     }
-    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);
diff --git a/libc/src/math/generic/logf.cpp b/libc/src/math/generic/logf.cpp
index f1f93468479b11..358994735929a1 100644
--- a/libc/src/math/generic/logf.cpp
+++ b/libc/src/math/generic/logf.cpp
@@ -119,7 +119,7 @@ LLVM_LIBC_FUNCTION(float, logf, (float x)) {
         fputil::raise_except_if_required(FE_DIVBYZERO);
         return static_cast<float>(FPBits::neg_inf());
       }
-      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);
diff --git a/libc/src/math/generic/powf.cpp b/libc/src/math/generic/powf.cpp
index 49f33b71c56009..f1be147298a410 100644
--- a/libc/src/math/generic/powf.cpp
+++ b/libc/src/math/generic/powf.cpp
@@ -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(Sign(out_is_neg));
       }
       // 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(Sign(out_is_neg));
     }
     }
 
@@ -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)) {
diff --git a/libc/src/math/generic/sinf.cpp b/libc/src/math/generic/sinf.cpp
index 6fc1abb83e2e7b..9e574d4e572402 100644
--- a/libc/src/math/generic/sinf.cpp
+++ b/libc/src/math/generic/sinf.cpp
@@ -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)) {
diff --git a/libc/src/math/generic/sinhf.cpp b/libc/src/math/generic/sinhf.cpp
index d64519d0ec79bf..b3850c67427066 100644
--- a/libc/src/math/generic/sinhf.cpp
+++ b/libc/src/math/generic/sinhf.cpp
@@ -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.
diff --git a/libc/src/math/generic/tanhf.cpp b/libc/src/math/generic/tanhf.cpp
index 48e78ec2383f29..0efd0cefebe577 100644
--- a/libc/src/math/generic/tanhf.cpp
+++ b/libc/src/math/generic/tanhf.cpp
@@ -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))
diff --git a/libc/src/stdio/printf_core/float_dec_converter.h b/libc/src/stdio/printf_core/float_dec_converter.h
index cfa351cf017aeb..e1a44234bb309f 100644
--- a/libc/src/stdio/printf_core/float_dec_converter.h
+++ b/libc/src/stdio/printf_core/float_dec_converter.h
@@ -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,8 @@ 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 +587,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 +594,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 +734,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 +749,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 +981,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) {
diff --git a/libc/src/stdio/printf_core/float_hex_converter.h b/libc/src/stdio/printf_core/float_hex_converter.h
index 5ccae81b430c57..68a4ba6209d091 100644
--- a/libc/src/stdio/printf_core/float_hex_converter.h
+++ b/libc/src/stdio/printf_core/float_hex_converter.h
@@ -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();
diff --git a/libc/src/stdio/printf_core/float_inf_nan_converter.h b/libc/src/stdio/printf_core/float_inf_nan_converter.h
index 8669dc374cb297..f755ef6e31f261 100644
--- a/libc/src/stdio/printf_core/float_inf_nan_converter.h
+++ b/libc/src/stdio/printf_core/float_inf_nan_converter.h
@@ -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();
   }
 
diff --git a/libc/test/src/__support/FPUtil/fpbits_test.cpp b/libc/test/src/__support/FPUtil/fpbits_test.cpp
index a955f460cf3bb3..c2ddb8070508df 100644
--- a/libc/test/src/__support/FPUtil/fpbits_test.cpp
+++ b/libc/test/src/__support/FPUtil/fpbits_test.cpp
@@ -236,7 +236,7 @@ TEST(LlvmLibcFPBitsTest, FloatType) {
                "(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 +244,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 +252,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 +260,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 +268,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 +276,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));
@@ -299,7 +299,7 @@ TEST(LlvmLibcFPBitsTest, DoubleType) {
       "(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 +307,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 +315,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 +323,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 +331,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 +339,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));
@@ -368,7 +368,7 @@ TEST(LlvmLibcFPBitsTest, X86LongDoubleType) {
       "(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 +379,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 +390,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 +400,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 +411,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 +421,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);
@@ -451,7 +451,7 @@ TEST(LlvmLibcFPBitsTest, LongDoubleType) {
       "(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 +461,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 +471,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 +480,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 +490,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 +499,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);
@@ -527,7 +527,7 @@ TEST(LlvmLibcFPBitsTest, Float128Type) {
       "(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);
@@ -537,7 +537,7 @@ TEST(LlvmLibcFPBitsTest, Float128Type) {
                "(S: 0, E: 0x0000, M: 0x00000000000000000000000000000000)");
 
   Float128Bits negzero(Float128Bits::neg_zero());
-  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);
@@ -547,7 +547,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 +556,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 +566,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 +575,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);
diff --git a/libc/test/src/math/RoundToIntegerTest.h b/libc/test/src/math/RoundToIntegerTest.h
index d76b5a10dfa259..b8f1c85cb91c2e 100644
--- a/libc/test/src/math/RoundToIntegerTest.h
+++ b/libc/test/src/math/RoundToIntegerTest.h
@@ -31,6 +31,7 @@ class RoundToIntegerTestTemplate : public LIBC_NAMESPACE::testing::Test {
 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());
@@ -127,7 +128,7 @@ class RoundToIntegerTestTemplate : public LIBC_NAMESPACE::testing::Test {
     // 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 @@ class RoundToIntegerTestTemplate : public LIBC_NAMESPACE::testing::Test {
     // 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);
diff --git a/libc/test/src/math/atanhf_test.cpp b/libc/test/src/math/atanhf_test.cpp
index f62830ac9d4ef7..fcc9f44dbea932 100644
--- a/libc/test/src/math/atanhf_test.cpp
+++ b/libc/test/src/math/atanhf_test.cpp
@@ -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);
diff --git a/libc/test/src/math/smoke/atanhf_test.cpp b/libc/test/src/math/smoke/atanhf_test.cpp
index 0f7dc0d3063490..f27b8e130fc919 100644
--- a/libc/test/src/math/smoke/atanhf_test.cpp
+++ b/libc/test/src/math/smoke/atanhf_test.cpp
@@ -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);
 }
diff --git a/libc/test/src/stdlib/strtold_test.cpp b/libc/test/src/stdlib/strtold_test.cpp
index 86ac8a6e26d7c0..51f9975772aa5e 100644
--- a/libc/test/src/stdlib/strtold_test.cpp
+++ b/libc/test/src/stdlib/strtold_test.cpp
@@ -88,7 +88,7 @@ class LlvmLibcStrToLDTest : public LIBC_NAMESPACE::testing::Test {
     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);
diff --git a/libc/test/src/time/difftime_test.cpp b/libc/test/src/time/difftime_test.cpp
index 9c3e8d3f30f2b9..68ff4630e61baf 100644
--- a/libc/test/src/time/difftime_test.cpp
+++ b/libc/test/src/time/difftime_test.cpp
@@ -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());
 }

>From 1ddf1c20edfd7a58dd03921df4bc49aedc1fe7c8 Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Wed, 17 Jan 2024 20:50:47 +0000
Subject: [PATCH 02/10] Simplify some expressions

---
 libc/src/__support/FPUtil/FPBits.h            |  5 ++++
 .../__support/FPUtil/ManipulationFunctions.h  |  4 ++--
 .../FPUtil/NearestIntegerOperations.h         | 23 +++++--------------
 3 files changed, 13 insertions(+), 19 deletions(-)

diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h
index 6a94798973e634..75ce2c699a488a 100644
--- a/libc/src/__support/FPUtil/FPBits.h
+++ b/libc/src/__support/FPUtil/FPBits.h
@@ -708,6 +708,11 @@ template <typename T> struct FPBits : public internal::FPRep<get_fp_type<T>()> {
 
   // Methods below this are used by tests.
 
+
+  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();
   }
diff --git a/libc/src/__support/FPUtil/ManipulationFunctions.h b/libc/src/__support/FPUtil/ManipulationFunctions.h
index e0bd251883e20b..a162ce5fbf6fa0 100644
--- a/libc/src/__support/FPUtil/ManipulationFunctions.h
+++ b/libc/src/__support/FPUtil/ManipulationFunctions.h
@@ -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.is_neg() ? 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.is_neg() ? 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);
diff --git a/libc/src/__support/FPUtil/NearestIntegerOperations.h b/libc/src/__support/FPUtil/NearestIntegerOperations.h
index e32b4d27a7a1df..62568977dc0c8b 100644
--- a/libc/src/__support/FPUtil/NearestIntegerOperations.h
+++ b/libc/src/__support/FPUtil/NearestIntegerOperations.h
@@ -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.is_neg())
-      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);
@@ -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.is_neg();
   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);
   }
 }
 
@@ -256,7 +245,7 @@ LIBC_INLINE I rounded_float_to_signed_integer(F x) {
     set_domain_error_and_raise_invalid();
     return bits.is_neg() ? INTEGER_MIN : INTEGER_MAX;
   } else if (exponent == EXPONENT_LIMIT) {
-    if (bits.is_neg() == 0 || bits.get_mantissa() != 0) {
+    if (bits.is_pos() || bits.get_mantissa() != 0) {
       set_domain_error_and_raise_invalid();
       return bits.is_neg() ? INTEGER_MIN : INTEGER_MAX;
     }

>From 822fe22e7b1a527718feac7862d386eda43bdd9e Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Wed, 17 Jan 2024 21:01:16 +0000
Subject: [PATCH 03/10] More simplifications

---
 libc/src/__support/FPUtil/generic/FMA.h | 25 +++++++++++--------------
 libc/src/__support/float_to_string.h    |  4 ----
 2 files changed, 11 insertions(+), 18 deletions(-)

diff --git a/libc/src/__support/FPUtil/generic/FMA.h b/libc/src/__support/FPUtil/generic/FMA.h
index db1cc0a4716f74..2aaf6ce369a37a 100644
--- a/libc/src/__support/FPUtil/generic/FMA.h
+++ b/libc/src/__support/FPUtil/generic/FMA.h
@@ -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.is_neg();
-  bool y_sign = y_bits.is_neg();
-  bool z_sign = z_bits.is_neg();
-  bool prod_sign = x_sign != y_sign;
+  const Sign z_sign = z_bits.sign();
+  Sign prod_sign = Sign(x_bits.sign() != y_bits.sign());
   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;
   }
diff --git a/libc/src/__support/float_to_string.h b/libc/src/__support/float_to_string.h
index f0d712f06e637f..ab1afbe54dfac0 100644
--- a/libc/src/__support/float_to_string.h
+++ b/libc/src/__support/float_to_string.h
@@ -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.is_neg();
     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(); }

>From e75bfc699fb28dcb9c16f3b7988eb89229f44827 Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Wed, 17 Jan 2024 21:25:56 +0000
Subject: [PATCH 04/10] Remove neg_zero / neg_inf

---
 libc/src/__support/FPUtil/FPBits.h            |  5 ---
 .../__support/FPUtil/ManipulationFunctions.h  |  8 ++--
 libc/src/math/generic/log.cpp                 |  2 +-
 libc/src/math/generic/log10.cpp               |  2 +-
 libc/src/math/generic/log10f.cpp              |  2 +-
 libc/src/math/generic/log1p.cpp               |  2 +-
 libc/src/math/generic/log1pf.cpp              |  2 +-
 libc/src/math/generic/log2.cpp                |  2 +-
 libc/src/math/generic/log2f.cpp               |  2 +-
 libc/src/math/generic/logf.cpp                |  4 +-
 libc/test/UnitTest/FPMatcher.h                | 18 ++++----
 .../test/src/__support/FPUtil/fpbits_test.cpp | 42 ++++++++++++-------
 libc/test/src/math/FDimTest.h                 |  5 ++-
 libc/test/src/math/FmaTest.h                  |  4 +-
 libc/test/src/math/HypotTest.h                |  5 ++-
 libc/test/src/math/ILogbTest.h                |  5 ++-
 libc/test/src/math/LdExpTest.h                |  5 ++-
 libc/test/src/math/NextAfterTest.h            |  5 ++-
 libc/test/src/math/RIntTest.h                 |  5 ++-
 libc/test/src/math/RemQuoTest.h               |  5 ++-
 libc/test/src/math/RoundToIntegerTest.h       |  4 +-
 libc/test/src/math/smoke/FDimTest.h           |  4 +-
 libc/test/src/math/smoke/FmaTest.h            |  4 +-
 libc/test/src/math/smoke/HypotTest.h          |  4 +-
 libc/test/src/math/smoke/ILogbTest.h          |  4 +-
 libc/test/src/math/smoke/LdExpTest.h          |  4 +-
 libc/test/src/math/smoke/NextAfterTest.h      |  4 +-
 libc/test/src/math/smoke/NextTowardTest.h     |  6 +--
 libc/test/src/math/smoke/RIntTest.h           |  4 +-
 libc/test/src/math/smoke/RemQuoTest.h         |  4 +-
 libc/test/src/math/smoke/RoundToIntegerTest.h |  2 +-
 31 files changed, 94 insertions(+), 80 deletions(-)

diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h
index 75ce2c699a488a..990b88d18efeef 100644
--- a/libc/src/__support/FPUtil/FPBits.h
+++ b/libc/src/__support/FPUtil/FPBits.h
@@ -708,7 +708,6 @@ template <typename T> struct FPBits : public internal::FPRep<get_fp_type<T>()> {
 
   // Methods below this are used by tests.
 
-
   LIBC_INLINE static constexpr T one(Sign sign = Sign::POS) {
     return FPBits(UP::one(sign)).get_val();
   }
@@ -717,14 +716,10 @@ template <typename T> struct FPBits : public internal::FPRep<get_fp_type<T>()> {
     return FPBits(UP::zero(sign)).get_val();
   }
 
-  LIBC_INLINE static constexpr T neg_zero() { return zero(Sign::NEG); }
-
   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(Sign::NEG); }
-
   LIBC_INLINE static constexpr T min_normal() {
     return FPBits(UP::min_normal(Sign::POS)).get_val();
   }
diff --git a/libc/src/__support/FPUtil/ManipulationFunctions.h b/libc/src/__support/FPUtil/ManipulationFunctions.h
index a162ce5fbf6fa0..81c8281f3c7bbe 100644
--- a/libc/src/__support/FPUtil/ManipulationFunctions.h
+++ b/libc/src/__support/FPUtil/ManipulationFunctions.h
@@ -49,13 +49,13 @@ LIBC_INLINE T modf(T x, T &iptr) {
     return x;
   } else if (bits.is_inf()) {
     iptr = x;
-    return bits.is_neg() ? 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.is_neg() ? T(FPBits<T>::neg_zero()) : T(FPBits<T>::zero());
+      return T(FPBits<T>::zero(bits.sign()));
     } else {
       return x - iptr;
     }
@@ -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);
diff --git a/libc/src/math/generic/log.cpp b/libc/src/math/generic/log.cpp
index 859b32ddb77c41..5b3f48c85614b7 100644
--- a/libc/src/math/generic/log.cpp
+++ b/libc/src/math/generic/log.cpp
@@ -747,7 +747,7 @@ 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.is_neg() && !xbits.is_nan()) {
       fputil::set_errno_if_required(EDOM);
diff --git a/libc/src/math/generic/log10.cpp b/libc/src/math/generic/log10.cpp
index 12a51b7182e6a2..b7b49e2b3ac4b1 100644
--- a/libc/src/math/generic/log10.cpp
+++ b/libc/src/math/generic/log10.cpp
@@ -748,7 +748,7 @@ 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.is_neg() && !xbits.is_nan()) {
       fputil::set_errno_if_required(EDOM);
diff --git a/libc/src/math/generic/log10f.cpp b/libc/src/math/generic/log10f.cpp
index 40122391d1b6b4..46505f4e07e676 100644
--- a/libc/src/math/generic/log10f.cpp
+++ b/libc/src/math/generic/log10f.cpp
@@ -165,7 +165,7 @@ 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.is_neg() && !xbits.is_nan()) {
       // Return NaN and raise FE_INVALID
diff --git a/libc/src/math/generic/log1p.cpp b/libc/src/math/generic/log1p.cpp
index caa8b2e4d0b4cc..af651d3e5bca27 100644
--- a/libc/src/math/generic/log1p.cpp
+++ b/libc/src/math/generic/log1p.cpp
@@ -892,7 +892,7 @@ 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.is_neg() && !xbits.is_nan()) {
           // x < -1.0
diff --git a/libc/src/math/generic/log1pf.cpp b/libc/src/math/generic/log1pf.cpp
index eadb3435abb975..0812569c624b85 100644
--- a/libc/src/math/generic/log1pf.cpp
+++ b/libc/src/math/generic/log1pf.cpp
@@ -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);
diff --git a/libc/src/math/generic/log2.cpp b/libc/src/math/generic/log2.cpp
index 5ef2d100bf758b..261078f7107426 100644
--- a/libc/src/math/generic/log2.cpp
+++ b/libc/src/math/generic/log2.cpp
@@ -869,7 +869,7 @@ 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.is_neg() && !xbits.is_nan()) {
       fputil::set_errno_if_required(EDOM);
diff --git a/libc/src/math/generic/log2f.cpp b/libc/src/math/generic/log2f.cpp
index 4bd40522ce2dac..9cddbb9e8ea486 100644
--- a/libc/src/math/generic/log2f.cpp
+++ b/libc/src/math/generic/log2f.cpp
@@ -72,7 +72,7 @@ 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.is_neg() && !xbits.is_nan()) {
       fputil::set_errno_if_required(EDOM);
diff --git a/libc/src/math/generic/logf.cpp b/libc/src/math/generic/logf.cpp
index 358994735929a1..8ccb55dcc9e336 100644
--- a/libc/src/math/generic/logf.cpp
+++ b/libc/src/math/generic/logf.cpp
@@ -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,7 +117,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));
       }
       if (xbits.is_neg() && !xbits.is_nan()) {
         // Return NaN and raise FE_INVALID
diff --git a/libc/test/UnitTest/FPMatcher.h b/libc/test/UnitTest/FPMatcher.h
index 003de7eb72ac8e..26b8e3e60bdfd6 100644
--- a/libc/test/UnitTest/FPMatcher.h
+++ b/libc/test/UnitTest/FPMatcher.h
@@ -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();                               \
diff --git a/libc/test/src/__support/FPUtil/fpbits_test.cpp b/libc/test/src/__support/FPUtil/fpbits_test.cpp
index c2ddb8070508df..f0b155085dabf5 100644
--- a/libc/test/src/__support/FPUtil/fpbits_test.cpp
+++ b/libc/test/src/__support/FPUtil/fpbits_test.cpp
@@ -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,10 +229,12 @@ 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)");
 
@@ -290,10 +293,12 @@ 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)");
@@ -358,10 +363,12 @@ 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(),
@@ -441,10 +448,12 @@ 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(),
@@ -517,10 +526,11 @@ 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(),
@@ -536,7 +546,7 @@ TEST(LlvmLibcFPBitsTest, Float128Type) {
                "0x00000000000000000000000000000000 = "
                "(S: 0, E: 0x0000, M: 0x00000000000000000000000000000000)");
 
-  Float128Bits negzero(Float128Bits::neg_zero());
+  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)
diff --git a/libc/test/src/math/FDimTest.h b/libc/test/src/math/FDimTest.h
index e926640abc90e0..288d966b97ee86 100644
--- a/libc/test/src/math/FDimTest.h
+++ b/libc/test/src/math/FDimTest.h
@@ -17,6 +17,7 @@ class FDimTestTemplate : public LIBC_NAMESPACE::testing::Test {
 public:
   using FuncPtr = T (*)(T, T);
   using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
+  using Sign = LIBC_NAMESPACE::fputil::Sign;
   using StorageType = typename FPBits::StorageType;
 
   void test_na_n_arg(FuncPtr func) {
@@ -78,7 +79,7 @@ class FDimTestTemplate : public LIBC_NAMESPACE::testing::Test {
   // 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 neg_inf = T(FPBits::inf(Sign::NEG));
   const T zero = T(FPBits::zero());
-  const T neg_zero = T(FPBits::neg_zero());
+  const T neg_zero = T(FPBits::zero(Sign::NEG));
 };
diff --git a/libc/test/src/math/FmaTest.h b/libc/test/src/math/FmaTest.h
index af895e29f33c3e..c528c10401e293 100644
--- a/libc/test/src/math/FmaTest.h
+++ b/libc/test/src/math/FmaTest.h
@@ -25,9 +25,9 @@ class FmaTestTemplate : public LIBC_NAMESPACE::testing::Test {
   using StorageType = typename FPBits::StorageType;
   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 neg_inf = T(FPBits::inf(Sign::NEG));
   const T zero = T(FPBits::zero());
-  const T neg_zero = T(FPBits::neg_zero());
+  const T neg_zero = T(FPBits::zero(Sign::NEG));
 
   StorageType get_random_bit_pattern() {
     StorageType bits{0};
diff --git a/libc/test/src/math/HypotTest.h b/libc/test/src/math/HypotTest.h
index 4d8ef86fa9c461..b7eb63c192c70c 100644
--- a/libc/test/src/math/HypotTest.h
+++ b/libc/test/src/math/HypotTest.h
@@ -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();
diff --git a/libc/test/src/math/ILogbTest.h b/libc/test/src/math/ILogbTest.h
index 9f857da5547c7d..9fa25c9ff98614 100644
--- a/libc/test/src/math/ILogbTest.h
+++ b/libc/test/src/math/ILogbTest.h
@@ -25,11 +25,12 @@ class LlvmLibcILogbTest : public LIBC_NAMESPACE::testing::Test {
   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>
diff --git a/libc/test/src/math/LdExpTest.h b/libc/test/src/math/LdExpTest.h
index 371654e69c3d54..fe3c492d25f851 100644
--- a/libc/test/src/math/LdExpTest.h
+++ b/libc/test/src/math/LdExpTest.h
@@ -22,14 +22,15 @@ template <typename T>
 class LdExpTestTemplate : public LIBC_NAMESPACE::testing::Test {
   using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
   using NormalFloat = LIBC_NAMESPACE::fputil::NormalFloat<T>;
+  using Sign = LIBC_NAMESPACE::fputil::Sign;
   using StorageType = typename FPBits::StorageType;
   // 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 neg_zero = T(FPBits::zero(Sign::NEG));
   const T inf = T(FPBits::inf());
-  const T neg_inf = T(FPBits::neg_inf());
+  const T neg_inf = T(FPBits::inf(Sign::NEG));
   const T nan = T(FPBits::build_quiet_nan(1));
 
 public:
diff --git a/libc/test/src/math/NextAfterTest.h b/libc/test/src/math/NextAfterTest.h
index 005c5730e8f52d..62f7d596827531 100644
--- a/libc/test/src/math/NextAfterTest.h
+++ b/libc/test/src/math/NextAfterTest.h
@@ -21,11 +21,12 @@ 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 neg_zero = T(FPBits::zero(Sign::NEG));
   const T inf = T(FPBits::inf());
-  const T neg_inf = T(FPBits::neg_inf());
+  const T neg_inf = T(FPBits::inf(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;
diff --git a/libc/test/src/math/RIntTest.h b/libc/test/src/math/RIntTest.h
index 2471b831759fe7..3a8430dc31b35e 100644
--- a/libc/test/src/math/RIntTest.h
+++ b/libc/test/src/math/RIntTest.h
@@ -32,11 +32,12 @@ class RIntTestTemplate : public LIBC_NAMESPACE::testing::Test {
 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 neg_zero = T(FPBits::zero(Sign::NEG));
   const T inf = T(FPBits::inf());
-  const T neg_inf = T(FPBits::neg_inf());
+  const T neg_inf = T(FPBits::inf(Sign::NEG));
   const T nan = T(FPBits::build_quiet_nan(1));
 
   static inline mpfr::RoundingMode to_mpfr_rounding_mode(int mode) {
diff --git a/libc/test/src/math/RemQuoTest.h b/libc/test/src/math/RemQuoTest.h
index 6495b61331dbb5..728db594a56cff 100644
--- a/libc/test/src/math/RemQuoTest.h
+++ b/libc/test/src/math/RemQuoTest.h
@@ -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 neg_zero = T(FPBits::zero(Sign::NEG));
   const T inf = T(FPBits::inf());
-  const T neg_inf = T(FPBits::neg_inf());
+  const T neg_inf = T(FPBits::inf(Sign::NEG));
   const T nan = T(FPBits::build_quiet_nan(1));
 
 public:
diff --git a/libc/test/src/math/RoundToIntegerTest.h b/libc/test/src/math/RoundToIntegerTest.h
index b8f1c85cb91c2e..e8ada1b4c36c50 100644
--- a/libc/test/src/math/RoundToIntegerTest.h
+++ b/libc/test/src/math/RoundToIntegerTest.h
@@ -34,9 +34,9 @@ class RoundToIntegerTestTemplate : public LIBC_NAMESPACE::testing::Test {
   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);
diff --git a/libc/test/src/math/smoke/FDimTest.h b/libc/test/src/math/smoke/FDimTest.h
index e926640abc90e0..f40dd172e58b6c 100644
--- a/libc/test/src/math/smoke/FDimTest.h
+++ b/libc/test/src/math/smoke/FDimTest.h
@@ -78,7 +78,7 @@ class FDimTestTemplate : public LIBC_NAMESPACE::testing::Test {
   // 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 neg_inf = T(FPBits::inf(Sign::NEG));
   const T zero = T(FPBits::zero());
-  const T neg_zero = T(FPBits::neg_zero());
+  const T neg_zero = T(FPBits::zero(Sign::NEG));
 };
diff --git a/libc/test/src/math/smoke/FmaTest.h b/libc/test/src/math/smoke/FmaTest.h
index 9dd8dbb534a68e..d52c220a827f5f 100644
--- a/libc/test/src/math/smoke/FmaTest.h
+++ b/libc/test/src/math/smoke/FmaTest.h
@@ -21,9 +21,9 @@ class FmaTestTemplate : public LIBC_NAMESPACE::testing::Test {
   using StorageType = typename FPBits::StorageType;
   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 neg_inf = T(FPBits::inf(Sign::NEG));
   const T zero = T(FPBits::zero());
-  const T neg_zero = T(FPBits::neg_zero());
+  const T neg_zero = T(FPBits::zero(Sign::NEG));
 
 public:
   void test_special_numbers(Func func) {
diff --git a/libc/test/src/math/smoke/HypotTest.h b/libc/test/src/math/smoke/HypotTest.h
index 30200d120ed9d8..07e774e1e00a32 100644
--- a/libc/test/src/math/smoke/HypotTest.h
+++ b/libc/test/src/math/smoke/HypotTest.h
@@ -23,9 +23,9 @@ class HypotTestTemplate : public LIBC_NAMESPACE::testing::Test {
   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();
diff --git a/libc/test/src/math/smoke/ILogbTest.h b/libc/test/src/math/smoke/ILogbTest.h
index 9f857da5547c7d..f6b56305403551 100644
--- a/libc/test/src/math/smoke/ILogbTest.h
+++ b/libc/test/src/math/smoke/ILogbTest.h
@@ -26,10 +26,10 @@ class LlvmLibcILogbTest : public LIBC_NAMESPACE::testing::Test {
   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())));
+    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>
diff --git a/libc/test/src/math/smoke/LdExpTest.h b/libc/test/src/math/smoke/LdExpTest.h
index 371654e69c3d54..9e7ecd83f7b9bb 100644
--- a/libc/test/src/math/smoke/LdExpTest.h
+++ b/libc/test/src/math/smoke/LdExpTest.h
@@ -27,9 +27,9 @@ class LdExpTestTemplate : public LIBC_NAMESPACE::testing::Test {
   static constexpr StorageType MANTISSA = NormalFloat::ONE + 0x1234;
 
   const T zero = T(FPBits::zero());
-  const T neg_zero = T(FPBits::neg_zero());
+  const T neg_zero = T(FPBits::zero(Sign::NEG));
   const T inf = T(FPBits::inf());
-  const T neg_inf = T(FPBits::neg_inf());
+  const T neg_inf = T(FPBits::inf(Sign::NEG));
   const T nan = T(FPBits::build_quiet_nan(1));
 
 public:
diff --git a/libc/test/src/math/smoke/NextAfterTest.h b/libc/test/src/math/smoke/NextAfterTest.h
index c301f5ebe228e1..66f7f587f653bf 100644
--- a/libc/test/src/math/smoke/NextAfterTest.h
+++ b/libc/test/src/math/smoke/NextAfterTest.h
@@ -34,9 +34,9 @@ class NextAfterTestTemplate : public LIBC_NAMESPACE::testing::Test {
   using StorageType = typename FPBits::StorageType;
 
   const T zero = T(FPBits::zero());
-  const T neg_zero = T(FPBits::neg_zero());
+  const T neg_zero = T(FPBits::zero(Sign::NEG));
   const T inf = T(FPBits::inf());
-  const T neg_inf = T(FPBits::neg_inf());
+  const T neg_inf = T(FPBits::inf(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;
diff --git a/libc/test/src/math/smoke/NextTowardTest.h b/libc/test/src/math/smoke/NextTowardTest.h
index 359d4dea0dbc86..1d80a67f25a5ed 100644
--- a/libc/test/src/math/smoke/NextTowardTest.h
+++ b/libc/test/src/math/smoke/NextTowardTest.h
@@ -36,13 +36,13 @@ class NextTowardTestTemplate : public LIBC_NAMESPACE::testing::Test {
   using StorageType = typename FPBits::StorageType;
 
   const T zero = T(FPBits::zero());
-  const T neg_zero = T(FPBits::neg_zero());
+  const T neg_zero = T(FPBits::zero(Sign::NEG));
   const T inf = T(FPBits::inf());
-  const T neg_inf = T(FPBits::neg_inf());
+  const T neg_inf = T(FPBits::inf(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;
diff --git a/libc/test/src/math/smoke/RIntTest.h b/libc/test/src/math/smoke/RIntTest.h
index 89dc1a59d19d64..1523f81ae87bf5 100644
--- a/libc/test/src/math/smoke/RIntTest.h
+++ b/libc/test/src/math/smoke/RIntTest.h
@@ -31,9 +31,9 @@ class RIntTestTemplate : public LIBC_NAMESPACE::testing::Test {
   using StorageType = typename FPBits::StorageType;
 
   const T zero = T(FPBits::zero());
-  const T neg_zero = T(FPBits::neg_zero());
+  const T neg_zero = T(FPBits::zero(Sign::NEG));
   const T inf = T(FPBits::inf());
-  const T neg_inf = T(FPBits::neg_inf());
+  const T neg_inf = T(FPBits::inf(Sign::NEG));
   const T nan = T(FPBits::build_quiet_nan(1));
 
 public:
diff --git a/libc/test/src/math/smoke/RemQuoTest.h b/libc/test/src/math/smoke/RemQuoTest.h
index 4d4a12717f0bb8..127c1632f80bb7 100644
--- a/libc/test/src/math/smoke/RemQuoTest.h
+++ b/libc/test/src/math/smoke/RemQuoTest.h
@@ -21,9 +21,9 @@ class RemQuoTestTemplate : public LIBC_NAMESPACE::testing::Test {
   using StorageType = typename FPBits::StorageType;
 
   const T zero = T(FPBits::zero());
-  const T neg_zero = T(FPBits::neg_zero());
+  const T neg_zero = T(FPBits::zero(Sign::NEG));
   const T inf = T(FPBits::inf());
-  const T neg_inf = T(FPBits::neg_inf());
+  const T neg_inf = T(FPBits::inf(Sign::NEG));
   const T nan = T(FPBits::build_quiet_nan(1));
 
 public:
diff --git a/libc/test/src/math/smoke/RoundToIntegerTest.h b/libc/test/src/math/smoke/RoundToIntegerTest.h
index cb1ec280518ee5..2850b06605ce8e 100644
--- a/libc/test/src/math/smoke/RoundToIntegerTest.h
+++ b/libc/test/src/math/smoke/RoundToIntegerTest.h
@@ -30,7 +30,7 @@ class RoundToIntegerTestTemplate : public LIBC_NAMESPACE::testing::Test {
   using StorageType = typename FPBits::StorageType;
 
   const F zero = F(LIBC_NAMESPACE::fputil::FPBits<F>::zero());
-  const F neg_zero = F(LIBC_NAMESPACE::fputil::FPBits<F>::neg_zero());
+  const F neg_zero = F(LIBC_NAMESPACE::fputil::FPBits<F>::zero(Sign::NEG));
   const F inf = F(LIBC_NAMESPACE::fputil::FPBits<F>::inf());
   const F neg_inf = F(LIBC_NAMESPACE::fputil::FPBits<F>::neg_inf());
   const F nan = F(LIBC_NAMESPACE::fputil::FPBits<F>::build_quiet_nan(1));

>From 05d638b98caf91d6db6e547c98d0a7a6bec18140 Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Wed, 17 Jan 2024 21:46:21 +0000
Subject: [PATCH 05/10] Fix formatting

---
 libc/src/stdio/printf_core/float_dec_converter.h | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/libc/src/stdio/printf_core/float_dec_converter.h b/libc/src/stdio/printf_core/float_dec_converter.h
index e1a44234bb309f..6171d1d5946e6a 100644
--- a/libc/src/stdio/printf_core/float_dec_converter.h
+++ b/libc/src/stdio/printf_core/float_dec_converter.h
@@ -566,8 +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, float_bits.sign());
+        round = get_round_direction(last_digit, truncated, float_bits.sign());
 
         RET_IF_RESULT_NEGATIVE(
             float_writer.write_last_block(digits, maximum, round));

>From 59cca22f8883f8e216360a1da031afbebb47a48e Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Thu, 18 Jan 2024 10:06:59 +0000
Subject: [PATCH 06/10] Fix failing tests

---
 libc/test/src/math/FDimTest.h                 | 17 +++++++----------
 libc/test/src/math/FmaTest.h                  |  8 +++++---
 libc/test/src/math/LdExpTest.h                | 13 +++++++------
 libc/test/src/math/NextAfterTest.h            |  7 ++++---
 libc/test/src/math/RIntTest.h                 |  6 +++---
 libc/test/src/math/RemQuoTest.h               |  6 +++---
 libc/test/src/math/smoke/FDimTest.h           | 16 +++++++---------
 libc/test/src/math/smoke/FmaTest.h            |  8 +++++---
 libc/test/src/math/smoke/HypotTest.h          |  6 ++++--
 libc/test/src/math/smoke/ILogbTest.h          |  5 +++--
 libc/test/src/math/smoke/LdExpTest.h          | 12 +++++++-----
 libc/test/src/math/smoke/NextAfterTest.h      |  8 +++++---
 libc/test/src/math/smoke/NextTowardTest.h     |  7 ++++---
 libc/test/src/math/smoke/RIntTest.h           |  7 ++++---
 libc/test/src/math/smoke/RemQuoTest.h         |  7 ++++---
 libc/test/src/math/smoke/RoundToIntegerTest.h |  7 ++++---
 16 files changed, 76 insertions(+), 64 deletions(-)

diff --git a/libc/test/src/math/FDimTest.h b/libc/test/src/math/FDimTest.h
index 288d966b97ee86..0744e6ea8fd8fe 100644
--- a/libc/test/src/math/FDimTest.h
+++ b/libc/test/src/math/FDimTest.h
@@ -17,8 +17,14 @@ class FDimTestTemplate : public LIBC_NAMESPACE::testing::Test {
 public:
   using FuncPtr = T (*)(T, T);
   using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
-  using Sign = LIBC_NAMESPACE::fputil::Sign;
   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));
@@ -73,13 +79,4 @@ class FDimTestTemplate : public LIBC_NAMESPACE::testing::Test {
       }
     }
   }
-
-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::inf(Sign::NEG));
-  const T zero = T(FPBits::zero());
-  const T neg_zero = T(FPBits::zero(Sign::NEG));
 };
diff --git a/libc/test/src/math/FmaTest.h b/libc/test/src/math/FmaTest.h
index c528c10401e293..032a79821d5901 100644
--- a/libc/test/src/math/FmaTest.h
+++ b/libc/test/src/math/FmaTest.h
@@ -23,11 +23,13 @@ class FmaTestTemplate : public LIBC_NAMESPACE::testing::Test {
   using Func = T (*)(T, T, T);
   using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
   using StorageType = typename FPBits::StorageType;
-  const T nan = T(FPBits::build_quiet_nan(1));
-  const T inf = T(FPBits::inf());
+  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());
+  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));
 
   StorageType get_random_bit_pattern() {
     StorageType bits{0};
diff --git a/libc/test/src/math/LdExpTest.h b/libc/test/src/math/LdExpTest.h
index fe3c492d25f851..b507bb4ec56e55 100644
--- a/libc/test/src/math/LdExpTest.h
+++ b/libc/test/src/math/LdExpTest.h
@@ -22,17 +22,18 @@ template <typename T>
 class LdExpTestTemplate : public LIBC_NAMESPACE::testing::Test {
   using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
   using NormalFloat = LIBC_NAMESPACE::fputil::NormalFloat<T>;
-  using Sign = LIBC_NAMESPACE::fputil::Sign;
   using StorageType = typename FPBits::StorageType;
-  // A normalized mantissa to be used with tests.
-  static constexpr StorageType MANTISSA = NormalFloat::ONE + 0x1234;
+  using Sign = LIBC_NAMESPACE::fputil::Sign;
 
-  const T zero = T(FPBits::zero());
-  const T neg_zero = T(FPBits::zero(Sign::NEG));
-  const T inf = T(FPBits::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));
 
+  // A normalized mantissa to be used with tests.
+  static constexpr StorageType MANTISSA = NormalFloat::ONE + 0x1234;
+
 public:
   typedef T (*LdExpFunc)(T, int);
 
diff --git a/libc/test/src/math/NextAfterTest.h b/libc/test/src/math/NextAfterTest.h
index 62f7d596827531..2dc848b3ea36a0 100644
--- a/libc/test/src/math/NextAfterTest.h
+++ b/libc/test/src/math/NextAfterTest.h
@@ -23,11 +23,12 @@ class NextAfterTestTemplate : public LIBC_NAMESPACE::testing::Test {
   using StorageType = typename FPBits::StorageType;
   using Sign = LIBC_NAMESPACE::fputil::Sign;
 
-  const T zero = T(FPBits::zero());
-  const T neg_zero = T(FPBits::zero(Sign::NEG));
-  const T inf = T(FPBits::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;
diff --git a/libc/test/src/math/RIntTest.h b/libc/test/src/math/RIntTest.h
index 3a8430dc31b35e..6816e94d389f4e 100644
--- a/libc/test/src/math/RIntTest.h
+++ b/libc/test/src/math/RIntTest.h
@@ -34,10 +34,10 @@ class RIntTestTemplate : public LIBC_NAMESPACE::testing::Test {
   using StorageType = typename FPBits::StorageType;
   using Sign = LIBC_NAMESPACE::fputil::Sign;
 
-  const T zero = T(FPBits::zero());
-  const T neg_zero = T(FPBits::zero(Sign::NEG));
-  const T inf = T(FPBits::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) {
diff --git a/libc/test/src/math/RemQuoTest.h b/libc/test/src/math/RemQuoTest.h
index 728db594a56cff..9ed95256624521 100644
--- a/libc/test/src/math/RemQuoTest.h
+++ b/libc/test/src/math/RemQuoTest.h
@@ -24,10 +24,10 @@ class RemQuoTestTemplate : public LIBC_NAMESPACE::testing::Test {
   using StorageType = typename FPBits::StorageType;
   using Sign = LIBC_NAMESPACE::fputil::Sign;
 
-  const T zero = T(FPBits::zero());
-  const T neg_zero = T(FPBits::zero(Sign::NEG));
-  const T inf = T(FPBits::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:
diff --git a/libc/test/src/math/smoke/FDimTest.h b/libc/test/src/math/smoke/FDimTest.h
index f40dd172e58b6c..0744e6ea8fd8fe 100644
--- a/libc/test/src/math/smoke/FDimTest.h
+++ b/libc/test/src/math/smoke/FDimTest.h
@@ -18,6 +18,13 @@ class FDimTestTemplate : public LIBC_NAMESPACE::testing::Test {
   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 @@ class FDimTestTemplate : public LIBC_NAMESPACE::testing::Test {
       }
     }
   }
-
-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::inf(Sign::NEG));
-  const T zero = T(FPBits::zero());
-  const T neg_zero = T(FPBits::zero(Sign::NEG));
 };
diff --git a/libc/test/src/math/smoke/FmaTest.h b/libc/test/src/math/smoke/FmaTest.h
index d52c220a827f5f..dc624d871b9901 100644
--- a/libc/test/src/math/smoke/FmaTest.h
+++ b/libc/test/src/math/smoke/FmaTest.h
@@ -19,11 +19,13 @@ class FmaTestTemplate : public LIBC_NAMESPACE::testing::Test {
   using Func = T (*)(T, T, T);
   using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
   using StorageType = typename FPBits::StorageType;
-  const T nan = T(FPBits::build_quiet_nan(1));
-  const T inf = T(FPBits::inf());
+  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());
+  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:
   void test_special_numbers(Func func) {
diff --git a/libc/test/src/math/smoke/HypotTest.h b/libc/test/src/math/smoke/HypotTest.h
index 07e774e1e00a32..77454c19a6538c 100644
--- a/libc/test/src/math/smoke/HypotTest.h
+++ b/libc/test/src/math/smoke/HypotTest.h
@@ -21,11 +21,13 @@ class HypotTestTemplate : public LIBC_NAMESPACE::testing::Test {
   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 inf = FPBits::inf(Sign::POS);
   const T neg_inf = FPBits::inf(Sign::NEG);
-  const T zero = FPBits::zero();
+  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();
diff --git a/libc/test/src/math/smoke/ILogbTest.h b/libc/test/src/math/smoke/ILogbTest.h
index f6b56305403551..0a50abc04f727f 100644
--- a/libc/test/src/math/smoke/ILogbTest.h
+++ b/libc/test/src/math/smoke/ILogbTest.h
@@ -25,10 +25,11 @@ class LlvmLibcILogbTest : public LIBC_NAMESPACE::testing::Test {
   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())));
+    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::inf(Sign::POS))));
     EXPECT_EQ(INT_MAX, func(T(FPBits::inf(Sign::NEG))));
   }
 
diff --git a/libc/test/src/math/smoke/LdExpTest.h b/libc/test/src/math/smoke/LdExpTest.h
index 9e7ecd83f7b9bb..b507bb4ec56e55 100644
--- a/libc/test/src/math/smoke/LdExpTest.h
+++ b/libc/test/src/math/smoke/LdExpTest.h
@@ -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;
-  // A normalized mantissa to be used with tests.
-  static constexpr StorageType MANTISSA = NormalFloat::ONE + 0x1234;
+  using Sign = LIBC_NAMESPACE::fputil::Sign;
 
-  const T zero = T(FPBits::zero());
-  const T neg_zero = T(FPBits::zero(Sign::NEG));
-  const T inf = T(FPBits::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));
 
+  // A normalized mantissa to be used with tests.
+  static constexpr StorageType MANTISSA = NormalFloat::ONE + 0x1234;
+
 public:
   typedef T (*LdExpFunc)(T, int);
 
diff --git a/libc/test/src/math/smoke/NextAfterTest.h b/libc/test/src/math/smoke/NextAfterTest.h
index 66f7f587f653bf..d7eb60eec4ede4 100644
--- a/libc/test/src/math/smoke/NextAfterTest.h
+++ b/libc/test/src/math/smoke/NextAfterTest.h
@@ -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::zero(Sign::NEG));
-  const T inf = T(FPBits::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;
diff --git a/libc/test/src/math/smoke/NextTowardTest.h b/libc/test/src/math/smoke/NextTowardTest.h
index 1d80a67f25a5ed..af4e0ab14531c1 100644
--- a/libc/test/src/math/smoke/NextTowardTest.h
+++ b/libc/test/src/math/smoke/NextTowardTest.h
@@ -34,11 +34,12 @@ 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::zero(Sign::NEG));
-  const T inf = T(FPBits::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();
diff --git a/libc/test/src/math/smoke/RIntTest.h b/libc/test/src/math/smoke/RIntTest.h
index 1523f81ae87bf5..b242c7e441b69f 100644
--- a/libc/test/src/math/smoke/RIntTest.h
+++ b/libc/test/src/math/smoke/RIntTest.h
@@ -29,11 +29,12 @@ class RIntTestTemplate : public LIBC_NAMESPACE::testing::Test {
 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::zero(Sign::NEG));
-  const T inf = T(FPBits::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:
diff --git a/libc/test/src/math/smoke/RemQuoTest.h b/libc/test/src/math/smoke/RemQuoTest.h
index 127c1632f80bb7..93e20747e52638 100644
--- a/libc/test/src/math/smoke/RemQuoTest.h
+++ b/libc/test/src/math/smoke/RemQuoTest.h
@@ -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::zero(Sign::NEG));
-  const T inf = T(FPBits::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:
diff --git a/libc/test/src/math/smoke/RoundToIntegerTest.h b/libc/test/src/math/smoke/RoundToIntegerTest.h
index 2850b06605ce8e..2703b78f00e0f1 100644
--- a/libc/test/src/math/smoke/RoundToIntegerTest.h
+++ b/libc/test/src/math/smoke/RoundToIntegerTest.h
@@ -28,11 +28,12 @@ class RoundToIntegerTestTemplate : public LIBC_NAMESPACE::testing::Test {
 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 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());
-  const F neg_inf = F(LIBC_NAMESPACE::fputil::FPBits<F>::neg_inf());
+  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);

>From 36e386f2f07f7b1b3f6f5d3f7cf00264714bfa54 Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Thu, 18 Jan 2024 10:30:06 +0000
Subject: [PATCH 07/10] Force creation of Sign through Sign::NEG / Sign::POS

---
 libc/src/__support/FPUtil/BasicOperations.h                | 2 +-
 libc/src/__support/FPUtil/DivisionAndRemainderOperations.h | 6 +++---
 libc/src/__support/FPUtil/FPBits.h                         | 6 +++---
 libc/src/__support/FPUtil/NormalFloat.h                    | 2 +-
 libc/src/__support/FPUtil/dyadic_float.h                   | 2 +-
 libc/src/__support/FPUtil/generic/FMA.h                    | 2 +-
 libc/src/math/generic/powf.cpp                             | 4 ++--
 7 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/libc/src/__support/FPUtil/BasicOperations.h b/libc/src/__support/FPUtil/BasicOperations.h
index 4015edb1b65372..ea78809dfc7f7d 100644
--- a/libc/src/__support/FPUtil/BasicOperations.h
+++ b/libc/src/__support/FPUtil/BasicOperations.h
@@ -36,7 +36,7 @@ LIBC_INLINE T fmin(T x, T y) {
     // 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.is_neg()) ? x : y);
+    return (bitx.is_neg()) ? x : y;
   } else {
     return (x < y ? x : y);
   }
diff --git a/libc/src/__support/FPUtil/DivisionAndRemainderOperations.h b/libc/src/__support/FPUtil/DivisionAndRemainderOperations.h
index d3401b10a7cab8..71dbc2cc879783 100644
--- a/libc/src/__support/FPUtil/DivisionAndRemainderOperations.h
+++ b/libc/src/__support/FPUtil/DivisionAndRemainderOperations.h
@@ -43,7 +43,7 @@ LIBC_INLINE T remquo(T x, T y, int &q) {
     return x;
   }
 
-  bool result_sign = (xbits.is_neg() == ybits.is_neg() ? 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
@@ -72,7 +72,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 +107,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;
diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h
index 990b88d18efeef..3ee6289b749648 100644
--- a/libc/src/__support/FPUtil/FPBits.h
+++ b/libc/src/__support/FPUtil/FPBits.h
@@ -34,9 +34,6 @@ enum class FPType {
 // A type to interact with floating point type signs.
 // This may be moved outside of 'fputil' if useful.
 struct Sign {
-  LIBC_INLINE constexpr explicit Sign(bool is_negative)
-      : is_negative(is_negative) {}
-
   LIBC_INLINE constexpr bool is_pos() const { return !is_negative; }
   LIBC_INLINE constexpr bool is_neg() const { return is_negative; }
 
@@ -51,6 +48,9 @@ struct Sign {
   static const Sign NEG;
 
 private:
+  LIBC_INLINE constexpr explicit Sign(bool is_negative)
+      : is_negative(is_negative) {}
+
   bool is_negative;
 };
 
diff --git a/libc/src/__support/FPUtil/NormalFloat.h b/libc/src/__support/FPUtil/NormalFloat.h
index 39376bfcba0319..8b1612e1b47c61 100644
--- a/libc/src/__support/FPUtil/NormalFloat.h
+++ b/libc/src/__support/FPUtil/NormalFloat.h
@@ -47,7 +47,7 @@ template <typename T> struct NormalFloat {
   Sign sign = Sign::POS;
 
   LIBC_INLINE NormalFloat(int32_t e, StorageType m, bool s)
-      : exponent(e), mantissa(m), sign(Sign(s)) {
+      : exponent(e), mantissa(m), sign(s ? Sign::NEG : Sign::POS) {
     if (mantissa >= ONE)
       return;
 
diff --git a/libc/src/__support/FPUtil/dyadic_float.h b/libc/src/__support/FPUtil/dyadic_float.h
index 3cc3890b65a01b..439741d2c497c0 100644
--- a/libc/src/__support/FPUtil/dyadic_float.h
+++ b/libc/src/__support/FPUtil/dyadic_float.h
@@ -50,7 +50,7 @@ template <size_t Bits> struct DyadicFloat {
   }
 
   constexpr DyadicFloat(bool s, int e, MantissaType m)
-      : sign(Sign(s)), exponent(e), mantissa(m) {
+      : sign(s ? Sign::NEG : Sign::POS), exponent(e), mantissa(m) {
     normalize();
   }
 
diff --git a/libc/src/__support/FPUtil/generic/FMA.h b/libc/src/__support/FPUtil/generic/FMA.h
index 2aaf6ce369a37a..9c67c645d5243d 100644
--- a/libc/src/__support/FPUtil/generic/FMA.h
+++ b/libc/src/__support/FPUtil/generic/FMA.h
@@ -119,7 +119,7 @@ template <> LIBC_INLINE double fma<double>(double x, double y, double z) {
 
   FPBits x_bits(x), y_bits(y), z_bits(z);
   const Sign z_sign = z_bits.sign();
-  Sign prod_sign = Sign(x_bits.sign() != y_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();
diff --git a/libc/src/math/generic/powf.cpp b/libc/src/math/generic/powf.cpp
index f1be147298a410..932f1d70c33e8e 100644
--- a/libc/src/math/generic/powf.cpp
+++ b/libc/src/math/generic/powf.cpp
@@ -617,7 +617,7 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) {
         // pow(0, negative number) = inf
         fputil::set_errno_if_required(EDOM);
         fputil::raise_except_if_required(FE_DIVBYZERO);
-        return FloatBits::inf(Sign(out_is_neg));
+        return FloatBits::inf(out_is_neg ? Sign::NEG : Sign::POS);
       }
       // pow(0, positive number) = 0
       return out_is_neg ? -0.0f : 0.0f;
@@ -628,7 +628,7 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) {
       if (y_u >= FloatBits::SIGN_MASK) {
         return out_is_neg ? -0.0f : 0.0f;
       }
-      return FloatBits::inf(Sign(out_is_neg));
+      return FloatBits::inf(out_is_neg ? Sign::NEG : Sign::POS);
     }
     }
 

>From a8f74e27d6c832e551d4d7179a09f148063c2d5c Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Thu, 18 Jan 2024 10:32:30 +0000
Subject: [PATCH 08/10] Use Sign instead of bool in fpbits_str.h

---
 libc/src/__support/FPUtil/fpbits_str.h | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/libc/src/__support/FPUtil/fpbits_str.h b/libc/src/__support/FPUtil/fpbits_str.h
index b48def8b1cdcf4..a1654cddad7464 100644
--- a/libc/src/__support/FPUtil/fpbits_str.h
+++ b/libc/src/__support/FPUtil/fpbits_str.h
@@ -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.is_neg() ? "(-Infinity)" : "(+Infinity)";
 
-  const auto sign_char = [](bool is_neg) -> char { return is_neg ? '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.is_neg());
+  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: ";

>From a2e782df42ff3b548985f8fbfc24686fa8cb4155 Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Thu, 18 Jan 2024 10:35:19 +0000
Subject: [PATCH 09/10] Add comment about leaking abstraction.

---
 libc/src/math/generic/expm1.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libc/src/math/generic/expm1.cpp b/libc/src/math/generic/expm1.cpp
index 3d343a99d1c288..71c4663edd21a8 100644
--- a/libc/src/math/generic/expm1.cpp
+++ b/libc/src/math/generic/expm1.cpp
@@ -438,6 +438,8 @@ LLVM_LIBC_FUNCTION(double, expm1, (double x)) {
 
   double lo = fputil::multiply_add(p, mid_lo, hi_part.lo);
 
+  // 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);

>From afe74f31a3250fcd63b3ffed324d5a5f38c01b13 Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Thu, 18 Jan 2024 10:42:56 +0000
Subject: [PATCH 10/10] Fix formatting

---
 libc/src/__support/FPUtil/DivisionAndRemainderOperations.h | 3 ++-
 libc/test/src/math/NextAfterTest.h                         | 2 +-
 libc/test/src/math/smoke/NextAfterTest.h                   | 2 +-
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/libc/src/__support/FPUtil/DivisionAndRemainderOperations.h b/libc/src/__support/FPUtil/DivisionAndRemainderOperations.h
index 71dbc2cc879783..1c09e7906165f5 100644
--- a/libc/src/__support/FPUtil/DivisionAndRemainderOperations.h
+++ b/libc/src/__support/FPUtil/DivisionAndRemainderOperations.h
@@ -43,7 +43,8 @@ LIBC_INLINE T remquo(T x, T y, int &q) {
     return x;
   }
 
-  const Sign result_sign = (xbits.sign() == ybits.sign() ? Sign::POS : Sign::NEG);
+  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
diff --git a/libc/test/src/math/NextAfterTest.h b/libc/test/src/math/NextAfterTest.h
index 2dc848b3ea36a0..aa9646fd921f81 100644
--- a/libc/test/src/math/NextAfterTest.h
+++ b/libc/test/src/math/NextAfterTest.h
@@ -28,7 +28,7 @@ class NextAfterTestTemplate : public LIBC_NAMESPACE::testing::Test {
   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;
diff --git a/libc/test/src/math/smoke/NextAfterTest.h b/libc/test/src/math/smoke/NextAfterTest.h
index d7eb60eec4ede4..bdf3da627180aa 100644
--- a/libc/test/src/math/smoke/NextAfterTest.h
+++ b/libc/test/src/math/smoke/NextAfterTest.h
@@ -39,7 +39,7 @@ class NextAfterTestTemplate : public LIBC_NAMESPACE::testing::Test {
   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;



More information about the libc-commits mailing list