Gate the subnormal tie test on a compile-time predicate

This commit is contained in:
jadidbourbaki 2026-09-15 09:11:27 -04:00
parent abb4c8659a
commit 20a9b35333
3 changed files with 23 additions and 3 deletions

View File

@ -163,7 +163,8 @@ compute_float(int64_t q, uint64_t w) noexcept {
// std::float16_t (e.g., 2^-25 = 298023223876953125e-25), so we apply the
// same round-to-even test as in the normal case below.
// See script/format_parameters.py.
if ((product.low <= 1) && (q >= binary::min_exponent_round_to_even()) &&
if (binary::subnormal_ties_possible() && (product.low <= 1) &&
(q >= binary::min_exponent_round_to_even()) &&
(q <= binary::max_exponent_round_to_even()) &&
((answer.mantissa & 3) == 1)) {
if (((answer.mantissa << subnormal_shift) << shift) == product.high) {

View File

@ -225,12 +225,16 @@ using parse_options = parse_options_t<char>;
#ifndef FASTFLOAT_ASSERT
#define FASTFLOAT_ASSERT(x) \
{ static_cast<void>(x); }
{ \
static_cast<void>(x); \
}
#endif
#ifndef FASTFLOAT_DEBUG_ASSERT
#define FASTFLOAT_DEBUG_ASSERT(x) \
{ static_cast<void>(x); }
{ \
static_cast<void>(x); \
}
#endif
// rust style `try!()` macro, or `?` operator
@ -662,6 +666,7 @@ template <typename T> struct binary_format : binary_format_lookup_tables<T> {
static constexpr uint64_t
max_mantissa_fast_path(); // used when fegetround() == FE_TONEAREST
static constexpr bool fast_path_can_overflow();
static constexpr bool subnormal_ties_possible();
static constexpr int largest_power_of_ten();
static constexpr int smallest_power_of_ten();
static constexpr T exact_power_of_ten(int64_t power);
@ -1110,6 +1115,15 @@ inline constexpr bool binary_format<T>::fast_path_can_overflow() {
double((std::numeric_limits<T>::max)());
}
// A subnormal needs w * 10^q < 2^(minimum_exponent() + 1), so q is at most
// (minimum_exponent() + 1) * log10(2), with 1233/4096 < log10(2). Only
// std::float16_t has such q in its round-to-even range.
template <typename T>
inline constexpr bool binary_format<T>::subnormal_ties_possible() {
return min_exponent_round_to_even() <=
(((minimum_exponent() + 1) * 1233) >> 12);
}
template <>
inline constexpr uint64_t
binary_format<double>::max_mantissa_fast_path(int64_t power) {

View File

@ -310,6 +310,11 @@ def check_ties(fmt):
check(lo <= min(sub), "and the subnormal ties at q in [%d, %d]" % (min(sub), max(sub)))
else:
note("no subnormal tie has fewer than 20 digits")
# subnormal_ties_possible() in float_common.h: an upper bound on the
# largest q that can give a subnormal, compared with the tie range
q_sub = ((fmt.minimum_exponent + 1) * 1233) >> 12
check(10**q_sub < 2**fmt.emin < 10 ** (q_sub + 2), "q <= %d bounds the subnormal exponents" % q_sub)
check((lo <= q_sub) == bool(sub), "subnormal_ties_possible() == %s" % bool(sub))
longest = len(str(((1 << (p + 2)) - 1) * 5**fmt.bias))
check(fmt.max_digits >= longest, "max_digits=%d >= %d, the longest tie" % (fmt.max_digits, longest))