[libc-commits] [libc] 455d678 - [libc] Add get_explicit_exponent to fpbits

Michael Jones via libc-commits libc-commits at lists.llvm.org
Tue Aug 15 16:23:28 PDT 2023


Author: Michael Jones
Date: 2023-08-15T16:23:02-07:00
New Revision: 455d678019d8a713f04f33ca27573f0676df05f6

URL: https://github.com/llvm/llvm-project/commit/455d678019d8a713f04f33ca27573f0676df05f6
DIFF: https://github.com/llvm/llvm-project/commit/455d678019d8a713f04f33ca27573f0676df05f6.diff

LOG: [libc] Add get_explicit_exponent to fpbits

In the same way that get_explicit_mantissa is used to get the mantissa
with all the implicit bits spelled out, get_explicit_exponent gives you
the exponent with the special cases handled. Mainly it handles the cases
where the exponent is zero, which causes the exponent to either be 1
higher than expected, or just 0.

Reviewed By: lntue

Differential Revision: https://reviews.llvm.org/D157156

Added: 
    

Modified: 
    libc/src/__support/FPUtil/FPBits.h
    libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h
    libc/src/__support/FPUtil/x86_64/LongDoubleBits.h
    libc/src/__support/float_to_string.h
    libc/src/stdio/printf_core/float_dec_converter.h
    libc/src/stdio/printf_core/float_hex_converter.h

Removed: 
    


################################################################################
diff  --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h
index 49285527305ab8..326211669dce66 100644
--- a/libc/src/__support/FPUtil/FPBits.h
+++ b/libc/src/__support/FPUtil/FPBits.h
@@ -128,6 +128,23 @@ template <typename T> struct FPBits {
     return int(get_unbiased_exponent()) - EXPONENT_BIAS;
   }
 
