mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-24 16:42:05 +00:00
Merge pull request #34463 from vdimir/wide_integer_from_builtin_double_multiplier
Use `cpp_bin_float_double` in `set_multiplier` for `wide_integer_from_builtin` for aarch64
This commit is contained in:
commit
ddad064285
@ -12,6 +12,18 @@
|
|||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
|
#include <boost/multiprecision/cpp_bin_float.hpp>
|
||||||
|
#include <boost/math/special_functions/fpclassify.hpp>
|
||||||
|
|
||||||
|
/// Use same extended double for all platforms
|
||||||
|
#if (LDBL_MANT_DIG == 64)
|
||||||
|
#define CONSTEXPR_FROM_DOUBLE constexpr
|
||||||
|
using FromDoubleIntermediateType = long double;
|
||||||
|
#else
|
||||||
|
/// `wide_integer_from_builtin` can't be constexpr with non-literal `cpp_bin_float_double_extended`
|
||||||
|
#define CONSTEXPR_FROM_DOUBLE
|
||||||
|
using FromDoubleIntermediateType = boost::multiprecision::cpp_bin_float_double_extended;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace wide
|
namespace wide
|
||||||
{
|
{
|
||||||
@ -265,12 +277,23 @@ struct integer<Bits, Signed>::_impl
|
|||||||
constexpr static void set_multiplier(integer<Bits, Signed> & self, T t) noexcept
|
constexpr static void set_multiplier(integer<Bits, Signed> & self, T t) noexcept
|
||||||
{
|
{
|
||||||
constexpr uint64_t max_int = std::numeric_limits<uint64_t>::max();
|
constexpr uint64_t max_int = std::numeric_limits<uint64_t>::max();
|
||||||
|
static_assert(std::is_same_v<T, double> || std::is_same_v<T, FromDoubleIntermediateType>);
|
||||||
/// Implementation specific behaviour on overflow (if we don't check here, stack overflow will triggered in bigint_cast).
|
/// Implementation specific behaviour on overflow (if we don't check here, stack overflow will triggered in bigint_cast).
|
||||||
if (!std::isfinite(t))
|
if constexpr (std::is_same_v<T, double>)
|
||||||
{
|
{
|
||||||
self = 0;
|
if (!std::isfinite(t))
|
||||||
return;
|
{
|
||||||
|
self = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!boost::math::isfinite(t))
|
||||||
|
{
|
||||||
|
self = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const T alpha = t / static_cast<T>(max_int);
|
const T alpha = t / static_cast<T>(max_int);
|
||||||
@ -278,13 +301,13 @@ struct integer<Bits, Signed>::_impl
|
|||||||
if (alpha <= static_cast<T>(max_int))
|
if (alpha <= static_cast<T>(max_int))
|
||||||
self = static_cast<uint64_t>(alpha);
|
self = static_cast<uint64_t>(alpha);
|
||||||
else // max(double) / 2^64 will surely contain less than 52 precision bits, so speed up computations.
|
else // max(double) / 2^64 will surely contain less than 52 precision bits, so speed up computations.
|
||||||
set_multiplier<double>(self, alpha);
|
set_multiplier<double>(self, static_cast<double>(alpha));
|
||||||
|
|
||||||
self *= max_int;
|
self *= max_int;
|
||||||
self += static_cast<uint64_t>(t - floor(alpha) * static_cast<T>(max_int)); // += b_i
|
self += static_cast<uint64_t>(t - floor(alpha) * static_cast<T>(max_int)); // += b_i
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr static void wide_integer_from_builtin(integer<Bits, Signed> & self, double rhs) noexcept
|
CONSTEXPR_FROM_DOUBLE static void wide_integer_from_builtin(integer<Bits, Signed> & self, double rhs) noexcept
|
||||||
{
|
{
|
||||||
constexpr int64_t max_int = std::numeric_limits<int64_t>::max();
|
constexpr int64_t max_int = std::numeric_limits<int64_t>::max();
|
||||||
constexpr int64_t min_int = std::numeric_limits<int64_t>::lowest();
|
constexpr int64_t min_int = std::numeric_limits<int64_t>::lowest();
|
||||||
@ -294,24 +317,17 @@ struct integer<Bits, Signed>::_impl
|
|||||||
/// the result may not fit in 64 bits.
|
/// the result may not fit in 64 bits.
|
||||||
/// The example of such a number is 9.22337e+18.
|
/// The example of such a number is 9.22337e+18.
|
||||||
/// As to_Integral does a static_cast to int64_t, it may result in UB.
|
/// As to_Integral does a static_cast to int64_t, it may result in UB.
|
||||||
/// The necessary check here is that long double has enough significant (mantissa) bits to store the
|
/// The necessary check here is that FromDoubleIntermediateType has enough significant (mantissa) bits to store the
|
||||||
/// int64_t max value precisely.
|
/// int64_t max value precisely.
|
||||||
|
|
||||||
// TODO Be compatible with Apple aarch64
|
if (rhs > static_cast<FromDoubleIntermediateType>(min_int) && rhs < static_cast<FromDoubleIntermediateType>(max_int))
|
||||||
#if not (defined(__APPLE__) && defined(__aarch64__))
|
|
||||||
static_assert(LDBL_MANT_DIG >= 64,
|
|
||||||
"On your system long double has less than 64 precision bits, "
|
|
||||||
"which may result in UB when initializing double from int64_t");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (rhs > static_cast<long double>(min_int) && rhs < static_cast<long double>(max_int))
|
|
||||||
{
|
{
|
||||||
self = static_cast<int64_t>(rhs);
|
self = static_cast<int64_t>(rhs);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const long double rhs_long_double = (static_cast<long double>(rhs) < 0)
|
const FromDoubleIntermediateType rhs_long_double = (static_cast<FromDoubleIntermediateType>(rhs) < 0)
|
||||||
? -static_cast<long double>(rhs)
|
? -static_cast<FromDoubleIntermediateType>(rhs)
|
||||||
: rhs;
|
: rhs;
|
||||||
|
|
||||||
set_multiplier(self, rhs_long_double);
|
set_multiplier(self, rhs_long_double);
|
||||||
|
Loading…
Reference in New Issue
Block a user