stop -> handler and swap args

This commit is contained in:
Victor Zverovich 2019-03-10 14:43:26 -07:00
parent f90d33ca12
commit b1f7cca89e

View File

@ -468,9 +468,9 @@ inline round_direction get_round_direction(uint64_t divisor, uint64_t remainder,
} }
// Generates output using Grisu2 digit-gen algorithm. // Generates output using Grisu2 digit-gen algorithm.
template <typename Stop> template <typename Handler>
int grisu2_gen_digits(char* buf, fp value, uint64_t error, int& exp, int grisu2_gen_digits(char* buf, fp value, uint64_t error, int& exp,
Stop stop) { Handler handler) {
fp one(1ull << -value.e, value.e); fp one(1ull << -value.e, value.e);
// The integral part of scaled value (p1 in Grisu) = value / one. It cannot be // The integral part of scaled value (p1 in Grisu) = value / one. It cannot be
// zero because it contains a product of two 64-bit numbers with MSB set (due // zero because it contains a product of two 64-bit numbers with MSB set (due
@ -482,7 +482,7 @@ int grisu2_gen_digits(char* buf, fp value, uint64_t error, int& exp,
uint64_t fractional = value.f & (one.f - 1); uint64_t fractional = value.f & (one.f - 1);
exp = count_digits(integral); // kappa in Grisu. exp = count_digits(integral); // kappa in Grisu.
int size = 0; int size = 0;
if (stop.init(buf, size, value.f, data::POWERS_OF_10_64[exp] << -one.e, if (handler.on_start(buf, size, data::POWERS_OF_10_64[exp] << -one.e, value.f,
error, exp)) { error, exp)) {
return size; return size;
} }
@ -539,7 +539,7 @@ int grisu2_gen_digits(char* buf, fp value, uint64_t error, int& exp,
--exp; --exp;
uint64_t remainder = uint64_t remainder =
(static_cast<uint64_t>(integral) << -one.e) + fractional; (static_cast<uint64_t>(integral) << -one.e) + fractional;
if (stop(buf, size, remainder, data::POWERS_OF_10_64[exp] << -one.e, if (handler(buf, size, data::POWERS_OF_10_64[exp] << -one.e, remainder,
error, exp, true)) { error, exp, true)) {
return size; return size;
} }
@ -552,12 +552,12 @@ int grisu2_gen_digits(char* buf, fp value, uint64_t error, int& exp,
buf[size++] = static_cast<char>('0' + digit); buf[size++] = static_cast<char>('0' + digit);
fractional &= one.f - 1; fractional &= one.f - 1;
--exp; --exp;
if (stop(buf, size, fractional, one.f, error, exp, false)) return size; if (handler(buf, size, one.f, fractional, error, exp, false)) return size;
} }
} }
// Stopping condition for the fixed precision. // The fixed precision digit handler.
struct fixed_stop { struct fixed_handler {
int precision; int precision;
int exp10; int exp10;
bool fixed; bool fixed;
@ -566,7 +566,7 @@ struct fixed_stop {
return full_exp <= 0 && -full_exp >= precision; return full_exp <= 0 && -full_exp >= precision;
} }
bool init(char* buf, int& size, uint64_t remainder, uint64_t divisor, bool on_start(char* buf, int& size, uint64_t divisor, uint64_t remainder,
uint64_t error, int& exp) { uint64_t error, int& exp) {
if (!fixed) return false; if (!fixed) return false;
int full_exp = exp + exp10; int full_exp = exp + exp10;
@ -586,7 +586,7 @@ struct fixed_stop {
} }
// TODO: test // TODO: test
bool operator()(char* buf, int& size, uint64_t remainder, uint64_t divisor, bool operator()(char* buf, int& size, uint64_t divisor, uint64_t remainder,
uint64_t error, int& exp, bool integral) const { uint64_t error, int& exp, bool integral) const {
assert(remainder < divisor); assert(remainder < divisor);
if (size != precision && !enough_precision(exp + exp10)) return false; if (size != precision && !enough_precision(exp + exp10)) return false;
@ -623,13 +623,15 @@ struct fixed_stop {
} }
}; };
// Stopping condition for the shortest representation. // The shortest representation digit handler.
struct shortest_stop { struct shortest_handler {
fp diff; // wp_w in Grisu. fp diff; // wp_w in Grisu.
bool init(char*, int&, uint64_t, uint64_t, uint64_t, int&) { return false; } bool on_start(char*, int&, uint64_t, uint64_t, uint64_t, int&) {
return false;
}
bool operator()(char* buf, int& size, uint64_t remainder, uint64_t divisor, bool operator()(char* buf, int& size, uint64_t divisor, uint64_t remainder,
uint64_t error, int& exp, bool integral) { uint64_t error, int& exp, bool integral) {
if (remainder > error) return false; if (remainder > error) return false;
uint64_t d = integral ? diff.f : diff.f * data::POWERS_OF_10_64[-exp]; uint64_t d = integral ? diff.f : diff.f * data::POWERS_OF_10_64[-exp];
@ -668,8 +670,9 @@ grisu2_format(Double value, buffer& buf, int precision, bool fixed, int& exp) {
auto cached_pow = get_cached_power( auto cached_pow = get_cached_power(
min_exp - (fp_value.e + fp::significand_size), cached_exp10); min_exp - (fp_value.e + fp::significand_size), cached_exp10);
fp_value = fp_value * cached_pow; fp_value = fp_value * cached_pow;
int size = grisu2_gen_digits(buf.data(), fp_value, 1, exp, int size =
fixed_stop{precision, -cached_exp10, fixed}); grisu2_gen_digits(buf.data(), fp_value, 1, exp,
fixed_handler{precision, -cached_exp10, fixed});
if (size < 0) return false; if (size < 0) return false;
buf.resize(to_unsigned(size)); buf.resize(to_unsigned(size));
} else { } else {
@ -687,7 +690,7 @@ grisu2_format(Double value, buffer& buf, int precision, bool fixed, int& exp) {
lower = lower * cached_pow; // \tilde{M}^- in Grisu. lower = lower * cached_pow; // \tilde{M}^- in Grisu.
++lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}. ++lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}.
int size = grisu2_gen_digits(buf.data(), upper, upper.f - lower.f, exp, int size = grisu2_gen_digits(buf.data(), upper, upper.f - lower.f, exp,
shortest_stop{upper - fp_value}); shortest_handler{upper - fp_value});
if (size < 0) return false; if (size < 0) return false;
buf.resize(to_unsigned(size)); buf.resize(to_unsigned(size));
} }