From ef5797fa94d882ce1975c143cd7d3aaa418ce393 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Mar=C3=ADn?= Date: Wed, 23 Sep 2026 21:17:27 +0200 Subject: [PATCH] Skip the range check in compute_float after Clinger's range test under clang If the exponent passed that test, the mantissa failed it, so it is not zero and the exponent is within range. GCC carries this into compute_float by itself. Co-Authored-By: Claude Opus 5.5 (1M context) --- include/fast_float/decimal_to_binary.h | 6 ++++-- include/fast_float/parse_number.h | 12 ++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index b9b96f4..a7ee289 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -98,7 +98,9 @@ compute_error(int64_t q, uint64_t w) noexcept { // packed. However, in some very rare cases, the computation will fail. In such // cases, we return an adjusted_mantissa with a negative power of 2: the caller // should recompute in such cases. -template +// known_in_range: the caller knows that q is within the range of powers of +// ten, so only w == 0 is checked. +template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa compute_float(int64_t q, uint64_t w) noexcept { adjusted_mantissa answer; @@ -107,7 +109,7 @@ compute_float(int64_t q, uint64_t w) noexcept { bool const q_out_of_range = uint64_t(q - binary::smallest_power_of_ten()) > uint64_t(binary::largest_power_of_ten() - binary::smallest_power_of_ten()); - if ((w == 0) || q_out_of_range) { + if ((w == 0) || (!known_in_range && q_out_of_range)) { bool const underflow = (w == 0) | (q < binary::smallest_power_of_ten()); answer.power2 = int32_t(!underflow) * binary::infinite_power(); answer.mantissa = 0; diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index d3856cb..0db46ec 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -445,8 +445,20 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value, return answer; } +#ifdef __clang__ + // If the exponent passed Clinger's range test, it is well within range. GCC + // carries this into compute_float by itself; clang needs the instantiation + // without the range check. The mantissa can still be zero when the rounding + // mode is not to nearest. + adjusted_mantissa am = + (binary_format::min_exponent_fast_path() <= pns.exponent && + pns.exponent <= binary_format::max_exponent_fast_path()) + ? compute_float, true>(pns.exponent, pns.mantissa) + : compute_float>(pns.exponent, pns.mantissa); +#else adjusted_mantissa am = compute_float>(pns.exponent, pns.mantissa); +#endif // Slow path B (rare): Eisel-Lemire could not resolve; digit_comp needs the // integer/fraction spans. Route to the cold helper (clinger there is a // dead-effect since it already failed here; the cold re-parse + digit_comp