diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index b15eb21c..f30d6073 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -215,18 +215,6 @@ template struct bits { static_cast(sizeof(T) * std::numeric_limits::digits); }; -template constexpr bool has_implicit_bit() { - return std::numeric_limits::digits != 64; -} - -// Returns the number of significand bits in Float excluding the implicit bit. -template constexpr int num_significand_bits() { - // Subtract 1 to account for an implicit most significant bit in the - // normalized form. - return std::numeric_limits::digits - - (has_implicit_bit() ? 1 : 0); -} - // A floating-point number f * pow(2, e). template struct basic_fp { F f; @@ -259,9 +247,8 @@ template struct basic_fp { const carrier_uint significand_mask = implicit_bit - 1; auto u = bit_cast(n); f = static_cast(u & significand_mask); - int biased_e = - static_cast((u & exponent_mask()) >> - dragonbox::float_info::significand_bits); + int biased_e = static_cast((u & exponent_mask()) >> + detail::num_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; @@ -1021,22 +1008,21 @@ template <> struct cache_accessor { static carrier_uint compute_left_endpoint_for_shorter_interval_case( const cache_entry_type& cache, int beta) noexcept { return static_cast( - (cache - (cache >> (float_info::significand_bits + 2))) >> - (64 - float_info::significand_bits - 1 - beta)); + (cache - (cache >> (num_significand_bits() + 2))) >> + (64 - num_significand_bits() - 1 - beta)); } static carrier_uint compute_right_endpoint_for_shorter_interval_case( const cache_entry_type& cache, int beta) noexcept { return static_cast( - (cache + (cache >> (float_info::significand_bits + 1))) >> - (64 - float_info::significand_bits - 1 - beta)); + (cache + (cache >> (num_significand_bits() + 1))) >> + (64 - num_significand_bits() - 1 - beta)); } static carrier_uint compute_round_up_for_shorter_interval_case( const cache_entry_type& cache, int beta) noexcept { return (static_cast( - cache >> - (64 - float_info::significand_bits - 2 - beta)) + + cache >> (64 - num_significand_bits() - 2 - beta)) + 1) / 2; } @@ -1780,21 +1766,20 @@ template <> struct cache_accessor { static carrier_uint compute_left_endpoint_for_shorter_interval_case( const cache_entry_type& cache, int beta) noexcept { return (cache.high() - - (cache.high() >> (float_info::significand_bits + 2))) >> - (64 - float_info::significand_bits - 1 - beta); + (cache.high() >> (num_significand_bits() + 2))) >> + (64 - num_significand_bits() - 1 - beta); } static carrier_uint compute_right_endpoint_for_shorter_interval_case( const cache_entry_type& cache, int beta) noexcept { return (cache.high() + - (cache.high() >> (float_info::significand_bits + 1))) >> - (64 - float_info::significand_bits - 1 - beta); + (cache.high() >> (num_significand_bits() + 1))) >> + (64 - num_significand_bits() - 1 - beta); } static carrier_uint compute_round_up_for_shorter_interval_case( const cache_entry_type& cache, int beta) noexcept { - return ((cache.high() >> - (64 - float_info::significand_bits - 2 - beta)) + + return ((cache.high() >> (64 - num_significand_bits() - 2 - beta)) + 1) / 2; } @@ -1942,25 +1927,24 @@ template decimal_fp to_decimal(T x) noexcept { // Extract significand bits and exponent bits. const carrier_uint significand_mask = - (static_cast(1) << float_info::significand_bits) - 1; + (static_cast(1) << num_significand_bits()) - 1; carrier_uint significand = (br & significand_mask); - int exponent = static_cast((br & exponent_mask()) >> - float_info::significand_bits); + int exponent = + static_cast((br & exponent_mask()) >> num_significand_bits()); if (exponent != 0) { // Check if normal. - exponent += float_info::exponent_bias - float_info::significand_bits; + exponent += float_info::exponent_bias - num_significand_bits(); // Shorter interval case; proceed like Schubfach. // In fact, when exponent == 1 and significand == 0, the interval is // regular. However, it can be shown that the end-results are anyway same. if (significand == 0) return shorter_interval_case(exponent); - significand |= - (static_cast(1) << float_info::significand_bits); + significand |= (static_cast(1) << num_significand_bits()); } else { // Subnormal case; the interval is always regular. if (significand == 0) return {0, 0}; - exponent = float_info::min_exponent - float_info::significand_bits; + exponent = float_info::min_exponent - num_significand_bits(); } const bool include_left_endpoint = (significand % 2 == 0); diff --git a/include/fmt/format.h b/include/fmt/format.h index 7c469985..4e254ca1 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -1226,7 +1226,6 @@ template struct float_info; template <> struct float_info { using carrier_uint = uint32_t; - static const int significand_bits = 23; static const int exponent_bits = 8; static const int min_exponent = -126; static const int max_exponent = 127; @@ -1249,7 +1248,6 @@ template <> struct float_info { template <> struct float_info { using carrier_uint = uint64_t; - static const int significand_bits = 52; static const int exponent_bits = 11; static const int min_exponent = -1022; static const int max_exponent = 1023; @@ -1275,7 +1273,6 @@ template struct float_info::value && std::numeric_limits::digits == 64>> { using carrier_uint = detail::uint128_t; - static const int significand_bits = 64; static const int exponent_bits = 15; }; @@ -1288,12 +1285,22 @@ template struct decimal_fp { template FMT_API auto to_decimal(T x) noexcept -> decimal_fp; } // namespace dragonbox -template +template constexpr bool has_implicit_bit() { + return std::numeric_limits::digits != 64; +} + +// Returns the number of significand bits in Float excluding the implicit bit. +template constexpr int num_significand_bits() { + return std::numeric_limits::digits - + (has_implicit_bit() ? 1 : 0); +} + +template constexpr auto exponent_mask() -> - typename dragonbox::float_info::carrier_uint { - using uint = typename dragonbox::float_info::carrier_uint; - return ((uint(1) << dragonbox::float_info::exponent_bits) - 1) - << dragonbox::float_info::significand_bits; + typename dragonbox::float_info::carrier_uint { + using uint = typename dragonbox::float_info::carrier_uint; + return ((uint(1) << dragonbox::float_info::exponent_bits) - 1) + << num_significand_bits(); } // Writes the exponent exp in the form "[+-]d{2,3}" to buffer. @@ -2178,11 +2185,9 @@ FMT_CONSTEXPR20 bool isinf(T value) { if (is_constant_evaluated()) { #if defined(__cpp_if_constexpr) if constexpr (std::numeric_limits::is_iec559) { - auto bits = detail::bit_cast(static_cast(value)); - constexpr auto significand_bits = - dragonbox::float_info::significand_bits; + auto bits = bit_cast(static_cast(value)); return (bits & exponent_mask()) && - !(bits & ((uint64_t(1) << significand_bits) - 1)); + !(bits & ((uint64_t(1) << num_significand_bits()) - 1)); } #endif } diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index 72445a68..e71ad194 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -227,13 +227,14 @@ TEST(fp_test, dragonbox_max_k) { using fmt::detail::dragonbox::floor_log10_pow2; using float_info = fmt::detail::dragonbox::float_info; EXPECT_EQ(fmt::detail::const_check(float_info::max_k), - float_info::kappa - floor_log10_pow2(float_info::min_exponent - - float_info::significand_bits)); + float_info::kappa - + floor_log10_pow2(float_info::min_exponent - + fmt::detail::num_significand_bits())); using double_info = fmt::detail::dragonbox::float_info; - EXPECT_EQ( - fmt::detail::const_check(double_info::max_k), - double_info::kappa - floor_log10_pow2(double_info::min_exponent - - double_info::significand_bits)); + EXPECT_EQ(fmt::detail::const_check(double_info::max_k), + double_info::kappa - + floor_log10_pow2(double_info::min_exponent - + fmt::detail::num_significand_bits())); } TEST(fp_test, get_round_direction) {