+  // If the number is subnormal, the exponent is treated as if it were the
+  // minimum exponent for a normal number. This is to keep continuity between
+  // the normal and subnormal ranges, but it causes problems for functions where
+  // values are calculated from the exponent, since just subtracting the bias
+  // will give a slightly incorrect result. Additionally, zero has an exponent
+  // of zero, and that should actually be treated as zero.
+  LIBC_INLINE int get_explicit_exponent() const {
+    const int unbiased_exp = int(get_unbiased_exponent());
+    if (is_zero()) {
+      return 0;
+    } else if (unbiased_exp == 0) {
+      return 1 - EXPONENT_BIAS;
+    } else {
+      return unbiased_exp - EXPONENT_BIAS;
+    }
+  }
+
   LIBC_INLINE bool is_zero() const {
     // Remove sign bit by shift
     return (bits << 1) == 0;

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 3ae79c2dd6cac7..a8e818dce990b2 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
@@ -60,7 +60,7 @@ LIBC_INLINE long double sqrt(long double x) {
     // sqrt( negative numbers ) = NaN
     return FPBits<long double>::build_quiet_nan(ONE >> 1);
   } else {
-    int x_exp = bits.get_exponent();
+    int x_exp = bits.get_explicit_exponent();
     UIntType x_mant = bits.get_mantissa();
 
     // Step 1a: Normalize denormal input

diff  --git a/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h b/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h
index bb03eea38be82f..c8dc6e99177d19 100644
--- a/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h
+++ b/libc/src/__support/FPUtil/x86_64/LongDoubleBits.h
@@ -135,11 +135,26 @@ template <> struct FPBits<long double> {
   }
 
   LIBC_INLINE int get_exponent() const {
-    if (get_unbiased_exponent() == 0)
-      return int(1) - EXPONENT_BIAS;
     return int(get_unbiased_exponent()) - EXPONENT_BIAS;
   }
 
+  // If the number is subnormal, the exponent is treated as if it were the
+  // minimum exponent for a normal number. This is to keep continuity between
+  // the normal and subnormal ranges, but it causes problems for functions where
+  // values are calculated from the exponent, since just subtracting the bias
+  // will give a slightly incorrect result. Additionally, zero has an exponent
+  // of zero, and that should actually be treated as zero.
+  LIBC_INLINE int get_explicit_exponent() const {
+    const int unbiased_exp = int(get_unbiased_exponent());
+    if (is_zero()) {
+      return 0;
+    } else if (unbiased_exp == 0) {
+      return 1 - EXPONENT_BIAS;
+    } else {
+      return unbiased_exp - EXPONENT_BIAS;
+    }
+  }
+
   LIBC_INLINE bool is_zero() const {
     return get_unbiased_exponent() == 0 && get_mantissa() == 0 &&
            get_implicit_bit() == 0;

diff  --git a/libc/src/__support/float_to_string.h b/libc/src/__support/float_to_string.h
index 404303a7edc057..4714068eadf0e5 100644
--- a/libc/src/__support/float_to_string.h
+++ b/libc/src/__support/float_to_string.h
@@ -423,18 +423,9 @@ class FloatToString {
 public:
   LIBC_INLINE constexpr FloatToString(T init_float) : float_bits(init_float) {
     is_negative = float_bits.get_sign();
-    exponent = float_bits.get_exponent();
+    exponent = float_bits.get_explicit_exponent();
     mantissa = float_bits.get_explicit_mantissa();
 
-    // Handle the exponent for numbers with a 0 exponent.
-    if (exponent == -EXP_BIAS) {
-      if (mantissa > 0) { // Subnormals
-        ++exponent;
-      } else { // Zeroes
-        exponent = 0;
-      }
-    }
-
     // Adjust for the width of the mantissa.
     exponent -= MANT_WIDTH;
 

diff  --git a/libc/src/stdio/printf_core/float_dec_converter.h b/libc/src/stdio/printf_core/float_dec_converter.h
index 7927220da3fff8..c81b59edcfa502 100644
--- a/libc/src/stdio/printf_core/float_dec_converter.h
+++ b/libc/src/stdio/printf_core/float_dec_converter.h
@@ -483,7 +483,7 @@ LIBC_INLINE int convert_float_decimal_typed(Writer *writer,
   // signed because later we use -MANT_WIDTH
   constexpr int32_t MANT_WIDTH = fputil::MantissaWidth<T>::VALUE;
   bool is_negative = float_bits.get_sign();
-  int exponent = float_bits.get_exponent();
+  int exponent = float_bits.get_explicit_exponent();
 
   char sign_char = 0;
 
@@ -626,7 +626,7 @@ LIBC_INLINE int convert_float_dec_exp_typed(Writer *writer,
   // signed because later we use -MANT_WIDTH
   constexpr int32_t MANT_WIDTH = fputil::MantissaWidth<T>::VALUE;
   bool is_negative = float_bits.get_sign();
-  int exponent = float_bits.get_exponent();
+  int exponent = float_bits.get_explicit_exponent();
   MantissaInt mantissa = float_bits.get_explicit_mantissa();
 
   const char a = (to_conv.conv_name & 32) | 'A';
@@ -787,7 +787,7 @@ LIBC_INLINE int convert_float_dec_auto_typed(Writer *writer,
   // signed because later we use -MANT_WIDTH
   constexpr int32_t MANT_WIDTH = fputil::MantissaWidth<T>::VALUE;
   bool is_negative = float_bits.get_sign();
-  int exponent = float_bits.get_exponent();
+  int exponent = float_bits.get_explicit_exponent();
   MantissaInt mantissa = float_bits.get_explicit_mantissa();
 
   // From the standard: Let P (init_precision) equal the precision if nonzero, 6

diff  --git a/libc/src/stdio/printf_core/float_hex_converter.h b/libc/src/stdio/printf_core/float_hex_converter.h
index 6f350ce8d6765d..c19179884948dc 100644
--- a/libc/src/stdio/printf_core/float_hex_converter.h
+++ b/libc/src/stdio/printf_core/float_hex_converter.h
@@ -39,24 +39,21 @@ LIBC_INLINE int convert_float_hex_exp(Writer *writer,
   MantissaInt mantissa;
   bool is_inf_or_nan;
   uint32_t mantissa_width;
-  int exponent_bias;
   if (to_conv.length_modifier == LengthModifier::L) {
     mantissa_width = fputil::MantissaWidth<long double>::VALUE;
-    exponent_bias = fputil::FPBits<long double>::EXPONENT_BIAS;
     fputil::FPBits<long double>::UIntType float_raw = to_conv.conv_val_raw;
     fputil::FPBits<long double> float_bits(float_raw);
     is_negative = float_bits.get_sign();
-    exponent = float_bits.get_exponent();
+    exponent = float_bits.get_explicit_exponent();
     mantissa = float_bits.get_explicit_mantissa();
     is_inf_or_nan = float_bits.is_inf_or_nan();
   } else {
     mantissa_width = fputil::MantissaWidth<double>::VALUE;
-    exponent_bias = fputil::FPBits<double>::EXPONENT_BIAS;
     fputil::FPBits<double>::UIntType float_raw =
         static_cast<fputil::FPBits<double>::UIntType>(to_conv.conv_val_raw);
     fputil::FPBits<double> float_bits(float_raw);
     is_negative = float_bits.get_sign();
-    exponent = float_bits.get_exponent();
+    exponent = float_bits.get_explicit_exponent();
     mantissa = float_bits.get_explicit_mantissa();
     is_inf_or_nan = float_bits.is_inf_or_nan();
   }
@@ -74,14 +71,6 @@ LIBC_INLINE int convert_float_hex_exp(Writer *writer,
            FormatFlags::SPACE_PREFIX)
     sign_char = ' ';
 
-  // Handle the exponent for numbers with a 0 exponent
-  if (exponent == -exponent_bias) {
-    if (mantissa > 0) // Subnormals
-      ++exponent;
-    else // Zeroes
-      exponent = 0;
-  }
-
   constexpr size_t BITS_IN_HEX_DIGIT = 4;
 
   // This is to handle situations where the mantissa isn't an even number of hex


        


More information about the libc-commits mailing list