Skip to content

Commit

Permalink
Reuse basic_fp
Browse files Browse the repository at this point in the history
Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
  • Loading branch information
phprus committed Nov 14, 2022
1 parent b13715e commit 019fa7e
Showing 1 changed file with 23 additions and 39 deletions.
62 changes: 23 additions & 39 deletions include/fmt/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -3116,71 +3116,62 @@ FMT_CONSTEXPR20 inline void format_dragon(basic_fp<uint128_t> value,
}

// Formats a floating-point number with snprintf using the hexfloat format.
template <typename Float, FMT_ENABLE_IF(!is_double_double<Float>::value)>
template <typename Float>
FMT_CONSTEXPR20 void format_hexfloat(Float value, int precision,
float_specs specs, buffer<char>& buf) {
// float is passed as double to reduce the number of instantiations and to
// simplify implementation.
static_assert(!std::is_same<Float, float>::value, "");
static_assert(std::numeric_limits<Float>::digits <= 113, "unsupported FP");

using info = dragonbox::float_info<Float>;

// Assume Float is in the format [sign][exponent][significand].
using carrier_uint = typename info::carrier_uint;

carrier_uint f;
int e;

constexpr auto num_significand_bits = detail::num_significand_bits<Float>();
const auto implicit_bit = carrier_uint(1) << num_significand_bits;
const auto significand_mask = implicit_bit - 1;
auto u = bit_cast<carrier_uint>(value);
f = static_cast<carrier_uint>(u & significand_mask);
auto biased_e =
static_cast<int>((u & exponent_mask<Float>()) >> num_significand_bits);
constexpr auto num_float_significand_bits =
detail::num_significand_bits<Float>();

if (biased_e == 0)
biased_e = 1; // Subnormals use biased exponent 1 (min exponent).
else if (has_implicit_bit<Float>())
f += static_cast<carrier_uint>(implicit_bit);

e = biased_e - (1 << (info::exponent_bits - 1)) + 1;
basic_fp<carrier_uint> f(value);
f.e += num_float_significand_bits;
if (!has_implicit_bit<Float>()) --f.e;

constexpr auto num_fraction_bits =
num_significand_bits + (has_implicit_bit<Float>() ? 1 : 0);
num_float_significand_bits + (has_implicit_bit<Float>() ? 1 : 0);
constexpr auto num_xdigits = (num_fraction_bits + 3) / 4;

constexpr auto leading_shift = ((num_xdigits - 1) * 4);
const auto leading_mask = carrier_uint(0xF) << leading_shift;
const auto leading_v =
static_cast<uint32_t>((f & leading_mask) >> leading_shift);
if (leading_v > 1) e -= (32 - FMT_BUILTIN_CLZ(leading_v) - 1);
static_cast<uint32_t>((f.f & leading_mask) >> leading_shift);
if (leading_v > 1) f.e -= (32 - FMT_BUILTIN_CLZ(leading_v) - 1);

int print_xdigits = num_xdigits - 1;
if (precision >= 0 && print_xdigits > precision) {
const int shift = ((print_xdigits - precision - 1) * 4);
const auto mask = carrier_uint(0xF) << shift;
const auto v = static_cast<uint32_t>((f & mask) >> shift);
const auto v = static_cast<uint32_t>((f.f & mask) >> shift);

if (v >= 8) {
const auto inc = carrier_uint(1) << (shift + 4);
f += inc;
f &= ~(inc - 1);
f.f += inc;
f.f &= ~(inc - 1);
}

// long double overflow
if (!has_implicit_bit<Float>() && ((f & implicit_bit) == implicit_bit)) {
f >>= 4;
e += 4;
// Check long double overflow
if (!has_implicit_bit<Float>()) {
const auto implicit_bit = carrier_uint(1) << num_float_significand_bits;
if ((f.f & implicit_bit) == implicit_bit) {
f.f >>= 4;
f.e += 4;
}
}

print_xdigits = precision;
}

char xdigits[num_bits<carrier_uint>() / 4];
detail::fill_n(xdigits, sizeof(xdigits), '0');
format_uint<4>(xdigits, f, num_xdigits, specs.upper);
format_uint<4>(xdigits, f.f, num_xdigits, specs.upper);

// Remove zero tail
while (print_xdigits > 0 && xdigits[print_xdigits] == '0') --print_xdigits;
Expand All @@ -3196,23 +3187,16 @@ FMT_CONSTEXPR20 void format_hexfloat(Float value, int precision,
buf.push_back(specs.upper ? 'P' : 'p');

uint32_t abs_e;
if (e < 0) {
if (f.e < 0) {
buf.push_back('-');
abs_e = static_cast<uint32_t>(-e);
abs_e = static_cast<uint32_t>(-f.e);
} else {
buf.push_back('+');
abs_e = static_cast<uint32_t>(e);
abs_e = static_cast<uint32_t>(f.e);
}
format_decimal<char>(appender(buf), abs_e, detail::count_digits(abs_e));
}

template <typename Float, FMT_ENABLE_IF(is_double_double<Float>::value)>
FMT_CONSTEXPR20 void format_hexfloat(Float value, int precision,
float_specs specs, buffer<char>& buf) {
static_assert(std::numeric_limits<double>::is_iec559, "unsupported FP");
format_hexfloat(static_cast<double>(value), precision, specs, buf);
}

template <typename Float>
FMT_CONSTEXPR20 auto format_float(Float value, int precision, float_specs specs,
buffer<char>& buf) -> int {
Expand Down

0 comments on commit 019fa7e

Please sign in to comment.