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) <noreply@anthropic.com>
This commit is contained in:
Raúl Marín 2026-09-23 21:17:27 +02:00
parent 0900eedf2f
commit ef5797fa94
2 changed files with 16 additions and 2 deletions

View File

@ -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 <typename binary>
// known_in_range: the caller knows that q is within the range of powers of
// ten, so only w == 0 is checked.
template <typename binary, bool known_in_range = false>
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;

View File

@ -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<T>::min_exponent_fast_path() <= pns.exponent &&
pns.exponent <= binary_format<T>::max_exponent_fast_path())
? compute_float<binary_format<T>, true>(pns.exponent, pns.mantissa)
: compute_float<binary_format<T>>(pns.exponent, pns.mantissa);
#else
adjusted_mantissa am =
compute_float<binary_format<T>>(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