mirror of
https://github.com/fmtlib/fmt.git
synced 2024-10-06 06:50:00 +00:00
Add initial double-double support
This commit is contained in:
parent
147e8ca580
commit
c6324009ba
@ -216,11 +216,10 @@ template <typename F> struct basic_fp {
|
|||||||
template <typename Float> FMT_CONSTEXPR basic_fp(Float n) { assign(n); }
|
template <typename Float> FMT_CONSTEXPR basic_fp(Float n) { assign(n); }
|
||||||
|
|
||||||
// Assigns n to this and return true iff predecessor is closer than successor.
|
// Assigns n to this and return true iff predecessor is closer than successor.
|
||||||
template <typename Float> FMT_CONSTEXPR auto assign(Float n) -> bool {
|
template <typename Float,
|
||||||
static_assert((std::numeric_limits<Float>::is_iec559 &&
|
FMT_ENABLE_IF(std::numeric_limits<Float>::is_iec559)>
|
||||||
std::numeric_limits<Float>::digits <= 113) ||
|
FMT_CONSTEXPR auto assign(Float n) -> bool {
|
||||||
is_float128<Float>::value,
|
static_assert(std::numeric_limits<Float>::digits <= 113, "unsupported FP");
|
||||||
"unsupported FP");
|
|
||||||
// Assume Float is in the format [sign][exponent][significand].
|
// Assume Float is in the format [sign][exponent][significand].
|
||||||
using carrier_uint = typename dragonbox::float_info<Float>::carrier_uint;
|
using carrier_uint = typename dragonbox::float_info<Float>::carrier_uint;
|
||||||
const auto num_float_significand_bits =
|
const auto num_float_significand_bits =
|
||||||
@ -231,8 +230,8 @@ template <typename F> struct basic_fp {
|
|||||||
f = static_cast<F>(u & significand_mask);
|
f = static_cast<F>(u & significand_mask);
|
||||||
auto biased_e = static_cast<int>((u & exponent_mask<Float>()) >>
|
auto biased_e = static_cast<int>((u & exponent_mask<Float>()) >>
|
||||||
num_float_significand_bits);
|
num_float_significand_bits);
|
||||||
// The predecessor is closer if n is a normalized power of 2 (f == 0) other
|
// The predecessor is closer if n is a normalized power of 2 (f == 0)
|
||||||
// than the smallest normalized number (biased_e > 1).
|
// other than the smallest normalized number (biased_e > 1).
|
||||||
auto is_predecessor_closer = f == 0 && biased_e > 1;
|
auto is_predecessor_closer = f == 0 && biased_e > 1;
|
||||||
if (biased_e == 0)
|
if (biased_e == 0)
|
||||||
biased_e = 1; // Subnormals use biased exponent 1 (min exponent).
|
biased_e = 1; // Subnormals use biased exponent 1 (min exponent).
|
||||||
@ -242,6 +241,13 @@ template <typename F> struct basic_fp {
|
|||||||
if (!has_implicit_bit<Float>()) ++e;
|
if (!has_implicit_bit<Float>()) ++e;
|
||||||
return is_predecessor_closer;
|
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>;
|
using fp = basic_fp<unsigned long long>;
|
||||||
|
@ -990,11 +990,12 @@ constexpr auto is_negative(T) -> bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> constexpr auto is_supported_floating_point(T) -> bool {
|
template <typename T>
|
||||||
return (std::is_same<T, float>() && FMT_USE_FLOAT) ||
|
FMT_CONSTEXPR auto is_supported_floating_point(T) -> bool {
|
||||||
(std::is_same<T, double>() && FMT_USE_DOUBLE) ||
|
if (std::is_same<T, float>()) return FMT_USE_FLOAT;
|
||||||
(std::is_same<T, long double>() && FMT_USE_LONG_DOUBLE) ||
|
if (std::is_same<T, double>()) return FMT_USE_DOUBLE;
|
||||||
is_float128<T>();
|
if (std::is_same<T, long double>()) return FMT_USE_LONG_DOUBLE;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Smallest of uint32_t, uint64_t, uint128_t that is large enough to
|
// Smallest of uint32_t, uint64_t, uint128_t that is large enough to
|
||||||
@ -2345,14 +2346,14 @@ template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value&&
|
|||||||
FMT_CONSTEXPR20 bool isfinite(T value) {
|
FMT_CONSTEXPR20 bool isfinite(T value) {
|
||||||
constexpr T inf = T(std::numeric_limits<double>::infinity());
|
constexpr T inf = T(std::numeric_limits<double>::infinity());
|
||||||
if (is_constant_evaluated())
|
if (is_constant_evaluated())
|
||||||
return !isnan(value) && value != inf && value != -inf;
|
return !detail::isnan(value) && value != inf && value != -inf;
|
||||||
return std::isfinite(value);
|
return std::isfinite(value);
|
||||||
}
|
}
|
||||||
template <typename T, FMT_ENABLE_IF(!has_isfinite<T>::value)>
|
template <typename T, FMT_ENABLE_IF(!has_isfinite<T>::value)>
|
||||||
FMT_CONSTEXPR bool isfinite(T value) {
|
FMT_CONSTEXPR bool isfinite(T value) {
|
||||||
T inf = T(std::numeric_limits<double>::infinity());
|
T inf = T(std::numeric_limits<double>::infinity());
|
||||||
// std::isfinite doesn't support __float128.
|
// std::isfinite doesn't support __float128.
|
||||||
return !isnan(value) && value != inf && value != -inf;
|
return !detail::isnan(value) && value != inf && value != -inf;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(is_floating_point<T>::value)>
|
template <typename T, FMT_ENABLE_IF(is_floating_point<T>::value)>
|
||||||
|
@ -361,6 +361,37 @@ TEST(format_impl_test, write_float128) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct double_double {
|
||||||
|
double a;
|
||||||
|
double b;
|
||||||
|
|
||||||
|
explicit constexpr double_double(double a_val = 0, double b_val = 0)
|
||||||
|
: a(a_val), b(b_val) {}
|
||||||
|
|
||||||
|
operator double() const { return a + b; }
|
||||||
|
auto operator-() const -> double_double { return double_double(-a, -b); }
|
||||||
|
};
|
||||||
|
|
||||||
|
bool operator>=(const double_double& lhs, const double_double& rhs) {
|
||||||
|
return lhs.a + lhs.b >= rhs.a + rhs.b;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
template <> struct is_floating_point<double_double> : std::true_type {};
|
||||||
|
template <> struct numeric_limits<double_double> {
|
||||||
|
static constexpr bool is_iec559 = false;
|
||||||
|
static constexpr int digits = 106;
|
||||||
|
};
|
||||||
|
} // namespace std
|
||||||
|
|
||||||
|
TEST(format_impl_test, write_double_double) {
|
||||||
|
auto s = std::string();
|
||||||
|
fmt::detail::write<char>(std::back_inserter(s), double_double(42), {});
|
||||||
|
#ifndef _MSC_VER // MSVC has an issue with specializing is_floating_point.
|
||||||
|
EXPECT_EQ(s, "42");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user