From f607e3e970fe0dc0e71b04e4a65f50e90aac74df Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 3 Apr 2022 08:44:51 -0700 Subject: [PATCH] Add __float128 support --- include/fmt/format-inl.h | 14 +++++++------- include/fmt/format.h | 29 ++++++++++++++++------------- test/format-test.cc | 6 ++++++ 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index 0febc002..99023abd 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -234,10 +234,10 @@ template struct basic_fp { // The predecessor is closer if n is a normalized power of 2 (f == 0) other // than the smallest normalized number (biased_e > 1). auto is_predecessor_closer = f == 0 && biased_e > 1; - if (biased_e != 0) - f += static_cast(implicit_bit); - else + if (biased_e == 0) biased_e = 1; // Subnormals use biased exponent 1 (min exponent). + else if (has_implicit_bit()) + f += static_cast(implicit_bit); e = biased_e - exponent_bias() - num_float_significand_bits; if (!has_implicit_bit()) ++e; return is_predecessor_closer; @@ -2049,9 +2049,9 @@ enum dragon { // Formats a floating-point number using a variation of the Fixed-Precision // Positive Floating-Point Printout ((FPP)^2) algorithm by Steele & White: // https://fmt.dev/papers/p372-steele.pdf. -FMT_CONSTEXPR20 inline void format_dragon(fp value, unsigned flags, - int num_digits, buffer& buf, - int& exp10) { +FMT_CONSTEXPR20 inline void format_dragon(basic_fp value, + unsigned flags, int num_digits, + buffer& buf, int& exp10) { bigint numerator; // 2 * R in (FPP)^2. bigint denominator; // 2 * S in (FPP)^2. // lower and upper are differences between value and corresponding boundaries. @@ -2255,7 +2255,7 @@ FMT_HEADER_ONLY_CONSTEXPR20 int format_float(Float value, int precision, } } if (use_dragon) { - auto f = fp(); + auto f = basic_fp(); bool is_predecessor_closer = specs.binary32 ? f.assign(static_cast(value)) : f.assign(converted_value); diff --git a/include/fmt/format.h b/include/fmt/format.h index 63eed8bb..dbf92f1a 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -336,24 +336,26 @@ class uint128_fallback { return static_cast(lo_); } - friend auto operator==(const uint128_fallback& lhs, - const uint128_fallback& rhs) -> bool { + friend constexpr auto operator==(const uint128_fallback& lhs, + const uint128_fallback& rhs) -> bool { return lhs.hi_ == rhs.hi_ && lhs.lo_ == rhs.lo_; } - friend auto operator!=(const uint128_fallback& lhs, - const uint128_fallback& rhs) -> bool { + friend constexpr auto operator!=(const uint128_fallback& lhs, + const uint128_fallback& rhs) -> bool { return !(lhs == rhs); } - friend auto operator>(const uint128_fallback& lhs, - const uint128_fallback& rhs) -> bool { + friend constexpr auto operator>(const uint128_fallback& lhs, + const uint128_fallback& rhs) -> bool { return lhs.hi_ != rhs.hi_ ? lhs.hi_ > rhs.hi_ : lhs.lo_ > rhs.lo_; } - friend auto operator|(const uint128_fallback& lhs, - const uint128_fallback& rhs) -> uint128_fallback { + friend constexpr auto operator|(const uint128_fallback& lhs, + const uint128_fallback& rhs) + -> uint128_fallback { return {lhs.hi_ | rhs.hi_, lhs.lo_ | rhs.lo_}; } - friend auto operator&(const uint128_fallback& lhs, - const uint128_fallback& rhs) -> uint128_fallback { + friend constexpr auto operator&(const uint128_fallback& lhs, + const uint128_fallback& rhs) + -> uint128_fallback { return {lhs.hi_ & rhs.hi_, lhs.lo_ & rhs.lo_}; } friend auto operator+(const uint128_fallback& lhs, @@ -366,12 +368,13 @@ class uint128_fallback { -> uint128_fallback { FMT_ASSERT(lhs.hi_ == 0, ""); uint64_t hi = (lhs.lo_ >> 32) * rhs; - return {hi >> 32, (hi << 32) + (lhs.lo_ & ~uint32_t()) * rhs}; + uint64_t lo = (lhs.lo_ & ~uint32_t()) * rhs; + uint64_t new_lo = (hi << 32) + lo; + return {(hi >> 32) + (new_lo < lo ? 1 : 0), new_lo}; } friend auto operator-(const uint128_fallback& lhs, uint64_t rhs) -> uint128_fallback { - FMT_ASSERT(lhs.lo_ >= rhs, ""); - return {lhs.hi_, lhs.lo_ - rhs}; + return {lhs.hi_ - (lhs.lo_ < rhs ? 1 : 0), lhs.lo_ - rhs}; } FMT_CONSTEXPR auto operator>>(int shift) const -> uint128_fallback { if (shift == 64) return {0, hi_}; diff --git a/test/format-test.cc b/test/format-test.cc index b5ecd03c..5acffab9 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -75,6 +75,12 @@ TEST(uint128_test, plus_assign) { EXPECT_EQ(n, uint128_fallback(1) << 64); } +TEST(uint128_test, multiply) { + auto n = uint128_fallback(2251799813685247); + n = n * 3611864890; + EXPECT_EQ(static_cast(n >> 64), 440901); +} + template void check_isfinite() { using fmt::detail::isfinite; EXPECT_TRUE(isfinite(Float(0.0)));