mirror of
https://github.com/fastfloat/fast_float.git
synced 2025-12-07 01:06:48 +08:00
Adopting proposal.
This commit is contained in:
parent
bfc0478feb
commit
39ea41b84a
@ -76,8 +76,10 @@ fastfloat_really_inline bool rounds_to_nearest() noexcept {
|
|||||||
// However, it is expected to be much faster than the fegetround()
|
// However, it is expected to be much faster than the fegetround()
|
||||||
// function call.
|
// function call.
|
||||||
//
|
//
|
||||||
// volatile prevents the compiler from computing the function at compile-time
|
// The volatile keywoard prevents the compiler from computing the function
|
||||||
// It does not need to be std::numeric_limits<float>::min(), any small
|
// at compile-time.
|
||||||
|
// There might be other ways to prevent compile-time optimizations (e.g., asm).
|
||||||
|
// The value does not need to be std::numeric_limits<float>::min(), any small
|
||||||
// value so that 1 + x should round to 1 would do.
|
// value so that 1 + x should round to 1 would do.
|
||||||
static volatile float fmin = std::numeric_limits<float>::min();
|
static volatile float fmin = std::numeric_limits<float>::min();
|
||||||
//
|
//
|
||||||
@ -100,6 +102,8 @@ fastfloat_really_inline bool rounds_to_nearest() noexcept {
|
|||||||
// fmin + 1.0f = 0x1 (1)
|
// fmin + 1.0f = 0x1 (1)
|
||||||
// 1.0f - fmin = 0x1 (1)
|
// 1.0f - fmin = 0x1 (1)
|
||||||
//
|
//
|
||||||
|
// Note: This may fail to be accurate if fast-math has been
|
||||||
|
// enabled, as rounding conventions may not apply.
|
||||||
return (fmin + 1.0f == 1.0f - fmin);
|
return (fmin + 1.0f == 1.0f - fmin);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,12 +134,23 @@ 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;
|
||||||
|
// The implementation of the Clinger's fast path is convoluted because
|
||||||
|
// we want round-to-nearest in all cases, irrespective of the rounding mode
|
||||||
|
// selected on the thread.
|
||||||
|
// We proceed optimistically, assuming that detail::rounds_to_nearest() returns
|
||||||
|
// true.
|
||||||
|
if (binary_format<T>::min_exponent_fast_path() <= pns.exponent && pns.exponent <= binary_format<T>::max_exponent_fast_path() && !pns.too_many_digits) {
|
||||||
// Unfortunately, the conventional Clinger's fast path is only possible
|
// Unfortunately, the conventional Clinger's fast path is only possible
|
||||||
// when the system rounds to the nearest float.
|
// when the system rounds to the nearest float.
|
||||||
|
//
|
||||||
|
// We expect the next branch to almost always be selected.
|
||||||
|
// We could check it first (before the previous branch), but
|
||||||
|
// there might be performance advantages at having the check
|
||||||
|
// be last.
|
||||||
if(detail::rounds_to_nearest()) {
|
if(detail::rounds_to_nearest()) {
|
||||||
// We have that fegetround() == FE_TONEAREST.
|
// We have that fegetround() == FE_TONEAREST.
|
||||||
// Next is Clinger's fast path.
|
// Next is Clinger's fast path.
|
||||||
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.mantissa <=binary_format<T>::max_mantissa_fast_path()) {
|
||||||
value = T(pns.mantissa);
|
value = T(pns.mantissa);
|
||||||
if (pns.exponent < 0) { value = value / binary_format<T>::exact_power_of_ten(-pns.exponent); }
|
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); }
|
else { value = value * binary_format<T>::exact_power_of_ten(pns.exponent); }
|
||||||
@ -145,7 +160,7 @@ from_chars_result from_chars_advanced(const char *first, const char *last,
|
|||||||
} else {
|
} else {
|
||||||
// We do not have that fegetround() == FE_TONEAREST.
|
// We do not have that fegetround() == FE_TONEAREST.
|
||||||
// Next is a modified Clinger's fast path, inspired by Jakub Jelínek's proposal
|
// 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) {
|
if (pns.exponent >= 0 && pns.mantissa <=binary_format<T>::max_mantissa_fast_path(pns.exponent)) {
|
||||||
#if (defined(_WIN32) && defined(__clang__))
|
#if (defined(_WIN32) && defined(__clang__))
|
||||||
// ClangCL may map 0 to -0.0 when fegetround() == FE_DOWNWARD
|
// ClangCL may map 0 to -0.0 when fegetround() == FE_DOWNWARD
|
||||||
if(pns.mantissa == 0) {
|
if(pns.mantissa == 0) {
|
||||||
@ -158,6 +173,7 @@ from_chars_result from_chars_advanced(const char *first, const char *last,
|
|||||||
return answer;
|
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) {
|
||||||
if(am != compute_float<binary_format<T>>(pns.exponent, pns.mantissa + 1)) {
|
if(am != compute_float<binary_format<T>>(pns.exponent, pns.mantissa + 1)) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user