mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-31 11:17:35 +02:00
Move basic_fp to format.h for compile-time formatting
This commit is contained in:
@ -197,57 +197,6 @@ template <typename T> constexpr int16_t basic_impl_data<T>::pow10_exponents[];
|
|||||||
template <typename T> constexpr uint64_t basic_impl_data<T>::power_of_10_64[];
|
template <typename T> constexpr uint64_t basic_impl_data<T>::power_of_10_64[];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// A floating-point number f * pow(2, e) where F is an unsigned type.
|
|
||||||
template <typename F> struct basic_fp {
|
|
||||||
F f;
|
|
||||||
int e;
|
|
||||||
|
|
||||||
static constexpr const int num_significand_bits =
|
|
||||||
static_cast<int>(sizeof(F) * num_bits<unsigned char>());
|
|
||||||
|
|
||||||
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 <typename Float> FMT_CONSTEXPR basic_fp(Float n) { assign(n); }
|
|
||||||
|
|
||||||
// Assigns n to this and return true iff predecessor is closer than successor.
|
|
||||||
template <typename Float,
|
|
||||||
FMT_ENABLE_IF(std::numeric_limits<Float>::is_iec559)>
|
|
||||||
FMT_CONSTEXPR auto assign(Float n) -> bool {
|
|
||||||
static_assert(std::numeric_limits<Float>::digits <= 113, "unsupported FP");
|
|
||||||
// Assume Float is in the format [sign][exponent][significand].
|
|
||||||
using carrier_uint = typename dragonbox::float_info<Float>::carrier_uint;
|
|
||||||
const auto num_float_significand_bits =
|
|
||||||
detail::num_significand_bits<Float>();
|
|
||||||
const auto implicit_bit = carrier_uint(1) << num_float_significand_bits;
|
|
||||||
const auto significand_mask = implicit_bit - 1;
|
|
||||||
auto u = bit_cast<carrier_uint>(n);
|
|
||||||
f = static_cast<F>(u & significand_mask);
|
|
||||||
auto biased_e = static_cast<int>((u & exponent_mask<Float>()) >>
|
|
||||||
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<Float>())
|
|
||||||
f += static_cast<F>(implicit_bit);
|
|
||||||
e = biased_e - exponent_bias<Float>() - num_float_significand_bits;
|
|
||||||
if (!has_implicit_bit<Float>()) ++e;
|
|
||||||
return is_predecessor_closer;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Float,
|
|
||||||
FMT_ENABLE_IF(!std::numeric_limits<Float>::is_iec559)>
|
|
||||||
FMT_CONSTEXPR auto assign(Float n) -> bool {
|
|
||||||
static_assert(std::numeric_limits<double>::is_iec559, "unsupported FP");
|
|
||||||
return assign(static_cast<double>(n));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
using fp = basic_fp<unsigned long long>;
|
|
||||||
|
|
||||||
// Normalizes the value converted from double and multiplied by (1 << SHIFT).
|
// Normalizes the value converted from double and multiplied by (1 << SHIFT).
|
||||||
template <int SHIFT = 0, typename F>
|
template <int SHIFT = 0, typename F>
|
||||||
FMT_CONSTEXPR basic_fp<F> normalize(basic_fp<F> value) {
|
FMT_CONSTEXPR basic_fp<F> normalize(basic_fp<F> value) {
|
||||||
@ -259,8 +208,8 @@ FMT_CONSTEXPR basic_fp<F> normalize(basic_fp<F> value) {
|
|||||||
--value.e;
|
--value.e;
|
||||||
}
|
}
|
||||||
// Subtract 1 to account for hidden bit.
|
// Subtract 1 to account for hidden bit.
|
||||||
const auto offset =
|
const auto offset = basic_fp<F>::num_significand_bits -
|
||||||
fp::num_significand_bits - num_significand_bits<double>() - SHIFT - 1;
|
num_significand_bits<double>() - SHIFT - 1;
|
||||||
value.f <<= offset;
|
value.f <<= offset;
|
||||||
value.e -= offset;
|
value.e -= offset;
|
||||||
return value;
|
return value;
|
||||||
@ -288,6 +237,8 @@ FMT_CONSTEXPR inline uint64_t multiply(uint64_t lhs, uint64_t rhs) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using fp = basic_fp<unsigned long long>;
|
||||||
|
|
||||||
FMT_CONSTEXPR inline fp operator*(fp x, fp y) {
|
FMT_CONSTEXPR inline fp operator*(fp x, fp y) {
|
||||||
return {multiply(x.f, y.f), x.e + y.e + 64};
|
return {multiply(x.f, y.f), x.e + y.e + 64};
|
||||||
}
|
}
|
||||||
|
@ -1361,6 +1361,55 @@ FMT_CONSTEXPR auto write_exponent(int exp, It it) -> It {
|
|||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A floating-point number f * pow(2, e) where F is an unsigned type.
|
||||||
|
template <typename F> struct basic_fp {
|
||||||
|
F f;
|
||||||
|
int e;
|
||||||
|
|
||||||
|
static constexpr const int num_significand_bits =
|
||||||
|
static_cast<int>(sizeof(F) * num_bits<unsigned char>());
|
||||||
|
|
||||||
|
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 <typename Float> FMT_CONSTEXPR basic_fp(Float n) { assign(n); }
|
||||||
|
|
||||||
|
// Assigns n to this and return true iff predecessor is closer than successor.
|
||||||
|
template <typename Float,
|
||||||
|
FMT_ENABLE_IF(std::numeric_limits<Float>::is_iec559)>
|
||||||
|
FMT_CONSTEXPR auto assign(Float n) -> bool {
|
||||||
|
static_assert(std::numeric_limits<Float>::digits <= 113, "unsupported FP");
|
||||||
|
// Assume Float is in the format [sign][exponent][significand].
|
||||||
|
using carrier_uint = typename dragonbox::float_info<Float>::carrier_uint;
|
||||||
|
const auto num_float_significand_bits =
|
||||||
|
detail::num_significand_bits<Float>();
|
||||||
|
const auto implicit_bit = carrier_uint(1) << num_float_significand_bits;
|
||||||
|
const auto significand_mask = implicit_bit - 1;
|
||||||
|
auto u = bit_cast<carrier_uint>(n);
|
||||||
|
f = static_cast<F>(u & significand_mask);
|
||||||
|
auto biased_e = static_cast<int>((u & exponent_mask<Float>()) >>
|
||||||
|
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<Float>())
|
||||||
|
f += static_cast<F>(implicit_bit);
|
||||||
|
e = biased_e - exponent_bias<Float>() - num_float_significand_bits;
|
||||||
|
if (!has_implicit_bit<Float>()) ++e;
|
||||||
|
return is_predecessor_closer;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Float,
|
||||||
|
FMT_ENABLE_IF(!std::numeric_limits<Float>::is_iec559)>
|
||||||
|
FMT_CONSTEXPR auto assign(Float n) -> bool {
|
||||||
|
static_assert(std::numeric_limits<double>::is_iec559, "unsupported FP");
|
||||||
|
return assign(static_cast<double>(n));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
FMT_HEADER_ONLY_CONSTEXPR20 auto format_float(T value, int precision,
|
FMT_HEADER_ONLY_CONSTEXPR20 auto format_float(T value, int precision,
|
||||||
float_specs specs,
|
float_specs specs,
|
||||||
|
Reference in New Issue
Block a user