We might reenable clinger.

This commit is contained in:
Daniel Lemire 2022-11-16 16:21:34 +00:00
parent dac641ee13
commit 6ceb29a7e4
2 changed files with 52 additions and 7 deletions

View File

@ -272,10 +272,12 @@ template <typename T> struct binary_format {
static inline constexpr int minimum_exponent(); static inline constexpr int minimum_exponent();
static inline constexpr int infinite_power(); static inline constexpr int infinite_power();
static inline constexpr int sign_index(); static inline constexpr int sign_index();
static inline constexpr int min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST
static inline constexpr int max_exponent_fast_path(); static inline constexpr int max_exponent_fast_path();
static inline constexpr int max_exponent_round_to_even(); static inline constexpr int max_exponent_round_to_even();
static inline constexpr int min_exponent_round_to_even(); static inline constexpr int min_exponent_round_to_even();
static inline constexpr uint64_t max_mantissa_fast_path(int64_t power); static inline constexpr uint64_t max_mantissa_fast_path(int64_t power);
static inline constexpr uint64_t max_mantissa_fast_path(); // used when fegetround() == FE_TONEAREST
static inline constexpr int largest_power_of_ten(); static inline constexpr int largest_power_of_ten();
static inline constexpr int smallest_power_of_ten(); static inline constexpr int smallest_power_of_ten();
static inline constexpr T exact_power_of_ten(int64_t power); static inline constexpr T exact_power_of_ten(int64_t power);
@ -285,6 +287,22 @@ template <typename T> struct binary_format {
static inline constexpr equiv_uint hidden_bit_mask(); static inline constexpr equiv_uint hidden_bit_mask();
}; };
template <> inline constexpr int binary_format<double>::min_exponent_fast_path() {
#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
return 0;
#else
return -22;
#endif
}
template <> inline constexpr int binary_format<float>::min_exponent_fast_path() {
#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
return 0;
#else
return -10;
#endif
}
template <> inline constexpr int binary_format<double>::mantissa_explicit_bits() { template <> inline constexpr int binary_format<double>::mantissa_explicit_bits() {
return 52; return 52;
} }
@ -331,13 +349,18 @@ template <> inline constexpr int binary_format<double>::max_exponent_fast_path()
template <> inline constexpr int binary_format<float>::max_exponent_fast_path() { template <> inline constexpr int binary_format<float>::max_exponent_fast_path() {
return 10; return 10;
} }
template <> inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path() {
return uint64_t(2) << mantissa_explicit_bits();
}
template <> inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path(int64_t power) { template <> inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path(int64_t power) {
// caller is responsible to ensure that // caller is responsible to ensure that
// power >= 0 && power <= 22 // power >= 0 && power <= 22
// //
return max_mantissa_double[power]; return max_mantissa_double[power];
} }
template <> inline constexpr uint64_t binary_format<float>::max_mantissa_fast_path() {
return uint64_t(2) << mantissa_explicit_bits();
}
template <> inline constexpr uint64_t binary_format<float>::max_mantissa_fast_path(int64_t power) { template <> inline constexpr uint64_t binary_format<float>::max_mantissa_fast_path(int64_t power) {
// caller is responsible to ensure that // caller is responsible to ensure that
// power >= 0 && power <= 10 // power >= 0 && power <= 10

View File

@ -60,6 +60,15 @@ from_chars_result parse_infnan(const char *first, const char *last, T &value) n
return answer; return answer;
} }
fastfloat_really_inline bool rounds_nearest() {
// This function is meant to be equivalent to :
// prior: #include <cfenv>
// return fegetround() == FE_TONEAREST;
// volatile prevents the compiler from computing the function at compile-time
static volatile float fmin = std::numeric_limits<float>::min();
return (fmin + 1.0f == 1.0f - fmin);
}
} // namespace detail } // namespace detail
template<typename T> template<typename T>
@ -87,12 +96,25 @@ from_chars_result from_chars_advanced(const char *first, const char *last,
} }
answer.ec = std::errc(); // be optimistic answer.ec = std::errc(); // be optimistic
answer.ptr = pns.lastmatch; answer.ptr = pns.lastmatch;
// Next is a modified Clinger's fast path, inspired by Jakub Jelínek's proposal if(detail::rounds_nearest()) {
if (pns.exponent >= 0 && pns.exponent <= binary_format<T>::max_exponent_fast_path() && pns.mantissa <=binary_format<T>::max_mantissa_fast_path(pns.exponent) && !pns.too_many_digits) { // We have that fegetround() == FE_TONEAREST.
value = T(pns.mantissa); // Next is Clinger's fast path.
value = value * binary_format<T>::exact_power_of_ten(pns.exponent); if (binary_format<T>::min_exponent_fast_path() <= pns.exponent && pns.exponent <= binary_format<T>::max_exponent_fast_path() && pns.mantissa <=binary_format<T>::max_mantissa_fast_path() && !pns.too_many_digits) {
if (pns.negative) { value = -value; } value = T(pns.mantissa);
return answer; if (pns.exponent < 0) { value = value / binary_format<T>::exact_power_of_ten(-pns.exponent); }
else { value = value * binary_format<T>::exact_power_of_ten(pns.exponent); }
if (pns.negative) { value = -value; }
return answer;
}
} else {
// We do not have that fegetround() == FE_TONEAREST.
// Next is a modified Clinger's fast path, inspired by Jakub Jelínek's proposal
if (pns.exponent >= 0 && pns.exponent <= binary_format<T>::max_exponent_fast_path() && pns.mantissa <=binary_format<T>::max_mantissa_fast_path(pns.exponent) && !pns.too_many_digits) {
value = T(pns.mantissa);
value = value * binary_format<T>::exact_power_of_ten(pns.exponent);
if (pns.negative) { value = -value; }
return answer;
}
} }
adjusted_mantissa am = compute_float<binary_format<T>>(pns.exponent, pns.mantissa); adjusted_mantissa am = compute_float<binary_format<T>>(pns.exponent, pns.mantissa);
if(pns.too_many_digits && am.power2 >= 0) { if(pns.too_many_digits && am.power2 >= 0) {