mirror of
https://github.com/fmtlib/fmt.git
synced 2024-12-26 00:21:13 +00:00
Minor grisu improvements
This commit is contained in:
parent
7fbbfed8c6
commit
e61cac687d
@ -332,14 +332,17 @@ const char basic_data<T>::BACKGROUND_COLOR[] = "\x1b[48;2;";
|
|||||||
template <typename T> const char basic_data<T>::RESET_COLOR[] = "\x1b[0m";
|
template <typename T> const char basic_data<T>::RESET_COLOR[] = "\x1b[0m";
|
||||||
template <typename T> const wchar_t basic_data<T>::WRESET_COLOR[] = L"\x1b[0m";
|
template <typename T> const wchar_t basic_data<T>::WRESET_COLOR[] = L"\x1b[0m";
|
||||||
|
|
||||||
|
template <typename T> struct bits {
|
||||||
|
static FMT_CONSTEXPR_DECL const int value =
|
||||||
|
sizeof(T) * std::numeric_limits<unsigned char>::digits;
|
||||||
|
};
|
||||||
|
|
||||||
// A handmade floating-point number f * pow(2, e).
|
// A handmade floating-point number f * pow(2, e).
|
||||||
class fp {
|
class fp {
|
||||||
private:
|
private:
|
||||||
typedef uint64_t significand_type;
|
typedef uint64_t significand_type;
|
||||||
|
|
||||||
// All sizes are in bits.
|
// All sizes are in bits.
|
||||||
static FMT_CONSTEXPR_DECL const int char_size =
|
|
||||||
std::numeric_limits<unsigned char>::digits;
|
|
||||||
// Subtract 1 to account for an implicit most significant bit in the
|
// Subtract 1 to account for an implicit most significant bit in the
|
||||||
// normalized form.
|
// normalized form.
|
||||||
static FMT_CONSTEXPR_DECL const int double_significand_size =
|
static FMT_CONSTEXPR_DECL const int double_significand_size =
|
||||||
@ -352,7 +355,7 @@ class fp {
|
|||||||
int e;
|
int e;
|
||||||
|
|
||||||
static FMT_CONSTEXPR_DECL const int significand_size =
|
static FMT_CONSTEXPR_DECL const int significand_size =
|
||||||
sizeof(significand_type) * char_size;
|
bits<significand_type>::value;
|
||||||
|
|
||||||
fp() : f(0), e(0) {}
|
fp() : f(0), e(0) {}
|
||||||
fp(uint64_t f_val, int e_val) : f(f_val), e(e_val) {}
|
fp(uint64_t f_val, int e_val) : f(f_val), e(e_val) {}
|
||||||
@ -362,9 +365,8 @@ class fp {
|
|||||||
template <typename Double> explicit fp(Double d) {
|
template <typename Double> explicit fp(Double d) {
|
||||||
// Assume double is in the format [sign][exponent][significand].
|
// Assume double is in the format [sign][exponent][significand].
|
||||||
typedef std::numeric_limits<Double> limits;
|
typedef std::numeric_limits<Double> limits;
|
||||||
const int double_size = static_cast<int>(sizeof(Double) * char_size);
|
|
||||||
const int exponent_size =
|
const int exponent_size =
|
||||||
double_size - double_significand_size - 1; // -1 for sign
|
bits<Double>::value - double_significand_size - 1; // -1 for sign
|
||||||
const uint64_t significand_mask = implicit_bit - 1;
|
const uint64_t significand_mask = implicit_bit - 1;
|
||||||
const uint64_t exponent_mask = (~0ull >> 1) & ~significand_mask;
|
const uint64_t exponent_mask = (~0ull >> 1) & ~significand_mask;
|
||||||
const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1;
|
const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1;
|
||||||
@ -463,9 +465,10 @@ FMT_FUNC bool grisu2_round(char* buf, int& size, int max_digits, uint64_t delta,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generates output using Grisu2 digit-gen algorithm.
|
// Generates output using Grisu2 digit-gen algorithm.
|
||||||
FMT_FUNC bool grisu2_gen_digits(char* buf, int& size, uint32_t hi, uint64_t lo,
|
FMT_FUNC int grisu2_gen_digits(char* buf, uint32_t hi, uint64_t lo, int& exp,
|
||||||
int& exp, uint64_t delta, const fp& one,
|
uint64_t delta, const fp& one, const fp& diff,
|
||||||
const fp& diff, int max_digits) {
|
int max_digits) {
|
||||||
|
int size = 0;
|
||||||
// Generate digits for the most significant part (hi).
|
// Generate digits for the most significant part (hi).
|
||||||
while (exp > 0) {
|
while (exp > 0) {
|
||||||
uint32_t digit = 0;
|
uint32_t digit = 0;
|
||||||
@ -519,10 +522,12 @@ FMT_FUNC bool grisu2_gen_digits(char* buf, int& size, uint32_t hi, uint64_t lo,
|
|||||||
--exp;
|
--exp;
|
||||||
uint64_t remainder = (static_cast<uint64_t>(hi) << -one.e) + lo;
|
uint64_t remainder = (static_cast<uint64_t>(hi) << -one.e) + lo;
|
||||||
if (remainder <= delta || size > max_digits) {
|
if (remainder <= delta || size > max_digits) {
|
||||||
return grisu2_round(
|
return grisu2_round(buf, size, max_digits, delta, remainder,
|
||||||
buf, size, max_digits, delta, remainder,
|
static_cast<uint64_t>(data::POWERS_OF_10_32[exp])
|
||||||
static_cast<uint64_t>(data::POWERS_OF_10_32[exp]) << -one.e, diff.f,
|
<< -one.e,
|
||||||
exp);
|
diff.f, exp)
|
||||||
|
? size
|
||||||
|
: -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Generate digits for the least significant part (lo).
|
// Generate digits for the least significant part (lo).
|
||||||
@ -535,7 +540,9 @@ FMT_FUNC bool grisu2_gen_digits(char* buf, int& size, uint32_t hi, uint64_t lo,
|
|||||||
--exp;
|
--exp;
|
||||||
if (lo < delta || size > max_digits) {
|
if (lo < delta || size > max_digits) {
|
||||||
return grisu2_round(buf, size, max_digits, delta, lo, one.f,
|
return grisu2_round(buf, size, max_digits, delta, lo, one.f,
|
||||||
diff.f * data::POWERS_OF_10_32[-exp], exp);
|
diff.f * data::POWERS_OF_10_32[-exp], exp)
|
||||||
|
? size
|
||||||
|
: -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -742,11 +749,10 @@ grisu2_format(Double value, buffer& buf, core_format_specs specs) {
|
|||||||
upper = upper * cached_pow; // \tilde{M}^+ in Grisu.
|
upper = upper * cached_pow; // \tilde{M}^+ in Grisu.
|
||||||
--upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}.
|
--upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}.
|
||||||
fp one(1ull << -upper.e, upper.e);
|
fp one(1ull << -upper.e, upper.e);
|
||||||
// hi (p1 in Grisu) contains the most significant digits of scaled_upper.
|
// hi (p1 in Grisu) contains the most significant digits of scaled upper.
|
||||||
// hi = floor(upper / one).
|
// hi = floor(upper / one).
|
||||||
uint32_t hi = static_cast<uint32_t>(upper.f >> -one.e);
|
uint32_t hi = static_cast<uint32_t>(upper.f >> -one.e);
|
||||||
int exp = count_digits(hi); // kappa in Grisu.
|
int exp = count_digits(hi); // kappa in Grisu.
|
||||||
gen_digits_params params = process_specs(specs, cached_exp + exp, buf);
|
|
||||||
fp_value.normalize();
|
fp_value.normalize();
|
||||||
fp scaled_value = fp_value * cached_pow;
|
fp scaled_value = fp_value * cached_pow;
|
||||||
lower = lower * cached_pow; // \tilde{M}^- in Grisu.
|
lower = lower * cached_pow; // \tilde{M}^- in Grisu.
|
||||||
@ -754,11 +760,12 @@ grisu2_format(Double value, buffer& buf, core_format_specs specs) {
|
|||||||
uint64_t delta = upper.f - lower.f;
|
uint64_t delta = upper.f - lower.f;
|
||||||
fp diff = upper - scaled_value; // wp_w in Grisu.
|
fp diff = upper - scaled_value; // wp_w in Grisu.
|
||||||
// lo (p2 in Grisu) contains the least significants digits of scaled_upper.
|
// lo (p2 in Grisu) contains the least significants digits of scaled_upper.
|
||||||
// lo = supper % one.
|
// lo = upper % one.
|
||||||
uint64_t lo = upper.f & (one.f - 1);
|
uint64_t lo = upper.f & (one.f - 1);
|
||||||
int size = 0;
|
gen_digits_params params = process_specs(specs, cached_exp + exp, buf);
|
||||||
if (!grisu2_gen_digits(buf.data(), size, hi, lo, exp, delta, one, diff,
|
int size = grisu2_gen_digits(buf.data(), hi, lo, exp, delta, one, diff,
|
||||||
params.num_digits)) {
|
params.num_digits);
|
||||||
|
if (size < 0) {
|
||||||
buf.clear();
|
buf.clear();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user