Refactor FP formatting

This commit is contained in:
Victor Zverovich 2021-09-26 08:20:28 -07:00
parent ff7e73af66
commit 716d69f27e

View File

@ -2242,21 +2242,18 @@ small_divisor_case_label:
// Formats a floating-point number using a variation of the Fixed-Precision // Formats a floating-point number using a variation of the Fixed-Precision
// Positive Floating-Point Printout ((FPP)^2) algorithm by Steele & White: // Positive Floating-Point Printout ((FPP)^2) algorithm by Steele & White:
// https://fmt.dev/papers/p372-steele.pdf. // https://fmt.dev/papers/p372-steele.pdf.
template <typename Float> FMT_CONSTEXPR20 inline void format_dragon(fp value, bool is_predecessor_closer,
FMT_CONSTEXPR20 void fallback_format(Float n, int num_digits, bool binary32, int num_digits, buffer<char>& buf,
buffer<char>& buf, int& exp10) { int& exp10) {
bigint numerator; // 2 * R in (FPP)^2. bigint numerator; // 2 * R in (FPP)^2.
bigint denominator; // 2 * S in (FPP)^2. bigint denominator; // 2 * S in (FPP)^2.
// lower and upper are differences between value and corresponding boundaries. // lower and upper are differences between value and corresponding boundaries.
bigint lower; // (M^- in (FPP)^2). bigint lower; // (M^- in (FPP)^2).
bigint upper_store; // upper's value if different from lower. bigint upper_store; // upper's value if different from lower.
bigint* upper = nullptr; // (M^+ in (FPP)^2). bigint* upper = nullptr; // (M^+ in (FPP)^2).
fp value;
// Shift numerator and denominator by an extra bit or two (if lower boundary // Shift numerator and denominator by an extra bit or two (if lower boundary
// is closer) to make lower and upper integers. This eliminates multiplication // is closer) to make lower and upper integers. This eliminates multiplication
// by 2 during later computations. // by 2 during later computations.
const bool is_predecessor_closer =
binary32 ? value.assign(static_cast<float>(n)) : value.assign(n);
int shift = is_predecessor_closer ? 2 : 1; int shift = is_predecessor_closer ? 2 : 1;
uint64_t significand = value.f << shift; uint64_t significand = value.f << shift;
if (value.e >= 0) { if (value.e >= 0) {
@ -2359,11 +2356,12 @@ FMT_CONSTEXPR20 void fallback_format(Float n, int num_digits, bool binary32,
buf[num_digits - 1] = static_cast<char>('0' + digit); buf[num_digits - 1] = static_cast<char>('0' + digit);
} }
template <typename T> template <typename Float>
FMT_HEADER_ONLY_CONSTEXPR20 int format_float(T value, int precision, FMT_HEADER_ONLY_CONSTEXPR20 int format_float(Float value, int precision,
float_specs specs, float_specs specs,
buffer<char>& buf) { buffer<char>& buf) {
static_assert(!std::is_same<T, float>::value, ""); // float is passed as double to reduce the number of instantiations.
static_assert(!std::is_same<Float, float>::value, "");
FMT_ASSERT(value >= 0, "value is negative"); FMT_ASSERT(value >= 0, "value is negative");
const bool fixed = specs.format == float_format::fixed; const bool fixed = specs.format == float_format::fixed;
@ -2392,8 +2390,8 @@ FMT_HEADER_ONLY_CONSTEXPR20 int format_float(T value, int precision,
} }
int exp = 0; int exp = 0;
bool fallback = true; bool use_dragon = true;
if (is_fast_float<T>()) { if (is_fast_float<Float>()) {
// Use Grisu + Dragon4 for the given precision: // Use Grisu + Dragon4 for the given precision:
// https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf. // https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf.
const int min_exp = -60; // alpha in Grisu. const int min_exp = -60; // alpha in Grisu.
@ -2411,13 +2409,18 @@ FMT_HEADER_ONLY_CONSTEXPR20 int format_float(T value, int precision,
!is_constant_evaluated()) { !is_constant_evaluated()) {
exp += handler.exp10; exp += handler.exp10;
buf.try_resize(to_unsigned(handler.size)); buf.try_resize(to_unsigned(handler.size));
fallback = false; use_dragon = false;
} else { } else {
exp += handler.size - cached_exp10 - 1; exp += handler.size - cached_exp10 - 1;
precision = handler.precision; precision = handler.precision;
} }
} }
if (fallback) fallback_format(value, precision, specs.binary32, buf, exp); if (use_dragon) {
auto f = fp();
bool is_predecessor_closer =
specs.binary32 ? f.assign(static_cast<float>(value)) : f.assign(value);
format_dragon(f, is_predecessor_closer, precision, buf, exp);
}
if (!fixed && !specs.showpoint) { if (!fixed && !specs.showpoint) {
// Remove trailing zeros. // Remove trailing zeros.
auto num_digits = buf.size(); auto num_digits = buf.size();