Simplify Dragonbox Step 3.

This commit is contained in:
Junekey Jeon
2022-01-12 16:07:10 -08:00
committed by Victor Zverovich
parent 70561ed13e
commit f4dd1b1b8b

View File

@ -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;
} }