From d274125c74c4784b461e938a92c0afd2cb2e9b41 Mon Sep 17 00:00:00 2001 From: Artem Zuikov Date: Mon, 14 Sep 2020 14:56:43 +0300 Subject: [PATCH] Fix wide integer left shift + refactoring (#14697) --- base/common/throwError.h | 13 + base/common/types.h | 10 +- base/common/wide_integer.h | 134 ++--- base/common/wide_integer_impl.h | 477 +++++++++--------- base/common/wide_integer_to_string.h | 35 ++ src/IO/WriteHelpers.h | 7 + .../01475_fix_bigint_shift.reference | 2 + .../0_stateless/01475_fix_bigint_shift.sql | 2 + 8 files changed, 366 insertions(+), 314 deletions(-) create mode 100644 base/common/throwError.h create mode 100644 base/common/wide_integer_to_string.h create mode 100644 tests/queries/0_stateless/01475_fix_bigint_shift.reference create mode 100644 tests/queries/0_stateless/01475_fix_bigint_shift.sql diff --git a/base/common/throwError.h b/base/common/throwError.h new file mode 100644 index 00000000000..b495a0fbc7a --- /dev/null +++ b/base/common/throwError.h @@ -0,0 +1,13 @@ +#pragma once +#include + +/// Throw DB::Exception-like exception before its definition. +/// DB::Exception derived from Poco::Exception derived from std::exception. +/// DB::Exception generally cought as Poco::Exception. std::exception generally has other catch blocks and could lead to other outcomes. +/// DB::Exception is not defined yet. It'd better to throw Poco::Exception but we do not want to include any big header here, even . +/// So we throw some std::exception instead in the hope its catch block is the same as DB::Exception one. +template +inline void throwError(const T & err) +{ + throw std::runtime_error(err); +} diff --git a/base/common/types.h b/base/common/types.h index a02398a3365..2982781ce1f 100644 --- a/base/common/types.h +++ b/base/common/types.h @@ -23,8 +23,8 @@ using UInt64 = uint64_t; using Int128 = __int128; -using wInt256 = std::wide_integer<256, signed>; -using wUInt256 = std::wide_integer<256, unsigned>; +using wInt256 = wide::integer<256, signed>; +using wUInt256 = wide::integer<256, unsigned>; static_assert(sizeof(wInt256) == 32); static_assert(sizeof(wUInt256) == 32); @@ -119,12 +119,6 @@ template <> struct is_big_int { static constexpr bool value = true; }; template inline constexpr bool is_big_int_v = is_big_int::value; -template -inline std::string bigintToString(const T & x) -{ - return to_string(x); -} - template inline To bigint_cast(const From & x [[maybe_unused]]) { diff --git a/base/common/wide_integer.h b/base/common/wide_integer.h index 67d0b3f04da..2aeac072b3f 100644 --- a/base/common/wide_integer.h +++ b/base/common/wide_integer.h @@ -22,79 +22,87 @@ * without express or implied warranty. */ -#include // CHAR_BIT -#include #include #include #include +#include + +namespace wide +{ +template +class integer; +} namespace std { -template -class wide_integer; template -struct common_type, wide_integer>; +struct common_type, wide::integer>; template -struct common_type, Arithmetic>; +struct common_type, Arithmetic>; template -struct common_type>; +struct common_type>; + +} + +namespace wide +{ template -class wide_integer +class integer { public: using base_type = uint8_t; using signed_base_type = int8_t; // ctors - wide_integer() = default; + integer() = default; template - constexpr wide_integer(T rhs) noexcept; + constexpr integer(T rhs) noexcept; template - constexpr wide_integer(std::initializer_list il) noexcept; + constexpr integer(std::initializer_list il) noexcept; // assignment template - constexpr wide_integer & operator=(const wide_integer & rhs) noexcept; + constexpr integer & operator=(const integer & rhs) noexcept; template - constexpr wide_integer & operator=(Arithmetic rhs) noexcept; + constexpr integer & operator=(Arithmetic rhs) noexcept; template - constexpr wide_integer & operator*=(const Arithmetic & rhs); + constexpr integer & operator*=(const Arithmetic & rhs); template - constexpr wide_integer & operator/=(const Arithmetic & rhs); + constexpr integer & operator/=(const Arithmetic & rhs); template - constexpr wide_integer & operator+=(const Arithmetic & rhs) noexcept(is_same::value); + constexpr integer & operator+=(const Arithmetic & rhs) noexcept(std::is_same_v); template - constexpr wide_integer & operator-=(const Arithmetic & rhs) noexcept(is_same::value); + constexpr integer & operator-=(const Arithmetic & rhs) noexcept(std::is_same_v); template - constexpr wide_integer & operator%=(const Integral & rhs); + constexpr integer & operator%=(const Integral & rhs); template - constexpr wide_integer & operator&=(const Integral & rhs) noexcept; + constexpr integer & operator&=(const Integral & rhs) noexcept; template - constexpr wide_integer & operator|=(const Integral & rhs) noexcept; + constexpr integer & operator|=(const Integral & rhs) noexcept; template - constexpr wide_integer & operator^=(const Integral & rhs) noexcept; + constexpr integer & operator^=(const Integral & rhs) noexcept; - constexpr wide_integer & operator<<=(int n); - constexpr wide_integer & operator>>=(int n) noexcept; + constexpr integer & operator<<=(int n) noexcept; + constexpr integer & operator>>=(int n) noexcept; - constexpr wide_integer & operator++() noexcept(is_same::value); - constexpr wide_integer operator++(int) noexcept(is_same::value); - constexpr wide_integer & operator--() noexcept(is_same::value); - constexpr wide_integer operator--(int) noexcept(is_same::value); + constexpr integer & operator++() noexcept(std::is_same_v); + constexpr integer operator++(int) noexcept(std::is_same_v); + constexpr integer & operator--() noexcept(std::is_same_v); + constexpr integer operator--(int) noexcept(std::is_same_v); // observers @@ -114,10 +122,10 @@ public: private: template - friend class wide_integer; + friend class integer; - friend class numeric_limits>; - friend class numeric_limits>; + friend class std::numeric_limits>; + friend class std::numeric_limits>; base_type m_arr[_impl::arr_size]; }; @@ -134,115 +142,117 @@ using __only_integer = typename std::enable_if() && IntegralC // Unary operators template -constexpr wide_integer operator~(const wide_integer & lhs) noexcept; +constexpr integer operator~(const integer & lhs) noexcept; template -constexpr wide_integer operator-(const wide_integer & lhs) noexcept(is_same::value); +constexpr integer operator-(const integer & lhs) noexcept(std::is_same_v); template -constexpr wide_integer operator+(const wide_integer & lhs) noexcept(is_same::value); +constexpr integer operator+(const integer & lhs) noexcept(std::is_same_v); // Binary operators template -std::common_type_t, wide_integer> constexpr -operator*(const wide_integer & lhs, const wide_integer & rhs); +std::common_type_t, integer> constexpr +operator*(const integer & lhs, const integer & rhs); template > std::common_type_t constexpr operator*(const Arithmetic & rhs, const Arithmetic2 & lhs); template -std::common_type_t, wide_integer> constexpr -operator/(const wide_integer & lhs, const wide_integer & rhs); +std::common_type_t, integer> constexpr +operator/(const integer & lhs, const integer & rhs); template > std::common_type_t constexpr operator/(const Arithmetic & rhs, const Arithmetic2 & lhs); template -std::common_type_t, wide_integer> constexpr -operator+(const wide_integer & lhs, const wide_integer & rhs); +std::common_type_t, integer> constexpr +operator+(const integer & lhs, const integer & rhs); template > std::common_type_t constexpr operator+(const Arithmetic & rhs, const Arithmetic2 & lhs); template -std::common_type_t, wide_integer> constexpr -operator-(const wide_integer & lhs, const wide_integer & rhs); +std::common_type_t, integer> constexpr +operator-(const integer & lhs, const integer & rhs); template > std::common_type_t constexpr operator-(const Arithmetic & rhs, const Arithmetic2 & lhs); template -std::common_type_t, wide_integer> constexpr -operator%(const wide_integer & lhs, const wide_integer & rhs); +std::common_type_t, integer> constexpr +operator%(const integer & lhs, const integer & rhs); template > std::common_type_t constexpr operator%(const Integral & rhs, const Integral2 & lhs); template -std::common_type_t, wide_integer> constexpr -operator&(const wide_integer & lhs, const wide_integer & rhs); +std::common_type_t, integer> constexpr +operator&(const integer & lhs, const integer & rhs); template > std::common_type_t constexpr operator&(const Integral & rhs, const Integral2 & lhs); template -std::common_type_t, wide_integer> constexpr -operator|(const wide_integer & lhs, const wide_integer & rhs); +std::common_type_t, integer> constexpr +operator|(const integer & lhs, const integer & rhs); template > std::common_type_t constexpr operator|(const Integral & rhs, const Integral2 & lhs); template -std::common_type_t, wide_integer> constexpr -operator^(const wide_integer & lhs, const wide_integer & rhs); +std::common_type_t, integer> constexpr +operator^(const integer & lhs, const integer & rhs); template > std::common_type_t constexpr operator^(const Integral & rhs, const Integral2 & lhs); // TODO: Integral template -constexpr wide_integer operator<<(const wide_integer & lhs, int n) noexcept; +constexpr integer operator<<(const integer & lhs, int n) noexcept; template -constexpr wide_integer operator>>(const wide_integer & lhs, int n) noexcept; +constexpr integer operator>>(const integer & lhs, int n) noexcept; template >> -constexpr wide_integer operator<<(const wide_integer & lhs, Int n) noexcept +constexpr integer operator<<(const integer & lhs, Int n) noexcept { return lhs << int(n); } template >> -constexpr wide_integer operator>>(const wide_integer & lhs, Int n) noexcept +constexpr integer operator>>(const integer & lhs, Int n) noexcept { return lhs >> int(n); } template -constexpr bool operator<(const wide_integer & lhs, const wide_integer & rhs); +constexpr bool operator<(const integer & lhs, const integer & rhs); template > constexpr bool operator<(const Arithmetic & rhs, const Arithmetic2 & lhs); template -constexpr bool operator>(const wide_integer & lhs, const wide_integer & rhs); +constexpr bool operator>(const integer & lhs, const integer & rhs); template > constexpr bool operator>(const Arithmetic & rhs, const Arithmetic2 & lhs); template -constexpr bool operator<=(const wide_integer & lhs, const wide_integer & rhs); +constexpr bool operator<=(const integer & lhs, const integer & rhs); template > constexpr bool operator<=(const Arithmetic & rhs, const Arithmetic2 & lhs); template -constexpr bool operator>=(const wide_integer & lhs, const wide_integer & rhs); +constexpr bool operator>=(const integer & lhs, const integer & rhs); template > constexpr bool operator>=(const Arithmetic & rhs, const Arithmetic2 & lhs); template -constexpr bool operator==(const wide_integer & lhs, const wide_integer & rhs); +constexpr bool operator==(const integer & lhs, const integer & rhs); template > constexpr bool operator==(const Arithmetic & rhs, const Arithmetic2 & lhs); template -constexpr bool operator!=(const wide_integer & lhs, const wide_integer & rhs); +constexpr bool operator!=(const integer & lhs, const integer & rhs); template > constexpr bool operator!=(const Arithmetic & rhs, const Arithmetic2 & lhs); -template -std::string to_string(const wide_integer & n); +} + +namespace std +{ template -struct hash>; +struct hash>; } diff --git a/base/common/wide_integer_impl.h b/base/common/wide_integer_impl.h index c77a9120a55..26bd6704bdc 100644 --- a/base/common/wide_integer_impl.h +++ b/base/common/wide_integer_impl.h @@ -1,19 +1,47 @@ /// Original is here https://github.com/cerevra/int #pragma once -#include "wide_integer.h" +#include "throwError.h" -#include -#include +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif + +namespace wide +{ + +template +struct IsWideInteger +{ + static const constexpr bool value = false; +}; + +template +struct IsWideInteger> +{ + static const constexpr bool value = true; +}; + +template +static constexpr bool ArithmeticConcept() noexcept +{ + return std::is_arithmetic_v || IsWideInteger::value; +} + +template +static constexpr bool IntegralConcept() noexcept +{ + return std::is_integral_v || IsWideInteger::value; +} + +} namespace std { -#define CT(x) \ - std::common_type_t, std::decay_t> { x } // numeric limits template -class numeric_limits> +class numeric_limits> { public: static constexpr bool is_specialized = true; @@ -40,103 +68,84 @@ public: static constexpr bool traps = true; static constexpr bool tinyness_before = false; - static constexpr wide_integer min() noexcept + static constexpr wide::integer min() noexcept { if (is_same::value) { - using T = wide_integer; + using T = wide::integer; T res{}; - res.m_arr[T::_impl::big(0)] = std::numeric_limits::signed_base_type>::min(); + res.m_arr[T::_impl::big(0)] = std::numeric_limits::signed_base_type>::min(); return res; } return 0; } - static constexpr wide_integer max() noexcept + static constexpr wide::integer max() noexcept { - using T = wide_integer; + using T = wide::integer; T res{}; res.m_arr[T::_impl::big(0)] = is_same::value - ? std::numeric_limits::signed_base_type>::max() - : std::numeric_limits::base_type>::max(); - for (int i = 1; i < wide_integer::_impl::arr_size; ++i) + ? std::numeric_limits::signed_base_type>::max() + : std::numeric_limits::base_type>::max(); + for (int i = 1; i < wide::integer::_impl::arr_size; ++i) { - res.m_arr[T::_impl::big(i)] = std::numeric_limits::base_type>::max(); + res.m_arr[T::_impl::big(i)] = std::numeric_limits::base_type>::max(); } return res; } - static constexpr wide_integer lowest() noexcept { return min(); } - static constexpr wide_integer epsilon() noexcept { return 0; } - static constexpr wide_integer round_error() noexcept { return 0; } - static constexpr wide_integer infinity() noexcept { return 0; } - static constexpr wide_integer quiet_NaN() noexcept { return 0; } - static constexpr wide_integer signaling_NaN() noexcept { return 0; } - static constexpr wide_integer denorm_min() noexcept { return 0; } + static constexpr wide::integer lowest() noexcept { return min(); } + static constexpr wide::integer epsilon() noexcept { return 0; } + static constexpr wide::integer round_error() noexcept { return 0; } + static constexpr wide::integer infinity() noexcept { return 0; } + static constexpr wide::integer quiet_NaN() noexcept { return 0; } + static constexpr wide::integer signaling_NaN() noexcept { return 0; } + static constexpr wide::integer denorm_min() noexcept { return 0; } }; -template -struct IsWideInteger -{ - static const constexpr bool value = false; -}; - -template -struct IsWideInteger> -{ - static const constexpr bool value = true; -}; - -template -static constexpr bool ArithmeticConcept() noexcept -{ - return std::is_arithmetic_v || IsWideInteger::value; -} - -template -static constexpr bool IntegralConcept() noexcept -{ - return std::is_integral_v || IsWideInteger::value; -} - // type traits template -struct common_type, wide_integer> +struct common_type, wide::integer> { using type = std::conditional_t < Bits == Bits2, - wide_integer< + wide::integer< Bits, - std::conditional_t<(std::is_same::value && std::is_same::value), signed, unsigned>>, - std::conditional_t, wide_integer>>; + std::conditional_t<(std::is_same_v && std::is_same_v), signed, unsigned>>, + std::conditional_t, wide::integer>>; }; template -struct common_type, Arithmetic> +struct common_type, Arithmetic> { - static_assert(ArithmeticConcept(), ""); + static_assert(wide::ArithmeticConcept()); using type = std::conditional_t< - std::is_floating_point::value, + std::is_floating_point_v, Arithmetic, std::conditional_t< sizeof(Arithmetic) < Bits * sizeof(long), - wide_integer, + wide::integer, std::conditional_t< Bits * sizeof(long) < sizeof(Arithmetic), Arithmetic, std::conditional_t< - Bits * sizeof(long) == sizeof(Arithmetic) && (is_same::value || std::is_signed::value), + Bits * sizeof(long) == sizeof(Arithmetic) && (std::is_same_v || std::is_signed_v), Arithmetic, - wide_integer>>>>; + wide::integer>>>>; }; template -struct common_type> : std::common_type, Arithmetic> +struct common_type> : common_type, Arithmetic> { }; +} + +namespace wide +{ + template -struct wide_integer::_impl +struct integer::_impl { static_assert(Bits % CHAR_BIT == 0, "=)"); @@ -152,7 +161,7 @@ struct wide_integer::_impl static constexpr unsigned any(unsigned idx) { return idx; } template - constexpr static bool is_negative(const wide_integer & n) noexcept + constexpr static bool is_negative(const integer & n) noexcept { if constexpr (std::is_same_v) return static_cast(n.m_arr[big(0)]) < 0; @@ -161,7 +170,7 @@ struct wide_integer::_impl } template - constexpr static wide_integer make_positive(const wide_integer & n) noexcept + constexpr static integer make_positive(const integer & n) noexcept { return is_negative(n) ? operator_unary_minus(n) : n; } @@ -178,7 +187,7 @@ struct wide_integer::_impl } template - constexpr static void wide_integer_from_bultin(wide_integer & self, Integral rhs) noexcept + constexpr static void wide_integer_from_bultin(integer & self, Integral rhs) noexcept { auto r = _impl::to_Integral(rhs); @@ -197,7 +206,7 @@ struct wide_integer::_impl } } - constexpr static void wide_integer_from_bultin(wide_integer & self, double rhs) noexcept + constexpr static void wide_integer_from_bultin(integer & self, double rhs) noexcept { if ((rhs > 0 && rhs < std::numeric_limits::max()) || (rhs < 0 && rhs > std::numeric_limits::min())) { @@ -223,10 +232,10 @@ struct wide_integer::_impl template constexpr static void - wide_integer_from_wide_integer(wide_integer & self, const wide_integer & rhs) noexcept + wide_integer_from_wide_integer(integer & self, const integer & rhs) noexcept { // int Bits_to_copy = std::min(arr_size, rhs.arr_size); - auto rhs_arr_size = wide_integer::_impl::arr_size; + auto rhs_arr_size = integer::_impl::arr_size; int base_elems_to_copy = _impl::arr_size < rhs_arr_size ? _impl::arr_size : rhs_arr_size; for (int i = 0; i < base_elems_to_copy; ++i) { @@ -244,14 +253,14 @@ struct wide_integer::_impl return sizeof(T) * CHAR_BIT <= Bits; } - constexpr static wide_integer shift_left(const wide_integer & rhs, int n) + constexpr static integer shift_left(const integer & rhs, int n) noexcept { if (static_cast(n) >= base_bits * arr_size) return 0; if (n <= 0) return rhs; - wide_integer lhs = rhs; + integer lhs = rhs; int bit_shift = n % base_bits; unsigned n_bytes = n / base_bits; if (bit_shift) @@ -275,23 +284,19 @@ struct wide_integer::_impl return lhs; } - constexpr static wide_integer shift_left(const wide_integer & rhs, int n) + constexpr static integer shift_left(const integer & rhs, int n) noexcept { - // static_assert(is_negative(rhs), "shift left for negative lhsbers is underfined!"); - if (is_negative(rhs)) - throw std::runtime_error("shift left for negative lhsbers is underfined!"); - - return wide_integer(shift_left(wide_integer(rhs), n)); + return integer(shift_left(integer(rhs), n)); } - constexpr static wide_integer shift_right(const wide_integer & rhs, int n) noexcept + constexpr static integer shift_right(const integer & rhs, int n) noexcept { if (static_cast(n) >= base_bits * arr_size) return 0; if (n <= 0) return rhs; - wide_integer lhs = rhs; + integer lhs = rhs; int bit_shift = n % base_bits; unsigned n_bytes = n / base_bits; if (bit_shift) @@ -315,7 +320,7 @@ struct wide_integer::_impl return lhs; } - constexpr static wide_integer shift_right(const wide_integer & rhs, int n) noexcept + constexpr static integer shift_right(const integer & rhs, int n) noexcept { if (static_cast(n) >= base_bits * arr_size) return 0; @@ -324,14 +329,14 @@ struct wide_integer::_impl bool is_neg = is_negative(rhs); if (!is_neg) - return shift_right(wide_integer(rhs), n); + return shift_right(integer(rhs), n); - wide_integer lhs = rhs; + integer lhs = rhs; int bit_shift = n % base_bits; unsigned n_bytes = n / base_bits; if (bit_shift) { - lhs = shift_right(wide_integer(lhs), bit_shift); + lhs = shift_right(integer(lhs), bit_shift); lhs.m_arr[big(0)] |= std::numeric_limits::max() << (base_bits - bit_shift); } if (n_bytes) @@ -349,8 +354,8 @@ struct wide_integer::_impl } template - constexpr static wide_integer - operator_plus_T(const wide_integer & lhs, T rhs) noexcept(is_same::value) + constexpr static integer + operator_plus_T(const integer & lhs, T rhs) noexcept(std::is_same_v) { if (rhs < 0) return _operator_minus_T(lhs, -rhs); @@ -360,10 +365,10 @@ struct wide_integer::_impl private: template - constexpr static wide_integer - _operator_minus_T(const wide_integer & lhs, T rhs) noexcept(is_same::value) + constexpr static integer + _operator_minus_T(const integer & lhs, T rhs) noexcept(std::is_same_v) { - wide_integer res = lhs; + integer res = lhs; bool is_underflow = false; int r_idx = 0; @@ -399,10 +404,10 @@ private: } template - constexpr static wide_integer - _operator_plus_T(const wide_integer & lhs, T rhs) noexcept(is_same::value) + constexpr static integer + _operator_plus_T(const integer & lhs, T rhs) noexcept(std::is_same_v) { - wide_integer res = lhs; + integer res = lhs; bool is_overflow = false; int r_idx = 0; @@ -438,27 +443,27 @@ private: } public: - constexpr static wide_integer operator_unary_tilda(const wide_integer & lhs) noexcept + constexpr static integer operator_unary_tilda(const integer & lhs) noexcept { - wide_integer res{}; + integer res{}; for (int i = 0; i < arr_size; ++i) res.m_arr[any(i)] = ~lhs.m_arr[any(i)]; return res; } - constexpr static wide_integer - operator_unary_minus(const wide_integer & lhs) noexcept(is_same::value) + constexpr static integer + operator_unary_minus(const integer & lhs) noexcept(std::is_same_v) { return operator_plus_T(operator_unary_tilda(lhs), 1); } template - constexpr static auto operator_plus(const wide_integer & lhs, const T & rhs) noexcept(is_same::value) + constexpr static auto operator_plus(const integer & lhs, const T & rhs) noexcept(std::is_same_v) { if constexpr (should_keep_size()) { - wide_integer t = rhs; + integer t = rhs; if (is_negative(t)) return _operator_minus_wide_integer(lhs, operator_unary_minus(t)); else @@ -467,17 +472,17 @@ public: else { static_assert(T::_impl::_is_wide_integer, ""); - return std::common_type_t, wide_integer>::_impl::operator_plus( - wide_integer(lhs), rhs); + return std::common_type_t, integer>::_impl::operator_plus( + integer(lhs), rhs); } } template - constexpr static auto operator_minus(const wide_integer & lhs, const T & rhs) noexcept(is_same::value) + constexpr static auto operator_minus(const integer & lhs, const T & rhs) noexcept(std::is_same_v) { if constexpr (should_keep_size()) { - wide_integer t = rhs; + integer t = rhs; if (is_negative(t)) return _operator_plus_wide_integer(lhs, operator_unary_minus(t)); else @@ -486,16 +491,16 @@ public: else { static_assert(T::_impl::_is_wide_integer, ""); - return std::common_type_t, wide_integer>::_impl::operator_minus( - wide_integer(lhs), rhs); + return std::common_type_t, integer>::_impl::operator_minus( + integer(lhs), rhs); } } private: - constexpr static wide_integer _operator_minus_wide_integer( - const wide_integer & lhs, const wide_integer & rhs) noexcept(is_same::value) + constexpr static integer _operator_minus_wide_integer( + const integer & lhs, const integer & rhs) noexcept(std::is_same_v) { - wide_integer res = lhs; + integer res = lhs; bool is_underflow = false; for (int idx = 0; idx < arr_size; ++idx) @@ -518,10 +523,10 @@ private: return res; } - constexpr static wide_integer _operator_plus_wide_integer( - const wide_integer & lhs, const wide_integer & rhs) noexcept(is_same::value) + constexpr static integer _operator_plus_wide_integer( + const integer & lhs, const integer & rhs) noexcept(std::is_same_v) { - wide_integer res = lhs; + integer res = lhs; bool is_overflow = false; for (int idx = 0; idx < arr_size; ++idx) @@ -546,14 +551,14 @@ private: public: template - constexpr static auto operator_star(const wide_integer & lhs, const T & rhs) + constexpr static auto operator_star(const integer & lhs, const T & rhs) { if constexpr (should_keep_size()) { - const wide_integer a = make_positive(lhs); - wide_integer t = make_positive(wide_integer(rhs)); + const integer a = make_positive(lhs); + integer t = make_positive(integer(rhs)); - wide_integer res = 0; + integer res = 0; for (size_t i = 0; i < arr_size * base_bits; ++i) { @@ -563,7 +568,7 @@ public: t = shift_right(t, 1); } - if (is_same::value && is_negative(wide_integer(rhs)) != is_negative(lhs)) + if (std::is_same_v && is_negative(integer(rhs)) != is_negative(lhs)) res = operator_unary_minus(res); return res; @@ -571,19 +576,19 @@ public: else { static_assert(T::_impl::_is_wide_integer, ""); - return std::common_type_t, T>::_impl::operator_star(T(lhs), rhs); + return std::common_type_t, T>::_impl::operator_star(T(lhs), rhs); } } template - constexpr static bool operator_more(const wide_integer & lhs, const T & rhs) noexcept + constexpr static bool operator_more(const integer & lhs, const T & rhs) noexcept { if constexpr (should_keep_size()) { // static_assert(Signed == std::is_signed::value, // "warning: operator_more: comparison of integers of different signs"); - wide_integer t = rhs; + integer t = rhs; if (std::numeric_limits::is_signed && (is_negative(lhs) != is_negative(t))) return is_negative(t); @@ -599,19 +604,19 @@ public: else { static_assert(T::_impl::_is_wide_integer, ""); - return std::common_type_t, T>::_impl::operator_more(T(lhs), rhs); + return std::common_type_t, T>::_impl::operator_more(T(lhs), rhs); } } template - constexpr static bool operator_less(const wide_integer & lhs, const T & rhs) noexcept + constexpr static bool operator_less(const integer & lhs, const T & rhs) noexcept { if constexpr (should_keep_size()) { // static_assert(Signed == std::is_signed::value, // "warning: operator_less: comparison of integers of different signs"); - wide_integer t = rhs; + integer t = rhs; if (std::numeric_limits::is_signed && (is_negative(lhs) != is_negative(t))) return is_negative(lhs); @@ -625,16 +630,16 @@ public: else { static_assert(T::_impl::_is_wide_integer, ""); - return std::common_type_t, T>::_impl::operator_less(T(lhs), rhs); + return std::common_type_t, T>::_impl::operator_less(T(lhs), rhs); } } template - constexpr static bool operator_eq(const wide_integer & lhs, const T & rhs) noexcept + constexpr static bool operator_eq(const integer & lhs, const T & rhs) noexcept { if constexpr (should_keep_size()) { - wide_integer t = rhs; + integer t = rhs; for (int i = 0; i < arr_size; ++i) if (lhs.m_arr[any(i)] != t.m_arr[any(i)]) @@ -645,17 +650,17 @@ public: else { static_assert(T::_impl::_is_wide_integer, ""); - return std::common_type_t, T>::_impl::operator_eq(T(lhs), rhs); + return std::common_type_t, T>::_impl::operator_eq(T(lhs), rhs); } } template - constexpr static auto operator_pipe(const wide_integer & lhs, const T & rhs) noexcept + constexpr static auto operator_pipe(const integer & lhs, const T & rhs) noexcept { if constexpr (should_keep_size()) { - wide_integer t = rhs; - wide_integer res = lhs; + integer t = rhs; + integer res = lhs; for (int i = 0; i < arr_size; ++i) res.m_arr[any(i)] |= t.m_arr[any(i)]; @@ -664,17 +669,17 @@ public: else { static_assert(T::_impl::_is_wide_integer, ""); - return std::common_type_t, T>::_impl::operator_pipe(T(lhs), rhs); + return std::common_type_t, T>::_impl::operator_pipe(T(lhs), rhs); } } template - constexpr static auto operator_amp(const wide_integer & lhs, const T & rhs) noexcept + constexpr static auto operator_amp(const integer & lhs, const T & rhs) noexcept { if constexpr (should_keep_size()) { - wide_integer t = rhs; - wide_integer res = lhs; + integer t = rhs; + integer res = lhs; for (int i = 0; i < arr_size; ++i) res.m_arr[any(i)] &= t.m_arr[any(i)]; @@ -683,7 +688,7 @@ public: else { static_assert(T::_impl::_is_wide_integer, ""); - return std::common_type_t, T>::_impl::operator_amp(T(lhs), rhs); + return std::common_type_t, T>::_impl::operator_amp(T(lhs), rhs); } } @@ -702,7 +707,7 @@ private: } if (is_zero) - throw std::domain_error("divide by zero"); + throwError("divide by zero"); T n = lhserator; T d = denominator; @@ -733,15 +738,15 @@ private: public: template - constexpr static auto operator_slash(const wide_integer & lhs, const T & rhs) + constexpr static auto operator_slash(const integer & lhs, const T & rhs) { if constexpr (should_keep_size()) { - wide_integer o = rhs; - wide_integer quotient{}, remainder{}; + integer o = rhs; + integer quotient{}, remainder{}; divide(make_positive(lhs), make_positive(o), quotient, remainder); - if (is_same::value && is_negative(o) != is_negative(lhs)) + if (std::is_same_v && is_negative(o) != is_negative(lhs)) quotient = operator_unary_minus(quotient); return quotient; @@ -749,20 +754,20 @@ public: else { static_assert(T::_impl::_is_wide_integer, ""); - return std::common_type_t, wide_integer>::operator_slash(T(lhs), rhs); + return std::common_type_t, integer>::operator_slash(T(lhs), rhs); } } template - constexpr static auto operator_percent(const wide_integer & lhs, const T & rhs) + constexpr static auto operator_percent(const integer & lhs, const T & rhs) { if constexpr (should_keep_size()) { - wide_integer o = rhs; - wide_integer quotient{}, remainder{}; + integer o = rhs; + integer quotient{}, remainder{}; divide(make_positive(lhs), make_positive(o), quotient, remainder); - if (is_same::value && is_negative(lhs)) + if (std::is_same_v && is_negative(lhs)) remainder = operator_unary_minus(remainder); return remainder; @@ -770,18 +775,18 @@ public: else { static_assert(T::_impl::_is_wide_integer, ""); - return std::common_type_t, wide_integer>::operator_percent(T(lhs), rhs); + return std::common_type_t, integer>::operator_percent(T(lhs), rhs); } } // ^ template - constexpr static auto operator_circumflex(const wide_integer & lhs, const T & rhs) noexcept + constexpr static auto operator_circumflex(const integer & lhs, const T & rhs) noexcept { if constexpr (should_keep_size()) { - wide_integer t(rhs); - wide_integer res = lhs; + integer t(rhs); + integer res = lhs; for (int i = 0; i < arr_size; ++i) res.m_arr[any(i)] ^= t.m_arr[any(i)]; @@ -794,11 +799,11 @@ public: } } - constexpr static wide_integer from_str(const char * c) + constexpr static integer from_str(const char * c) { - wide_integer res = 0; + integer res = 0; - bool is_neg = is_same::value && *c == '-'; + bool is_neg = std::is_same_v && *c == '-'; if (is_neg) ++c; @@ -827,7 +832,7 @@ public: ++c; } else - throw std::runtime_error("invalid char from"); + throwError("invalid char from"); } } else @@ -835,7 +840,7 @@ public: while (*c) { if (*c < '0' || *c > '9') - throw std::runtime_error("invalid char from"); + throwError("invalid char from"); res = operator_star(res, 10U); res = operator_plus_T(res, *c - '0'); @@ -854,7 +859,7 @@ public: template template -constexpr wide_integer::wide_integer(T rhs) noexcept +constexpr integer::integer(T rhs) noexcept : m_arr{} { if constexpr (IsWideInteger::value) @@ -865,7 +870,7 @@ constexpr wide_integer::wide_integer(T rhs) noexcept template template -constexpr wide_integer::wide_integer(std::initializer_list il) noexcept +constexpr integer::integer(std::initializer_list il) noexcept : m_arr{} { if (il.size() == 1) @@ -881,7 +886,7 @@ constexpr wide_integer::wide_integer(std::initializer_list il) template template -constexpr wide_integer & wide_integer::operator=(const wide_integer & rhs) noexcept +constexpr integer & integer::operator=(const integer & rhs) noexcept { _impl::wide_integer_from_wide_integer(*this, rhs); return *this; @@ -889,7 +894,7 @@ constexpr wide_integer & wide_integer::operator=(con template template -constexpr wide_integer & wide_integer::operator=(T rhs) noexcept +constexpr integer & integer::operator=(T rhs) noexcept { _impl::wide_integer_from_bultin(*this, rhs); return *this; @@ -897,7 +902,7 @@ constexpr wide_integer & wide_integer::operator=(T r template template -constexpr wide_integer & wide_integer::operator*=(const T & rhs) +constexpr integer & integer::operator*=(const T & rhs) { *this = *this * rhs; return *this; @@ -905,7 +910,7 @@ constexpr wide_integer & wide_integer::operator*=(co template template -constexpr wide_integer & wide_integer::operator/=(const T & rhs) +constexpr integer & integer::operator/=(const T & rhs) { *this = *this / rhs; return *this; @@ -913,7 +918,7 @@ constexpr wide_integer & wide_integer::operator/=(co template template -constexpr wide_integer & wide_integer::operator+=(const T & rhs) noexcept(is_same::value) +constexpr integer & integer::operator+=(const T & rhs) noexcept(std::is_same_v) { *this = *this + rhs; return *this; @@ -921,7 +926,7 @@ constexpr wide_integer & wide_integer::operator+=(co template template -constexpr wide_integer & wide_integer::operator-=(const T & rhs) noexcept(is_same::value) +constexpr integer & integer::operator-=(const T & rhs) noexcept(std::is_same_v) { *this = *this - rhs; return *this; @@ -929,7 +934,7 @@ constexpr wide_integer & wide_integer::operator-=(co template template -constexpr wide_integer & wide_integer::operator%=(const T & rhs) +constexpr integer & integer::operator%=(const T & rhs) { *this = *this % rhs; return *this; @@ -937,7 +942,7 @@ constexpr wide_integer & wide_integer::operator%=(co template template -constexpr wide_integer & wide_integer::operator&=(const T & rhs) noexcept +constexpr integer & integer::operator&=(const T & rhs) noexcept { *this = *this & rhs; return *this; @@ -945,7 +950,7 @@ constexpr wide_integer & wide_integer::operator&=(co template template -constexpr wide_integer & wide_integer::operator|=(const T & rhs) noexcept +constexpr integer & integer::operator|=(const T & rhs) noexcept { *this = *this | rhs; return *this; @@ -953,35 +958,35 @@ constexpr wide_integer & wide_integer::operator|=(co template template -constexpr wide_integer & wide_integer::operator^=(const T & rhs) noexcept +constexpr integer & integer::operator^=(const T & rhs) noexcept { *this = *this ^ rhs; return *this; } template -constexpr wide_integer & wide_integer::operator<<=(int n) +constexpr integer & integer::operator<<=(int n) noexcept { *this = _impl::shift_left(*this, n); return *this; } template -constexpr wide_integer & wide_integer::operator>>=(int n) noexcept +constexpr integer & integer::operator>>=(int n) noexcept { *this = _impl::shift_right(*this, n); return *this; } template -constexpr wide_integer & wide_integer::operator++() noexcept(is_same::value) +constexpr integer & integer::operator++() noexcept(std::is_same_v) { *this = _impl::operator_plus(*this, 1); return *this; } template -constexpr wide_integer wide_integer::operator++(int) noexcept(is_same::value) +constexpr integer integer::operator++(int) noexcept(std::is_same_v) { auto tmp = *this; *this = _impl::operator_plus(*this, 1); @@ -989,14 +994,14 @@ constexpr wide_integer wide_integer::operator++(int) } template -constexpr wide_integer & wide_integer::operator--() noexcept(is_same::value) +constexpr integer & integer::operator--() noexcept(std::is_same_v) { *this = _impl::operator_minus(*this, 1); return *this; } template -constexpr wide_integer wide_integer::operator--(int) noexcept(is_same::value) +constexpr integer integer::operator--(int) noexcept(std::is_same_v) { auto tmp = *this; *this = _impl::operator_minus(*this, 1); @@ -1004,14 +1009,14 @@ constexpr wide_integer wide_integer::operator--(int) } template -constexpr wide_integer::operator bool() const noexcept +constexpr integer::operator bool() const noexcept { return !_impl::operator_eq(*this, 0); } template template -constexpr wide_integer::operator T() const noexcept +constexpr integer::operator T() const noexcept { static_assert(std::numeric_limits::is_integer, ""); T res = 0; @@ -1023,12 +1028,12 @@ constexpr wide_integer::operator T() const noexcept } template -constexpr wide_integer::operator long double() const noexcept +constexpr integer::operator long double() const noexcept { if (_impl::operator_eq(*this, 0)) return 0; - wide_integer tmp = *this; + integer tmp = *this; if (_impl::is_negative(*this)) tmp = -tmp; @@ -1048,42 +1053,45 @@ constexpr wide_integer::operator long double() const noexcept } template -constexpr wide_integer::operator double() const noexcept +constexpr integer::operator double() const noexcept { return static_cast(*this); } template -constexpr wide_integer::operator float() const noexcept +constexpr integer::operator float() const noexcept { return static_cast(*this); } // Unary operators template -constexpr wide_integer operator~(const wide_integer & lhs) noexcept +constexpr integer operator~(const integer & lhs) noexcept { - return wide_integer::_impl::operator_unary_tilda(lhs); + return integer::_impl::operator_unary_tilda(lhs); } template -constexpr wide_integer operator-(const wide_integer & lhs) noexcept(is_same::value) +constexpr integer operator-(const integer & lhs) noexcept(std::is_same_v) { - return wide_integer::_impl::operator_unary_minus(lhs); + return integer::_impl::operator_unary_minus(lhs); } template -constexpr wide_integer operator+(const wide_integer & lhs) noexcept(is_same::value) +constexpr integer operator+(const integer & lhs) noexcept(std::is_same_v) { return lhs; } +#define CT(x) \ + std::common_type_t, std::decay_t> { x } + // Binary operators template -std::common_type_t, wide_integer> constexpr -operator*(const wide_integer & lhs, const wide_integer & rhs) +std::common_type_t, integer> constexpr +operator*(const integer & lhs, const integer & rhs) { - return std::common_type_t, wide_integer>::_impl::operator_star(lhs, rhs); + return std::common_type_t, integer>::_impl::operator_star(lhs, rhs); } template @@ -1093,10 +1101,10 @@ std::common_type_t constexpr operator*(const Arithmetic } template -std::common_type_t, wide_integer> constexpr -operator/(const wide_integer & lhs, const wide_integer & rhs) +std::common_type_t, integer> constexpr +operator/(const integer & lhs, const integer & rhs) { - return std::common_type_t, wide_integer>::_impl::operator_slash(lhs, rhs); + return std::common_type_t, integer>::_impl::operator_slash(lhs, rhs); } template std::common_type_t constexpr operator/(const Arithmetic & lhs, const Arithmetic2 & rhs) @@ -1105,10 +1113,10 @@ std::common_type_t constexpr operator/(const Arithmetic } template -std::common_type_t, wide_integer> constexpr -operator+(const wide_integer & lhs, const wide_integer & rhs) +std::common_type_t, integer> constexpr +operator+(const integer & lhs, const integer & rhs) { - return std::common_type_t, wide_integer>::_impl::operator_plus(lhs, rhs); + return std::common_type_t, integer>::_impl::operator_plus(lhs, rhs); } template std::common_type_t constexpr operator+(const Arithmetic & lhs, const Arithmetic2 & rhs) @@ -1117,10 +1125,10 @@ std::common_type_t constexpr operator+(const Arithmetic } template -std::common_type_t, wide_integer> constexpr -operator-(const wide_integer & lhs, const wide_integer & rhs) +std::common_type_t, integer> constexpr +operator-(const integer & lhs, const integer & rhs) { - return std::common_type_t, wide_integer>::_impl::operator_minus(lhs, rhs); + return std::common_type_t, integer>::_impl::operator_minus(lhs, rhs); } template std::common_type_t constexpr operator-(const Arithmetic & lhs, const Arithmetic2 & rhs) @@ -1129,10 +1137,10 @@ std::common_type_t constexpr operator-(const Arithmetic } template -std::common_type_t, wide_integer> constexpr -operator%(const wide_integer & lhs, const wide_integer & rhs) +std::common_type_t, integer> constexpr +operator%(const integer & lhs, const integer & rhs) { - return std::common_type_t, wide_integer>::_impl::operator_percent(lhs, rhs); + return std::common_type_t, integer>::_impl::operator_percent(lhs, rhs); } template std::common_type_t constexpr operator%(const Integral & lhs, const Integral2 & rhs) @@ -1141,10 +1149,10 @@ std::common_type_t constexpr operator%(const Integral & lhs } template -std::common_type_t, wide_integer> constexpr -operator&(const wide_integer & lhs, const wide_integer & rhs) +std::common_type_t, integer> constexpr +operator&(const integer & lhs, const integer & rhs) { - return std::common_type_t, wide_integer>::_impl::operator_amp(lhs, rhs); + return std::common_type_t, integer>::_impl::operator_amp(lhs, rhs); } template std::common_type_t constexpr operator&(const Integral & lhs, const Integral2 & rhs) @@ -1153,10 +1161,10 @@ std::common_type_t constexpr operator&(const Integral & lhs } template -std::common_type_t, wide_integer> constexpr -operator|(const wide_integer & lhs, const wide_integer & rhs) +std::common_type_t, integer> constexpr +operator|(const integer & lhs, const integer & rhs) { - return std::common_type_t, wide_integer>::_impl::operator_pipe(lhs, rhs); + return std::common_type_t, integer>::_impl::operator_pipe(lhs, rhs); } template std::common_type_t constexpr operator|(const Integral & lhs, const Integral2 & rhs) @@ -1165,10 +1173,10 @@ std::common_type_t constexpr operator|(const Integral & lhs } template -std::common_type_t, wide_integer> constexpr -operator^(const wide_integer & lhs, const wide_integer & rhs) +std::common_type_t, integer> constexpr +operator^(const integer & lhs, const integer & rhs) { - return std::common_type_t, wide_integer>::_impl::operator_circumflex(lhs, rhs); + return std::common_type_t, integer>::_impl::operator_circumflex(lhs, rhs); } template std::common_type_t constexpr operator^(const Integral & lhs, const Integral2 & rhs) @@ -1177,20 +1185,20 @@ std::common_type_t constexpr operator^(const Integral & lhs } template -constexpr wide_integer operator<<(const wide_integer & lhs, int n) noexcept +constexpr integer operator<<(const integer & lhs, int n) noexcept { - return wide_integer::_impl::shift_left(lhs, n); + return integer::_impl::shift_left(lhs, n); } template -constexpr wide_integer operator>>(const wide_integer & lhs, int n) noexcept +constexpr integer operator>>(const integer & lhs, int n) noexcept { - return wide_integer::_impl::shift_right(lhs, n); + return integer::_impl::shift_right(lhs, n); } template -constexpr bool operator<(const wide_integer & lhs, const wide_integer & rhs) +constexpr bool operator<(const integer & lhs, const integer & rhs) { - return std::common_type_t, wide_integer>::_impl::operator_less(lhs, rhs); + return std::common_type_t, integer>::_impl::operator_less(lhs, rhs); } template constexpr bool operator<(const Arithmetic & lhs, const Arithmetic2 & rhs) @@ -1199,9 +1207,9 @@ constexpr bool operator<(const Arithmetic & lhs, const Arithmetic2 & rhs) } template -constexpr bool operator>(const wide_integer & lhs, const wide_integer & rhs) +constexpr bool operator>(const integer & lhs, const integer & rhs) { - return std::common_type_t, wide_integer>::_impl::operator_more(lhs, rhs); + return std::common_type_t, integer>::_impl::operator_more(lhs, rhs); } template constexpr bool operator>(const Arithmetic & lhs, const Arithmetic2 & rhs) @@ -1210,10 +1218,10 @@ constexpr bool operator>(const Arithmetic & lhs, const Arithmetic2 & rhs) } template -constexpr bool operator<=(const wide_integer & lhs, const wide_integer & rhs) +constexpr bool operator<=(const integer & lhs, const integer & rhs) { - return std::common_type_t, wide_integer>::_impl::operator_less(lhs, rhs) - || std::common_type_t, wide_integer>::_impl::operator_eq(lhs, rhs); + return std::common_type_t, integer>::_impl::operator_less(lhs, rhs) + || std::common_type_t, integer>::_impl::operator_eq(lhs, rhs); } template constexpr bool operator<=(const Arithmetic & lhs, const Arithmetic2 & rhs) @@ -1222,10 +1230,10 @@ constexpr bool operator<=(const Arithmetic & lhs, const Arithmetic2 & rhs) } template -constexpr bool operator>=(const wide_integer & lhs, const wide_integer & rhs) +constexpr bool operator>=(const integer & lhs, const integer & rhs) { - return std::common_type_t, wide_integer>::_impl::operator_more(lhs, rhs) - || std::common_type_t, wide_integer>::_impl::operator_eq(lhs, rhs); + return std::common_type_t, integer>::_impl::operator_more(lhs, rhs) + || std::common_type_t, integer>::_impl::operator_eq(lhs, rhs); } template constexpr bool operator>=(const Arithmetic & lhs, const Arithmetic2 & rhs) @@ -1234,9 +1242,9 @@ constexpr bool operator>=(const Arithmetic & lhs, const Arithmetic2 & rhs) } template -constexpr bool operator==(const wide_integer & lhs, const wide_integer & rhs) +constexpr bool operator==(const integer & lhs, const integer & rhs) { - return std::common_type_t, wide_integer>::_impl::operator_eq(lhs, rhs); + return std::common_type_t, integer>::_impl::operator_eq(lhs, rhs); } template constexpr bool operator==(const Arithmetic & lhs, const Arithmetic2 & rhs) @@ -1245,9 +1253,9 @@ constexpr bool operator==(const Arithmetic & lhs, const Arithmetic2 & rhs) } template -constexpr bool operator!=(const wide_integer & lhs, const wide_integer & rhs) +constexpr bool operator!=(const integer & lhs, const integer & rhs) { - return !std::common_type_t, wide_integer>::_impl::operator_eq(lhs, rhs); + return !std::common_type_t, integer>::_impl::operator_eq(lhs, rhs); } template constexpr bool operator!=(const Arithmetic & lhs, const Arithmetic2 & rhs) @@ -1255,35 +1263,17 @@ constexpr bool operator!=(const Arithmetic & lhs, const Arithmetic2 & rhs) return CT(lhs) != CT(rhs); } -template -inline std::string to_string(const wide_integer & n) -{ - std::string res; - if (wide_integer::_impl::operator_eq(n, 0U)) - return "0"; +#undef CT - wide_integer t; - bool is_neg = wide_integer::_impl::is_negative(n); - if (is_neg) - t = wide_integer::_impl::operator_unary_minus(n); - else - t = n; - - while (!wide_integer::_impl::operator_eq(t, 0U)) - { - res.insert(res.begin(), '0' + char(wide_integer::_impl::operator_percent(t, 10U))); - t = wide_integer::_impl::operator_slash(t, 10U); - } - - if (is_neg) - res.insert(res.begin(), '-'); - return res; } -template -struct hash> +namespace std { - std::size_t operator()(const wide_integer & lhs) const + +template +struct hash> +{ + std::size_t operator()(const wide::integer & lhs) const { static_assert(Bits % (sizeof(size_t) * 8) == 0); @@ -1293,9 +1283,8 @@ struct hash> size_t res = 0; for (unsigned i = 0; i < count; ++i) res ^= ptr[i]; - return hash()(res); + return res; } }; -#undef CT } diff --git a/base/common/wide_integer_to_string.h b/base/common/wide_integer_to_string.h new file mode 100644 index 00000000000..9908ef4be7a --- /dev/null +++ b/base/common/wide_integer_to_string.h @@ -0,0 +1,35 @@ +#pragma once + +#include + +#include "wide_integer.h" + +namespace wide +{ + +template +inline std::string to_string(const integer & n) +{ + std::string res; + if (integer::_impl::operator_eq(n, 0U)) + return "0"; + + integer t; + bool is_neg = integer::_impl::is_negative(n); + if (is_neg) + t = integer::_impl::operator_unary_minus(n); + else + t = n; + + while (!integer::_impl::operator_eq(t, 0U)) + { + res.insert(res.begin(), '0' + char(integer::_impl::operator_percent(t, 10U))); + t = integer::_impl::operator_slash(t, 10U); + } + + if (is_neg) + res.insert(res.begin(), '-'); + return res; +} + +} diff --git a/src/IO/WriteHelpers.h b/src/IO/WriteHelpers.h index 3b9eced09bd..1f0fe095059 100644 --- a/src/IO/WriteHelpers.h +++ b/src/IO/WriteHelpers.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -42,6 +43,12 @@ namespace ErrorCodes extern const int ILLEGAL_TYPE_OF_ARGUMENT; } +template +inline std::string bigintToString(const T & x) +{ + return to_string(x); +} + /// Helper functions for formatted and binary output. inline void writeChar(char x, WriteBuffer & buf) diff --git a/tests/queries/0_stateless/01475_fix_bigint_shift.reference b/tests/queries/0_stateless/01475_fix_bigint_shift.reference new file mode 100644 index 00000000000..c278273c760 --- /dev/null +++ b/tests/queries/0_stateless/01475_fix_bigint_shift.reference @@ -0,0 +1,2 @@ +-4 +-4 diff --git a/tests/queries/0_stateless/01475_fix_bigint_shift.sql b/tests/queries/0_stateless/01475_fix_bigint_shift.sql new file mode 100644 index 00000000000..d16cdeca85d --- /dev/null +++ b/tests/queries/0_stateless/01475_fix_bigint_shift.sql @@ -0,0 +1,2 @@ +SELECT bitShiftLeft(toInt64(-2), 1); +SELECT bitShiftLeft(toInt256(-2), 1);