mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-29 11:02:08 +00:00
improved the wide int constructor
This commit is contained in:
parent
a8d8dd7d3e
commit
37c70f4f6a
@ -228,58 +228,39 @@ struct integer<Bits, Signed>::_impl
|
||||
self.items[i] = 0;
|
||||
}
|
||||
|
||||
constexpr static void wide_integer_from_bultin(integer<Bits, Signed> & self, double rhs) noexcept
|
||||
{
|
||||
/**
|
||||
* N.B. t is constructed from double, so max(t) = max(double) ~ 2^310
|
||||
* the recursive call happens when t / 2^64 > 2^64, so there won't be more than 5 of them.
|
||||
*/
|
||||
template <class T>
|
||||
constexpr static void set_multiplier(wide_integer<Bits, Signed> & self, T t) noexcept {
|
||||
constexpr uint64_t max_int = std::numeric_limits<uint64_t>::max();
|
||||
const T alpha = t / max_int;
|
||||
|
||||
if (alpha <= max_int)
|
||||
for (uint64_t i = 0; i < static_cast<uint64_t>(alpha); ++i)
|
||||
self *= max_int;
|
||||
else // max(double) / 2^64 will surely contain less than 52 precision bits, so speed up computations.
|
||||
set_multiplier(self, static_cast<double>(alpha));
|
||||
|
||||
self += static_cast<uint64_t>(t - alpha * max_int);
|
||||
}
|
||||
|
||||
constexpr static void wide_integer_from_bultin(wide_integer<Bits, Signed>& self, double rhs) noexcept {
|
||||
constexpr int64_t max_int = std::numeric_limits<int64_t>::max();
|
||||
constexpr int64_t min_int = std::numeric_limits<int64_t>::min();
|
||||
|
||||
constexpr long double max_int_long_double = static_cast<long double>(max_int);
|
||||
|
||||
if ((rhs > 0 && rhs < max_int) ||
|
||||
(rhs < 0 && rhs > min_int))
|
||||
{
|
||||
self = to_Integral(rhs);
|
||||
if ((rhs > 0 && rhs < max_int) || (rhs < 0 && rhs > min_int)) {
|
||||
self = static_cast<int64_t>(rhs);
|
||||
return;
|
||||
}
|
||||
|
||||
/// There are values in int64 that have more than 53 significant bits (in terms of double
|
||||
/// representation). Such values, being promoted to double, are rounded up or down. If they are rounded up,
|
||||
/// 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
|
||||
/// int64_t max value precisely.
|
||||
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");
|
||||
|
||||
/// Always >= 0
|
||||
const long double rhs_long_double = (static_cast<long double>(rhs) < 0)
|
||||
? -static_cast<long double>(rhs)
|
||||
: rhs;
|
||||
|
||||
const long double rhs_max_int_count = rhs_long_double / max_int;
|
||||
|
||||
// We can't just get the number of iterations like rhs_max_int_count / max_int as it may not fit it int64_t.
|
||||
long double rhs_max_int_count_acc = rhs_max_int_count;
|
||||
|
||||
self = 0;
|
||||
|
||||
while (rhs_max_int_count_acc > max_int_long_double)
|
||||
{
|
||||
self += max_int;
|
||||
rhs_max_int_count_acc -= max_int_long_double;
|
||||
}
|
||||
|
||||
self *= max_int;
|
||||
|
||||
const long double rhs_div_max_int = rhs_max_int_count * max_int;
|
||||
const long double rhs_mod_max_int = rhs_long_double - rhs_div_max_int;
|
||||
|
||||
assert(rhs_mod_max_int < max_int_long_double);
|
||||
assert(rhs_mod_max_int > static_cast<long double>(min_int));
|
||||
|
||||
self += static_cast<int64_t>(rhs_mod_max_int);
|
||||
set_multiplier(self, rhs_long_double);
|
||||
|
||||
if (rhs < 0)
|
||||
self = -self;
|
||||
|
Loading…
Reference in New Issue
Block a user