diff --git a/base/base/wide_integer_impl.h b/base/base/wide_integer_impl.h index ec146fd5821..ed2c2972cfe 100644 --- a/base/base/wide_integer_impl.h +++ b/base/base/wide_integer_impl.h @@ -12,6 +12,18 @@ #include #include +#include +#include + +/// 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 { @@ -265,12 +277,23 @@ struct integer::_impl constexpr static void set_multiplier(integer & self, T t) noexcept { constexpr uint64_t max_int = std::numeric_limits::max(); - + static_assert(std::is_same_v || std::is_same_v); /// 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) { - self = 0; - return; + if (!std::isfinite(t)) + { + self = 0; + return; + } + } + else + { + if (!boost::math::isfinite(t)) + { + self = 0; + return; + } } const T alpha = t / static_cast(max_int); @@ -278,13 +301,13 @@ struct integer::_impl if (alpha <= static_cast(max_int)) self = static_cast(alpha); else // max(double) / 2^64 will surely contain less than 52 precision bits, so speed up computations. - set_multiplier(self, alpha); + set_multiplier(self, static_cast(alpha)); self *= max_int; self += static_cast(t - floor(alpha) * static_cast(max_int)); // += b_i } - constexpr static void wide_integer_from_builtin(integer & self, double rhs) noexcept + CONSTEXPR_FROM_DOUBLE static void wide_integer_from_builtin(integer & self, double rhs) noexcept { constexpr int64_t max_int = std::numeric_limits::max(); constexpr int64_t min_int = std::numeric_limits::lowest(); @@ -294,24 +317,17 @@ struct integer::_impl /// the result may not fit in 64 bits. /// 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. - /// 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. - // TODO Be compatible with Apple aarch64 -#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(min_int) && rhs < static_cast(max_int)) + if (rhs > static_cast(min_int) && rhs < static_cast(max_int)) { self = static_cast(rhs); return; } - const long double rhs_long_double = (static_cast(rhs) < 0) - ? -static_cast(rhs) + const FromDoubleIntermediateType rhs_long_double = (static_cast(rhs) < 0) + ? -static_cast(rhs) : rhs; set_multiplier(self, rhs_long_double);