diff --git a/libc/src/__support/str_to_float.h b/libc/src/__support/str_to_float.h --- a/libc/src/__support/str_to_float.h +++ b/libc/src/__support/str_to_float.h @@ -546,6 +546,35 @@ return true; } +// The upper bound is the highest base-10 exponent that could possibly give a +// non-inf result for this size of float. The value is +// log_10(2^(exponent bias)). +// The generic approximation uses the fact that log_10(2^x) ~= x/3 +template constexpr int64_t get_upper_bound() { + return static_cast(fputil::FloatProperties::EXPONENT_BIAS) / 3; +} + +template <> constexpr int64_t get_upper_bound() { return 39; } + +template <> constexpr int64_t get_upper_bound() { return 309; } + +// The lower bound is the largest negative base-10 exponent that could possibly +// give a non-zero result for this size of float. The value is +// log_10(2^(exponent bias + mantissa width + intermediate mantissa width)) +// The generic approximation uses the fact that log_10(2^x) ~= x/3 +template constexpr int64_t get_lower_bound() { + return static_cast(fputil::FloatProperties::EXPONENT_BIAS + + fputil::FloatProperties::MANTISSA_WIDTH + + (sizeof(T) * 8)) / + 3; +} + +template <> constexpr int64_t get_lower_bound() { return 39 + 6 + 10; } + +template <> constexpr int64_t get_lower_bound() { + return 309 + 15 + 20; +} + // Takes a mantissa and base 10 exponent and converts it into its closest // floating point type T equivalient. First we try the Eisel-Lemire algorithm, // then if that fails then we fall back to a more accurate algorithm for @@ -561,19 +590,14 @@ // If the exponent is too large and can't be represented in this size of // float, return inf. These bounds are very loose, but are mostly serving as a // first pass. Some close numbers getting through is okay. - if (exp10 > - static_cast(fputil::FloatProperties::EXPONENT_BIAS) / 3) { + if (exp10 > get_upper_bound()) { *outputMantissa = 0; *outputExp2 = fputil::FPBits::MAX_EXPONENT; errno = ERANGE; return; } // If the exponent is too small even for a subnormal, return 0. - if (exp10 < 0 && - -static_cast(exp10) > - static_cast(fputil::FloatProperties::EXPONENT_BIAS + - fputil::FloatProperties::MANTISSA_WIDTH) / - 2) { + if (exp10 < 0 && -static_cast(exp10) > get_lower_bound()) { *outputMantissa = 0; *outputExp2 = 0; errno = ERANGE; @@ -934,8 +958,8 @@ } char *new_str_end = nullptr; - BitsType output_mantissa = 0; - uint32_t output_exponent = 0; + BitsType output_mantissa = ~0; + uint32_t output_exponent = ~0; if (base == 16) { seen_digit = hexadecimal_string_to_float( src, DECIMAL_POINT, &new_str_end, &output_mantissa, &output_exponent);