[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