mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-30 10:47:35 +02:00
Simplify Dragonbox Step 3.
This commit is contained in:
committed by
Victor Zverovich
parent
70561ed13e
commit
f4dd1b1b8b
@ -990,22 +990,22 @@ inline bool divisible_by_power_of_5(uint64_t x, int exp) FMT_NOEXCEPT {
|
|||||||
return x * divtest_table[exp].mod_inv <= divtest_table[exp].max_quotient;
|
return x * divtest_table[exp].mod_inv <= divtest_table[exp].max_quotient;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replaces n by floor(n / pow(5, N)) returning true if and only if n is
|
// Replaces n by floor(n / pow(10, N)) returning true if and only if n is
|
||||||
// divisible by pow(5, N).
|
// divisible by pow(10, N).
|
||||||
// Precondition: n <= 2 * pow(5, N + 1).
|
// Precondition: n <= pow(10, N + 1).
|
||||||
template <int N>
|
template <int N>
|
||||||
bool check_divisibility_and_divide_by_pow5(uint32_t& n) FMT_NOEXCEPT {
|
bool check_divisibility_and_divide_by_pow10(uint32_t& n) FMT_NOEXCEPT {
|
||||||
static constexpr struct {
|
static constexpr struct {
|
||||||
uint32_t magic_number;
|
uint32_t magic_number;
|
||||||
int bits_for_comparison;
|
int margin_bits;
|
||||||
uint32_t threshold;
|
int divisibility_check_bits;
|
||||||
int shift_amount;
|
} infos[] = {{0x199a, 8, 8}, {0xa3d71, 10, 16}};
|
||||||
} infos[] = {{0xcccd, 16, 0x3333, 18}, {0xa429, 8, 0x0a, 20}};
|
|
||||||
constexpr auto info = infos[N - 1];
|
constexpr auto info = infos[N - 1];
|
||||||
n *= info.magic_number;
|
n *= info.magic_number;
|
||||||
const uint32_t comparison_mask = (1u << info.bits_for_comparison) - 1;
|
n >>= margin_bits;
|
||||||
bool result = (n & comparison_mask) <= info.threshold;
|
const uint32_t comparison_mask = (1u << info.divisibility_check_bits) - 1;
|
||||||
n >>= info.shift_amount;
|
bool result = (n & comparison_mask) == 0;
|
||||||
|
n >>= info.divisibility_check_bits;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2111,7 +2111,7 @@ template <typename T> decimal_fp<T> to_decimal(T x) FMT_NOEXCEPT {
|
|||||||
const cache_entry_type cache = cache_accessor<T>::get_cached_power(-minus_k);
|
const cache_entry_type cache = cache_accessor<T>::get_cached_power(-minus_k);
|
||||||
const int beta_minus_1 = exponent + floor_log2_pow10(-minus_k);
|
const int beta_minus_1 = exponent + floor_log2_pow10(-minus_k);
|
||||||
|
|
||||||
// Compute zi and deltai
|
// Compute zi and deltai.
|
||||||
// 10^kappa <= deltai < 10^(kappa + 1)
|
// 10^kappa <= deltai < 10^(kappa + 1)
|
||||||
const uint32_t deltai = cache_accessor<T>::compute_delta(cache, beta_minus_1);
|
const uint32_t deltai = cache_accessor<T>::compute_delta(cache, beta_minus_1);
|
||||||
const carrier_uint two_fc = significand << 1;
|
const carrier_uint two_fc = significand << 1;
|
||||||
@ -2119,10 +2119,10 @@ template <typename T> decimal_fp<T> to_decimal(T x) FMT_NOEXCEPT {
|
|||||||
const carrier_uint zi =
|
const carrier_uint zi =
|
||||||
cache_accessor<T>::compute_mul(two_fr << beta_minus_1, cache);
|
cache_accessor<T>::compute_mul(two_fr << beta_minus_1, cache);
|
||||||
|
|
||||||
// Step 2: Try larger divisor; remove trailing zeros if necessary
|
// Step 2: Try larger divisor; remove trailing zeros if necessary.
|
||||||
|
|
||||||
// Using an upper bound on zi, we might be able to optimize the division
|
// Using an upper bound on zi, we might be able to optimize the division
|
||||||
// better than the compiler; we are computing zi / big_divisor here
|
// better than the compiler; we are computing zi / big_divisor here.
|
||||||
decimal_fp<T> ret_value;
|
decimal_fp<T> ret_value;
|
||||||
ret_value.significand = divide_by_10_to_kappa_plus_1(zi);
|
ret_value.significand = divide_by_10_to_kappa_plus_1(zi);
|
||||||
uint32_t r = static_cast<uint32_t>(zi - float_info<T>::big_divisor *
|
uint32_t r = static_cast<uint32_t>(zi - float_info<T>::big_divisor *
|
||||||
@ -2131,7 +2131,7 @@ template <typename T> decimal_fp<T> to_decimal(T x) FMT_NOEXCEPT {
|
|||||||
if (r > deltai) {
|
if (r > deltai) {
|
||||||
goto small_divisor_case_label;
|
goto small_divisor_case_label;
|
||||||
} else if (r < deltai) {
|
} else if (r < deltai) {
|
||||||
// Exclude the right endpoint if necessary
|
// Exclude the right endpoint if necessary.
|
||||||
if (r == 0 && !include_right_endpoint &&
|
if (r == 0 && !include_right_endpoint &&
|
||||||
is_endpoint_integer<T>(two_fr, exponent, minus_k)) {
|
is_endpoint_integer<T>(two_fr, exponent, minus_k)) {
|
||||||
--ret_value.significand;
|
--ret_value.significand;
|
||||||
@ -2141,7 +2141,7 @@ template <typename T> decimal_fp<T> to_decimal(T x) FMT_NOEXCEPT {
|
|||||||
} else {
|
} else {
|
||||||
// r == deltai; compare fractional parts
|
// r == deltai; compare fractional parts
|
||||||
// Check conditions in the order different from the paper
|
// Check conditions in the order different from the paper
|
||||||
// to take advantage of short-circuiting
|
// to take advantage of short-circuiting.
|
||||||
const carrier_uint two_fl = two_fc - 1;
|
const carrier_uint two_fl = two_fc - 1;
|
||||||
if ((!include_left_endpoint ||
|
if ((!include_left_endpoint ||
|
||||||
!is_endpoint_integer<T>(two_fl, exponent, minus_k)) &&
|
!is_endpoint_integer<T>(two_fl, exponent, minus_k)) &&
|
||||||
@ -2151,59 +2151,44 @@ template <typename T> decimal_fp<T> to_decimal(T x) FMT_NOEXCEPT {
|
|||||||
}
|
}
|
||||||
ret_value.exponent = minus_k + float_info<T>::kappa + 1;
|
ret_value.exponent = minus_k + float_info<T>::kappa + 1;
|
||||||
|
|
||||||
// We may need to remove trailing zeros
|
// We may need to remove trailing zeros.
|
||||||
ret_value.exponent += remove_trailing_zeros(ret_value.significand);
|
ret_value.exponent += remove_trailing_zeros(ret_value.significand);
|
||||||
return ret_value;
|
return ret_value;
|
||||||
|
|
||||||
// Step 3: Find the significand with the smaller divisor
|
// Step 3: Find the significand with the smaller divisor.
|
||||||
|
|
||||||
small_divisor_case_label:
|
small_divisor_case_label:
|
||||||
ret_value.significand *= 10;
|
ret_value.significand *= 10;
|
||||||
ret_value.exponent = minus_k + float_info<T>::kappa;
|
ret_value.exponent = minus_k + float_info<T>::kappa;
|
||||||
|
|
||||||
const uint32_t mask = (1u << float_info<T>::kappa) - 1;
|
|
||||||
auto dist = r - (deltai / 2) + (float_info<T>::small_divisor / 2);
|
auto dist = r - (deltai / 2) + (float_info<T>::small_divisor / 2);
|
||||||
|
bool const approx_y_parity = ((dist ^ (small_divisor / 2)) & 1) != 0;
|
||||||
|
|
||||||
// Is dist divisible by 2^kappa?
|
// Is dist divisible by 10^kappa?
|
||||||
if ((dist & mask) == 0) {
|
bool divisible_by_10_to_the_kappa =
|
||||||
const bool approx_y_parity =
|
check_divisibility_and_divide_by_pow10<float_info<T>::kappa>(dist);
|
||||||
((dist ^ (float_info<T>::small_divisor / 2)) & 1) != 0;
|
|
||||||
dist >>= float_info<T>::kappa;
|
|
||||||
|
|
||||||
// Is dist divisible by 5^kappa?
|
// Add dist / 10^kappa to the significand.
|
||||||
if (check_divisibility_and_divide_by_pow5<float_info<T>::kappa>(dist)) {
|
ret_value.significand += dist;
|
||||||
ret_value.significand += dist;
|
|
||||||
|
|
||||||
// Check z^(f) >= epsilon^(f)
|
if (divisible_by_10_to_the_kappa) {
|
||||||
// We have either yi == zi - epsiloni or yi == (zi - epsiloni) - 1,
|
// Check z^(f) >= epsilon^(f).
|
||||||
// where yi == zi - epsiloni if and only if z^(f) >= epsilon^(f)
|
// We have either yi == zi - epsiloni or yi == (zi - epsiloni) - 1,
|
||||||
// Since there are only 2 possibilities, we only need to care about the
|
// where yi == zi - epsiloni if and only if z^(f) >= epsilon^(f)
|
||||||
// parity. Also, zi and r should have the same parity since the divisor
|
// Since there are only 2 possibilities, we only need to care about the
|
||||||
// is an even number
|
// parity. Also, zi and r should have the same parity since the divisor
|
||||||
if (cache_accessor<T>::compute_mul_parity(two_fc, cache, beta_minus_1) !=
|
// is an even number.
|
||||||
approx_y_parity) {
|
if (cache_accessor<T>::compute_mul_parity(two_fc, cache, beta_minus_1) !=
|
||||||
--ret_value.significand;
|
approx_y_parity) {
|
||||||
} else {
|
--ret_value.significand;
|
||||||
// If z^(f) >= epsilon^(f), we might have a tie
|
} else {
|
||||||
// when z^(f) == epsilon^(f), or equivalently, when y is an integer
|
// If z^(f) >= epsilon^(f), we might have a tie
|
||||||
if (is_center_integer<T>(two_fc, exponent, minus_k)) {
|
// when z^(f) == epsilon^(f), or equivalently, when y is an integer
|
||||||
ret_value.significand = ret_value.significand % 2 == 0
|
if (is_center_integer<T>(two_fc, exponent, minus_k)) {
|
||||||
? ret_value.significand
|
ret_value.significand = ret_value.significand % 2 == 0
|
||||||
: ret_value.significand - 1;
|
? ret_value.significand
|
||||||
}
|
: ret_value.significand - 1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Is dist not divisible by 5^kappa?
|
|
||||||
else {
|
|
||||||
ret_value.significand += dist;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Is dist not divisible by 2^kappa?
|
|
||||||
else {
|
|
||||||
// Since we know dist is small, we might be able to optimize the division
|
|
||||||
// better than the compiler; we are computing dist / small_divisor here
|
|
||||||
ret_value.significand +=
|
|
||||||
small_division_by_pow10<float_info<T>::kappa>(dist);
|
|
||||||
}
|
}
|
||||||
return ret_value;
|
return ret_value;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user