Add partial support for extended precision FP

This commit is contained in:
Victor Zverovich
2022-02-07 06:44:42 -08:00
parent 0a24a0714e
commit 2b6f7fc7a3
2 changed files with 38 additions and 23 deletions

View File

@@ -245,8 +245,9 @@ struct fp {
template <typename Float> explicit FMT_CONSTEXPR fp(Float n) { assign(n); }
template <typename Float>
using is_supported = bool_constant<sizeof(Float) == sizeof(uint64_t) ||
sizeof(Float) == sizeof(uint32_t)>;
using is_supported = bool_constant<sizeof(Float) == sizeof(uint32_t) ||
sizeof(Float) == 2 * sizeof(uint32_t) ||
std::numeric_limits<Float>::digits == 64>;
// Assigns d to this and return true iff predecessor is closer than successor.
template <typename Float, FMT_ENABLE_IF(is_supported<Float>::value)>
@@ -255,13 +256,13 @@ struct fp {
const int num_float_significand_bits =
detail::num_significand_bits<Float>();
const uint64_t implicit_bit = 1ULL << num_float_significand_bits;
const uint64_t significand_mask = implicit_bit - 1;
constexpr bool is_double = sizeof(Float) == sizeof(uint64_t);
auto u = bit_cast<conditional_t<is_double, uint64_t, uint32_t>>(n);
using carrier_uint = typename dragonbox::float_info<Float>::carrier_uint;
const carrier_uint significand_mask = implicit_bit - 1;
auto u = bit_cast<carrier_uint>(n);
f = u & significand_mask;
const uint64_t exponent_mask = (~0ULL >> 1) & ~significand_mask;
int biased_e =
static_cast<int>((u & exponent_mask) >> num_float_significand_bits);
static_cast<int>((u & exponent_mask<Float>()) >>
dragonbox::float_info<Float>::significand_bits);
// The predecessor is closer if n is a normalized power of 2 (f == 0) other
// than the smallest normalized number (biased_e > 1).
bool is_predecessor_closer = f == 0 && biased_e > 1;
@@ -2120,10 +2121,9 @@ FMT_CONSTEXPR20 inline void format_dragon(fp value, bool is_predecessor_closer,
// is closer) to make lower and upper integers. This eliminates multiplication
// by 2 during later computations.
int shift = is_predecessor_closer ? 2 : 1;
uint64_t significand = value.f << shift;
if (value.e >= 0) {
numerator.assign(significand);
numerator <<= value.e;
numerator.assign(value.f);
numerator <<= value.e + shift;
lower.assign(1);
lower <<= value.e;
if (shift != 1) {
@@ -2141,11 +2141,13 @@ FMT_CONSTEXPR20 inline void format_dragon(fp value, bool is_predecessor_closer,
upper_store <<= 1;
upper = &upper_store;
}
numerator *= significand;
numerator *= value.f;
numerator <<= shift;
denominator.assign(1);
denominator <<= shift - value.e;
} else {
numerator.assign(significand);
numerator.assign(value.f);
numerator <<= shift;
denominator.assign_pow10(exp10);
denominator <<= shift - value.e;
lower.assign(1);
@@ -2261,7 +2263,7 @@ FMT_HEADER_ONLY_CONSTEXPR20 int format_float(Float value, int precision,
// https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf.
const int min_exp = -60; // alpha in Grisu.
int cached_exp10 = 0; // K in Grisu.
fp normalized = normalize(fp(value));
fp normalized = normalize(fp(convert_float(value)));
const auto cached_pow = get_cached_power(
min_exp - (normalized.e + fp::num_significand_bits), cached_exp10);
normalized = normalized * cached_pow;
@@ -2278,8 +2280,9 @@ FMT_HEADER_ONLY_CONSTEXPR20 int format_float(Float value, int precision,
}
if (use_dragon) {
auto f = fp();
bool is_predecessor_closer =
specs.binary32 ? f.assign(static_cast<float>(value)) : f.assign(value);
bool is_predecessor_closer = specs.binary32
? f.assign(static_cast<float>(value))
: f.assign(convert_float(value));
// Limit precision to the maximum possible number of significant digits in
// an IEEE754 double because we don't need to generate zeros.
const int max_double_digits = 767;