From 2b9037a190410ec7c7e4f5a5b1048767eca6904f Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 29 May 2022 07:20:37 -0700 Subject: [PATCH] Move basic_fp to format.h for compile-time formatting --- include/fmt/format-inl.h | 57 +++------------------------------------- include/fmt/format.h | 49 ++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index 9ddbf34a..fcc1d742 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -197,57 +197,6 @@ template constexpr int16_t basic_impl_data::pow10_exponents[]; template constexpr uint64_t basic_impl_data::power_of_10_64[]; #endif -// A floating-point number f * pow(2, e) where F is an unsigned type. -template struct basic_fp { - F f; - int e; - - static constexpr const int num_significand_bits = - static_cast(sizeof(F) * num_bits()); - - constexpr basic_fp() : f(0), e(0) {} - constexpr basic_fp(uint64_t f_val, int e_val) : f(f_val), e(e_val) {} - - // Constructs fp from an IEEE754 floating-point number. - template FMT_CONSTEXPR basic_fp(Float n) { assign(n); } - - // Assigns n to this and return true iff predecessor is closer than successor. - template ::is_iec559)> - FMT_CONSTEXPR auto assign(Float n) -> bool { - static_assert(std::numeric_limits::digits <= 113, "unsupported FP"); - // Assume Float is in the format [sign][exponent][significand]. - using carrier_uint = typename dragonbox::float_info::carrier_uint; - const auto num_float_significand_bits = - detail::num_significand_bits(); - const auto implicit_bit = carrier_uint(1) << num_float_significand_bits; - const auto significand_mask = implicit_bit - 1; - auto u = bit_cast(n); - f = static_cast(u & significand_mask); - auto biased_e = static_cast((u & exponent_mask()) >> - num_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). - auto is_predecessor_closer = f == 0 && biased_e > 1; - 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; - } - - template ::is_iec559)> - FMT_CONSTEXPR auto assign(Float n) -> bool { - static_assert(std::numeric_limits::is_iec559, "unsupported FP"); - return assign(static_cast(n)); - } -}; - -using fp = basic_fp; - // Normalizes the value converted from double and multiplied by (1 << SHIFT). template FMT_CONSTEXPR basic_fp normalize(basic_fp value) { @@ -259,8 +208,8 @@ FMT_CONSTEXPR basic_fp normalize(basic_fp value) { --value.e; } // Subtract 1 to account for hidden bit. - const auto offset = - fp::num_significand_bits - num_significand_bits() - SHIFT - 1; + const auto offset = basic_fp::num_significand_bits - + num_significand_bits() - SHIFT - 1; value.f <<= offset; value.e -= offset; return value; @@ -288,6 +237,8 @@ FMT_CONSTEXPR inline uint64_t multiply(uint64_t lhs, uint64_t rhs) { #endif } +using fp = basic_fp; + FMT_CONSTEXPR inline fp operator*(fp x, fp y) { return {multiply(x.f, y.f), x.e + y.e + 64}; } diff --git a/include/fmt/format.h b/include/fmt/format.h index fdb2cf44..610a99c5 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -1361,6 +1361,55 @@ FMT_CONSTEXPR auto write_exponent(int exp, It it) -> It { return it; } +// A floating-point number f * pow(2, e) where F is an unsigned type. +template struct basic_fp { + F f; + int e; + + static constexpr const int num_significand_bits = + static_cast(sizeof(F) * num_bits()); + + constexpr basic_fp() : f(0), e(0) {} + constexpr basic_fp(uint64_t f_val, int e_val) : f(f_val), e(e_val) {} + + // Constructs fp from an IEEE754 floating-point number. + template FMT_CONSTEXPR basic_fp(Float n) { assign(n); } + + // Assigns n to this and return true iff predecessor is closer than successor. + template ::is_iec559)> + FMT_CONSTEXPR auto assign(Float n) -> bool { + static_assert(std::numeric_limits::digits <= 113, "unsupported FP"); + // Assume Float is in the format [sign][exponent][significand]. + using carrier_uint = typename dragonbox::float_info::carrier_uint; + const auto num_float_significand_bits = + detail::num_significand_bits(); + const auto implicit_bit = carrier_uint(1) << num_float_significand_bits; + const auto significand_mask = implicit_bit - 1; + auto u = bit_cast(n); + f = static_cast(u & significand_mask); + auto biased_e = static_cast((u & exponent_mask()) >> + num_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). + auto is_predecessor_closer = f == 0 && biased_e > 1; + 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; + } + + template ::is_iec559)> + FMT_CONSTEXPR auto assign(Float n) -> bool { + static_assert(std::numeric_limits::is_iec559, "unsupported FP"); + return assign(static_cast(n)); + } +}; + template FMT_HEADER_ONLY_CONSTEXPR20 auto format_float(T value, int precision, float_specs specs,