Skip to content

Commit

Permalink
[libc] Add get_explicit_exponent to fpbits
Browse files Browse the repository at this point in the history
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
  • Loading branch information
michaelrj-google committed Aug 15, 2023
1 parent 95ab1cd commit 455d678
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 29 deletions.
17 changes: 17 additions & 0 deletions libc/src/__support/FPUtil/FPBits.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
19 changes: 17 additions & 2 deletions libc/src/__support/FPUtil/x86_64/LongDoubleBits.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
11 changes: 1 addition & 10 deletions libc/src/__support/float_to_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
6 changes: 3 additions & 3 deletions libc/src/stdio/printf_core/float_dec_converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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';
Expand Down Expand Up @@ -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
Expand Down
15 changes: 2 additions & 13 deletions libc/src/stdio/printf_core/float_hex_converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand All @@ -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
Expand Down

0 comments on commit 455d678

Please sign in to comment.