Add 80-bit fast-path

This commit is contained in:
Matt Borland
2023-06-21 13:59:03 +02:00
parent 038b885581
commit 19b79fc326

View File

@@ -12,6 +12,68 @@
namespace boost { namespace charconv { namespace detail {
static constexpr long double powers_of_ten[] = {
1e0L, 1e1L, 1e2L, 1e3L, 1e4L, 1e5L, 1e6L,
1e7L, 1e8L, 1e9L, 1e10L, 1e11L, 1e12L, 1e13L,
1e14L, 1e15L, 1e16L, 1e17L, 1e18L, 1e19L, 1e20L,
1e21L, 1e22L, 1e23L, 1e24L, 1e25L, 1e26L, 1e27L
};
template <typename Unsigned_Integer>
inline long double compute_float80(std::int64_t power, Unsigned_Integer i, bool negative, bool& success) noexcept
{
// GLIBC uses 2^-16444 but MPFR uses 2^-16445 as the smallest subnormal value for 80 bit
static constexpr auto smallest_power = -4951;
static constexpr auto largest_power = 4931;
// We start with a fast path
// It is an extension of what was described in Clinger WD.
// How to read floating point numbers accurately.
// ACM SIGPLAN Notices. 1990
// https://dl.acm.org/doi/pdf/10.1145/93542.93557
#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0)
if (0 <= power && power <= 27 && i <= static_cast<Unsigned_Integer>(1) << 64)
#else
if (-27 <= power && power <= 27 && i <= static_cast<Unsigned_Integer>(1) << 64)
#endif
{
// The general idea is as follows.
// if 0 <= s <= 2^64 and if 10^0 <= p <= 10^27
// Both s and p can be represented exactly
// because of this s*p and s/p will produce
// correctly rounded values
auto ld = static_cast<long double>(i);
if (power < 0)
{
ld /= powers_of_ten[-power];
}
else
{
ld *= powers_of_ten[power];
}
if (negative)
{
ld = -ld;
}
success = true;
return ld;
}
if (i == 0 || power < smallest_power)
{
return negative ? -0.0L : 0.0L;
}
else if (power > largest_power)
{
return negative ? -HUGE_VALL : HUGE_VALL;
}
}
/*
inline long double compute_float80(std::int64_t power, std::uint64_t i, bool negative, bool& success) noexcept
{
long double return_val;
@@ -40,7 +102,7 @@ inline long double compute_float80(std::int64_t power, std::uint64_t i, bool neg
success = true;
return return_val;
}
*/
}}} // Namespaces
#endif // BOOST_CHARCONV_DETAIL_COMPUTE_FLOAT80_HPP