diff options
author | Vlad Yaroslavlev <vladon@vladon.com> | 2022-02-10 16:46:25 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:46:25 +0300 |
commit | 344ea37b4a345701ab0e67de2266a1c1bd7baf2d (patch) | |
tree | 1a2c5ffcf89eb53ecd79dbc9bc0a195c27404d0c /library/cpp/int128 | |
parent | 706b83ed7de5a473436620367af31fc0ceecde07 (diff) | |
download | ydb-344ea37b4a345701ab0e67de2266a1c1bd7baf2d.tar.gz |
Restoring authorship annotation for Vlad Yaroslavlev <vladon@vladon.com>. Commit 2 of 2.
Diffstat (limited to 'library/cpp/int128')
22 files changed, 3456 insertions, 3456 deletions
diff --git a/library/cpp/int128/README.md b/library/cpp/int128/README.md index 0fa0df29c6..e1c4dcbb78 100644 --- a/library/cpp/int128/README.md +++ b/library/cpp/int128/README.md @@ -1,6 +1,6 @@ -https://st.yandex-team.ru/IGNIETFERRO-697 - -(Объединение разрозненных по Аркадии библиотек для поддержки 128-битного целого) - -Идея классов ui128 / i128 в том, чтобы они работали так, как будто это компиляторные интовые типы. -Т.е. у этих классов не должно быть публичных функций типа ui128::GetHigh(), конструкторов из нескольких параметров и так далее. +https://st.yandex-team.ru/IGNIETFERRO-697 + +(Объединение разрозненных по Аркадии библиотек для поддержки 128-битного целого) + +Идея классов ui128 / i128 в том, чтобы они работали так, как будто это компиляторные интовые типы. +Т.е. у этих классов не должно быть публичных функций типа ui128::GetHigh(), конструкторов из нескольких параметров и так далее. diff --git a/library/cpp/int128/bench/main.cpp b/library/cpp/int128/bench/main.cpp index 54d063cc40..be4f8d1500 100644 --- a/library/cpp/int128/bench/main.cpp +++ b/library/cpp/int128/bench/main.cpp @@ -1,45 +1,45 @@ #include <library/cpp/int128/int128.h> #include <library/cpp/testing/benchmark/bench.h> - -#include <util/generic/xrange.h> -#include <util/system/compiler.h> - -Y_CPU_BENCHMARK(LibraryDivisionUnsigned128, iface) { - ui128 b = {0, 10'000'000}; - for (const auto i : xrange(iface.Iterations())) { - ui128 a = i * 10'000'000; - ui128 c = a / b; - Y_FAKE_READ(c); - } -} - -#if defined(Y_HAVE_INT128) -Y_CPU_BENCHMARK(IntrinsicDivisionUnsigned128, iface) { - unsigned __int128 b = 10'000'000; - for (const auto i : xrange(iface.Iterations())) { - unsigned __int128 a = i * 10'000'000; - unsigned __int128 c = a / b; - Y_FAKE_READ(c); - } -} -#endif // Y_HAVE_INT128 - -Y_CPU_BENCHMARK(LibraryDivisionSigned128, iface) { - i128 b = {0, 10'000'000}; - for (const auto i : xrange(iface.Iterations())) { - i128 a = i * 10'000'000; - i128 c = a / b; - Y_FAKE_READ(c); - } -} - -#if defined(Y_HAVE_INT128) -Y_CPU_BENCHMARK(IntrinsicDivisionSigned128, iface) { - signed __int128 b = 10'000'000; - for (const auto i : xrange(iface.Iterations())) { - signed __int128 a = i * 10'000'000; - signed __int128 c = a / b; - Y_FAKE_READ(c); - } -} -#endif // Y_HAVE_INT128 + +#include <util/generic/xrange.h> +#include <util/system/compiler.h> + +Y_CPU_BENCHMARK(LibraryDivisionUnsigned128, iface) { + ui128 b = {0, 10'000'000}; + for (const auto i : xrange(iface.Iterations())) { + ui128 a = i * 10'000'000; + ui128 c = a / b; + Y_FAKE_READ(c); + } +} + +#if defined(Y_HAVE_INT128) +Y_CPU_BENCHMARK(IntrinsicDivisionUnsigned128, iface) { + unsigned __int128 b = 10'000'000; + for (const auto i : xrange(iface.Iterations())) { + unsigned __int128 a = i * 10'000'000; + unsigned __int128 c = a / b; + Y_FAKE_READ(c); + } +} +#endif // Y_HAVE_INT128 + +Y_CPU_BENCHMARK(LibraryDivisionSigned128, iface) { + i128 b = {0, 10'000'000}; + for (const auto i : xrange(iface.Iterations())) { + i128 a = i * 10'000'000; + i128 c = a / b; + Y_FAKE_READ(c); + } +} + +#if defined(Y_HAVE_INT128) +Y_CPU_BENCHMARK(IntrinsicDivisionSigned128, iface) { + signed __int128 b = 10'000'000; + for (const auto i : xrange(iface.Iterations())) { + signed __int128 a = i * 10'000'000; + signed __int128 c = a / b; + Y_FAKE_READ(c); + } +} +#endif // Y_HAVE_INT128 diff --git a/library/cpp/int128/bench/ya.make b/library/cpp/int128/bench/ya.make index bcd7c2a263..4800e7883d 100644 --- a/library/cpp/int128/bench/ya.make +++ b/library/cpp/int128/bench/ya.make @@ -1,15 +1,15 @@ -OWNER( - vladon -) - +OWNER( + vladon +) + Y_BENCHMARK() - -SRCS( - main.cpp -) - -PEERDIR( + +SRCS( + main.cpp +) + +PEERDIR( library/cpp/int128 -) - -END() +) + +END() diff --git a/library/cpp/int128/int128.cpp b/library/cpp/int128/int128.cpp index dedcd28f91..a28a389fe8 100644 --- a/library/cpp/int128/int128.cpp +++ b/library/cpp/int128/int128.cpp @@ -1,55 +1,55 @@ -#include "int128.h" - -#include <tuple> - -IOutputStream& operator<<(IOutputStream& out, const ui128& other) { - // see http://stackoverflow.com/questions/4361441/c-print-a-biginteger-in-base-10 - // and http://stackoverflow.com/questions/8023414/how-to-convert-a-128-bit-integer-to-a-decimal-ascii-string-in-c - int d[39] = {0}; - int i; - int j; - for (i = 63; i > -1; i--) { - if ((other.High_ >> i) & 1) - ++d[0]; - for (j = 0; j < 39; j++) - d[j] *= 2; - for (j = 0; j < 38; j++) { - d[j + 1] += d[j] / 10; - d[j] %= 10; - } - } - for (i = 63; i > -1; i--) { - if ((other.Low_ >> i) & 1) - ++d[0]; - if (i > 0) - for (j = 0; j < 39; j++) - d[j] *= 2; - for (j = 0; j < 38; j++) { - d[j + 1] += d[j] / 10; - d[j] %= 10; - } - } - for (i = 38; i > 0; i--) - if (d[i] > 0) - break; - for (; i > -1; i--) - out << static_cast<char>('0' + d[i]); - - return out; -} - -void TSerializer<ui128>::Save(IOutputStream* out, const ui128& Number) { - ::Save(out, GetHigh(Number)); - ::Save(out, GetLow(Number)); -} - -void TSerializer<ui128>::Load(IInputStream* in, ui128& Number) { - ui64 High; - ui64 Low; - ::Load(in, High); - ::Load(in, Low); - Number = ui128(High, Low); -} +#include "int128.h" + +#include <tuple> + +IOutputStream& operator<<(IOutputStream& out, const ui128& other) { + // see http://stackoverflow.com/questions/4361441/c-print-a-biginteger-in-base-10 + // and http://stackoverflow.com/questions/8023414/how-to-convert-a-128-bit-integer-to-a-decimal-ascii-string-in-c + int d[39] = {0}; + int i; + int j; + for (i = 63; i > -1; i--) { + if ((other.High_ >> i) & 1) + ++d[0]; + for (j = 0; j < 39; j++) + d[j] *= 2; + for (j = 0; j < 38; j++) { + d[j + 1] += d[j] / 10; + d[j] %= 10; + } + } + for (i = 63; i > -1; i--) { + if ((other.Low_ >> i) & 1) + ++d[0]; + if (i > 0) + for (j = 0; j < 39; j++) + d[j] *= 2; + for (j = 0; j < 38; j++) { + d[j + 1] += d[j] / 10; + d[j] %= 10; + } + } + for (i = 38; i > 0; i--) + if (d[i] > 0) + break; + for (; i > -1; i--) + out << static_cast<char>('0' + d[i]); + + return out; +} + +void TSerializer<ui128>::Save(IOutputStream* out, const ui128& Number) { + ::Save(out, GetHigh(Number)); + ::Save(out, GetLow(Number)); +} + +void TSerializer<ui128>::Load(IInputStream* in, ui128& Number) { + ui64 High; + ui64 Low; + ::Load(in, High); + ::Load(in, Low); + Number = ui128(High, Low); +} IOutputStream& operator<<(IOutputStream& out, const i128& other) { diff --git a/library/cpp/int128/int128.h b/library/cpp/int128/int128.h index e6345f4f12..f1121fc0c6 100644 --- a/library/cpp/int128/int128.h +++ b/library/cpp/int128/int128.h @@ -1,1278 +1,1278 @@ -#pragma once - -#include "int128_util.h" - -#include <util/generic/bitops.h> -#include <util/system/compiler.h> -#include <util/system/defaults.h> -#include <util/stream/output.h> -#include <util/string/cast.h> -#include <util/string/builder.h> -#include <util/str_stl.h> -#include <util/ysaveload.h> - -#include <cfenv> -#include <climits> -#include <cmath> -#include <limits> -#include <type_traits> - -#if !defined(_little_endian_) && !defined(_big_endian_) - static_assert(false, "Platform endianness is not supported"); -#endif - -template <bool IsSigned> -class TInteger128 { -public: - TInteger128() noexcept = default; - -#if defined(_little_endian_) - constexpr TInteger128(const ui64 high, const ui64 low) noexcept - : Low_(low) - , High_(high) - { - } -#elif defined(_big_endian_) - constexpr TInteger128(const ui64 high, const ui64 low) noexcept - : High_(high) - , Low_(low) - { - } -#endif - - constexpr TInteger128(const TInteger128<!IsSigned> other) noexcept - : TInteger128{GetHigh(other), GetLow(other)} - { - } - -#if defined(_little_endian_) - constexpr TInteger128(const char other) noexcept - : Low_{static_cast<ui64>(other)} - , High_{0} - { - } - - constexpr TInteger128(const ui8 other) noexcept - : Low_{other} - , High_{0} - { - } - - constexpr TInteger128(const ui16 other) noexcept - : Low_{other} - , High_{0} - { - } - - constexpr TInteger128(const ui32 other) noexcept - : Low_{other} - , High_{0} - { - } - - constexpr TInteger128(const ui64 other) noexcept - : Low_{other} - , High_{0} - { - } - -#if defined(Y_HAVE_INT128) - constexpr TInteger128(const unsigned __int128 other) noexcept - : Low_{static_cast<ui64>(other & ~ui64{0})} - , High_{static_cast<ui64>(other >> 64)} - { - } -#endif - - constexpr TInteger128(const i8 other) noexcept - : Low_{static_cast<ui64>(other)} - , High_{other < 0 ? std::numeric_limits<ui64>::max() : 0} - { - } - - constexpr TInteger128(const i16 other) noexcept - : Low_{static_cast<ui64>(other)} - , High_{other < 0 ? std::numeric_limits<ui64>::max() : 0} - { - } - - constexpr TInteger128(const i32 other) noexcept - : Low_(static_cast<ui64>(other)) - , High_{other < 0 ? std::numeric_limits<ui64>::max() : 0} - { - } - - constexpr TInteger128(const i64 other) noexcept - : Low_(static_cast<ui64>(other)) - , High_{other < 0 ? std::numeric_limits<ui64>::max() : 0} - { - } - -#if defined(Y_HAVE_INT128) - template <bool IsSigned2 = IsSigned, std::enable_if_t<!IsSigned2, bool> = false> - constexpr TInteger128(const signed __int128 other) noexcept - : Low_{static_cast<ui64>(other & ~ui64{0})} - , High_{static_cast<ui64>(static_cast<unsigned __int128>(other) >> 64)} - { - } - - template <bool IsSigned2 = IsSigned, typename std::enable_if_t<IsSigned2, bool> = false> - constexpr TInteger128(const signed __int128 other) noexcept - : Low_{static_cast<ui64>(other & ~ui64(0))} - , High_{static_cast<ui64>(other >> 64)} - { - } -#endif - -#elif defined(_big_endian_) - static_assert(false, "Big-endian will be later"); -#endif // _little_endian_ or _big_endian_ - - constexpr TInteger128& operator=(const char other) noexcept { - *this = TInteger128{other}; - return *this; - } - - constexpr TInteger128& operator=(const ui8 other) noexcept { - *this = TInteger128{other}; - return *this; - } - - constexpr TInteger128& operator=(const ui16 other) noexcept { - *this = TInteger128{other}; - return *this; - } - - constexpr TInteger128& operator=(const ui32 other) noexcept { - *this = TInteger128{other}; - return *this; - } - - constexpr TInteger128& operator=(const ui64 other) noexcept { - *this = TInteger128{other}; - return *this; - } - -#if defined(Y_HAVE_INT128) - constexpr TInteger128& operator=(const unsigned __int128 other) noexcept { - *this = TInteger128{other}; - return *this; - } -#endif - - constexpr TInteger128& operator=(const i8 other) noexcept { - *this = TInteger128{other}; - return *this; - } - - constexpr TInteger128& operator=(const i16 other) noexcept { - *this = TInteger128{other}; - return *this; - } - - constexpr TInteger128& operator=(const i32 other) noexcept { - *this = TInteger128{other}; - return *this; - } - - constexpr TInteger128& operator=(const i64 other) noexcept { - *this = TInteger128{other}; - return *this; - } - -#if defined(Y_HAVE_INT128) - constexpr TInteger128& operator=(const signed __int128 other) noexcept { - *this = TInteger128{other}; - return *this; - } -#endif // Y_HAVE_INT128 - - constexpr TInteger128& operator+=(const TInteger128 other) noexcept { - return *this = *this + other; - } - - constexpr TInteger128& operator-=(const TInteger128 other) noexcept { - return *this = *this - other; - } - - constexpr TInteger128& operator*=(const TInteger128 other) noexcept { - return *this = *this * other; - } - - constexpr TInteger128& operator&=(const TInteger128 other) noexcept { - return *this = *this & other; - } - - constexpr TInteger128& operator^=(const TInteger128 other) noexcept { +#pragma once + +#include "int128_util.h" + +#include <util/generic/bitops.h> +#include <util/system/compiler.h> +#include <util/system/defaults.h> +#include <util/stream/output.h> +#include <util/string/cast.h> +#include <util/string/builder.h> +#include <util/str_stl.h> +#include <util/ysaveload.h> + +#include <cfenv> +#include <climits> +#include <cmath> +#include <limits> +#include <type_traits> + +#if !defined(_little_endian_) && !defined(_big_endian_) + static_assert(false, "Platform endianness is not supported"); +#endif + +template <bool IsSigned> +class TInteger128 { +public: + TInteger128() noexcept = default; + +#if defined(_little_endian_) + constexpr TInteger128(const ui64 high, const ui64 low) noexcept + : Low_(low) + , High_(high) + { + } +#elif defined(_big_endian_) + constexpr TInteger128(const ui64 high, const ui64 low) noexcept + : High_(high) + , Low_(low) + { + } +#endif + + constexpr TInteger128(const TInteger128<!IsSigned> other) noexcept + : TInteger128{GetHigh(other), GetLow(other)} + { + } + +#if defined(_little_endian_) + constexpr TInteger128(const char other) noexcept + : Low_{static_cast<ui64>(other)} + , High_{0} + { + } + + constexpr TInteger128(const ui8 other) noexcept + : Low_{other} + , High_{0} + { + } + + constexpr TInteger128(const ui16 other) noexcept + : Low_{other} + , High_{0} + { + } + + constexpr TInteger128(const ui32 other) noexcept + : Low_{other} + , High_{0} + { + } + + constexpr TInteger128(const ui64 other) noexcept + : Low_{other} + , High_{0} + { + } + +#if defined(Y_HAVE_INT128) + constexpr TInteger128(const unsigned __int128 other) noexcept + : Low_{static_cast<ui64>(other & ~ui64{0})} + , High_{static_cast<ui64>(other >> 64)} + { + } +#endif + + constexpr TInteger128(const i8 other) noexcept + : Low_{static_cast<ui64>(other)} + , High_{other < 0 ? std::numeric_limits<ui64>::max() : 0} + { + } + + constexpr TInteger128(const i16 other) noexcept + : Low_{static_cast<ui64>(other)} + , High_{other < 0 ? std::numeric_limits<ui64>::max() : 0} + { + } + + constexpr TInteger128(const i32 other) noexcept + : Low_(static_cast<ui64>(other)) + , High_{other < 0 ? std::numeric_limits<ui64>::max() : 0} + { + } + + constexpr TInteger128(const i64 other) noexcept + : Low_(static_cast<ui64>(other)) + , High_{other < 0 ? std::numeric_limits<ui64>::max() : 0} + { + } + +#if defined(Y_HAVE_INT128) + template <bool IsSigned2 = IsSigned, std::enable_if_t<!IsSigned2, bool> = false> + constexpr TInteger128(const signed __int128 other) noexcept + : Low_{static_cast<ui64>(other & ~ui64{0})} + , High_{static_cast<ui64>(static_cast<unsigned __int128>(other) >> 64)} + { + } + + template <bool IsSigned2 = IsSigned, typename std::enable_if_t<IsSigned2, bool> = false> + constexpr TInteger128(const signed __int128 other) noexcept + : Low_{static_cast<ui64>(other & ~ui64(0))} + , High_{static_cast<ui64>(other >> 64)} + { + } +#endif + +#elif defined(_big_endian_) + static_assert(false, "Big-endian will be later"); +#endif // _little_endian_ or _big_endian_ + + constexpr TInteger128& operator=(const char other) noexcept { + *this = TInteger128{other}; + return *this; + } + + constexpr TInteger128& operator=(const ui8 other) noexcept { + *this = TInteger128{other}; + return *this; + } + + constexpr TInteger128& operator=(const ui16 other) noexcept { + *this = TInteger128{other}; + return *this; + } + + constexpr TInteger128& operator=(const ui32 other) noexcept { + *this = TInteger128{other}; + return *this; + } + + constexpr TInteger128& operator=(const ui64 other) noexcept { + *this = TInteger128{other}; + return *this; + } + +#if defined(Y_HAVE_INT128) + constexpr TInteger128& operator=(const unsigned __int128 other) noexcept { + *this = TInteger128{other}; + return *this; + } +#endif + + constexpr TInteger128& operator=(const i8 other) noexcept { + *this = TInteger128{other}; + return *this; + } + + constexpr TInteger128& operator=(const i16 other) noexcept { + *this = TInteger128{other}; + return *this; + } + + constexpr TInteger128& operator=(const i32 other) noexcept { + *this = TInteger128{other}; + return *this; + } + + constexpr TInteger128& operator=(const i64 other) noexcept { + *this = TInteger128{other}; + return *this; + } + +#if defined(Y_HAVE_INT128) + constexpr TInteger128& operator=(const signed __int128 other) noexcept { + *this = TInteger128{other}; + return *this; + } +#endif // Y_HAVE_INT128 + + constexpr TInteger128& operator+=(const TInteger128 other) noexcept { + return *this = *this + other; + } + + constexpr TInteger128& operator-=(const TInteger128 other) noexcept { + return *this = *this - other; + } + + constexpr TInteger128& operator*=(const TInteger128 other) noexcept { + return *this = *this * other; + } + + constexpr TInteger128& operator&=(const TInteger128 other) noexcept { + return *this = *this & other; + } + + constexpr TInteger128& operator^=(const TInteger128 other) noexcept { return *this = *this ^ other; - } - - constexpr TInteger128& operator|=(const TInteger128 other) noexcept { - return *this = *this | other; - } - - constexpr TInteger128& operator<<=(int n) noexcept { - *this = *this << n; - return *this; - } - - constexpr TInteger128& operator>>=(int n) noexcept { - *this = *this >> n; - return *this; - } - - constexpr TInteger128& operator++() noexcept { - *this += 1; - return *this; - } - - constexpr TInteger128 operator++(int) noexcept { - const TInteger128 ret{*this}; - this->operator++(); - return ret; - } - - constexpr TInteger128& operator--() noexcept { - *this -= 1; - return *this; - } - - constexpr TInteger128 operator--(int) noexcept { - const TInteger128 ret{*this}; - this->operator--(); - return ret; - } - - explicit constexpr operator bool() const noexcept { - return Low_ || High_; - } - - explicit constexpr operator char() const noexcept { - return static_cast<char>(Low_); - } - - explicit constexpr operator ui8() const noexcept { - return static_cast<ui8>(Low_); - } - - explicit constexpr operator i8() const noexcept { - return static_cast<i8>(Low_); - } - - explicit constexpr operator ui16() const noexcept { - return static_cast<ui16>(Low_); - } - - explicit constexpr operator i16() const noexcept { - return static_cast<i16>(Low_); - } - - explicit constexpr operator ui32() const noexcept { - return static_cast<ui32>(Low_); - } - - explicit constexpr operator i32() const noexcept { - return static_cast<i32>(Low_); - } - - explicit constexpr operator ui64() const noexcept { - return static_cast<ui64>(Low_); - } - - explicit constexpr operator i64() const noexcept { - return static_cast<i64>(Low_); - } - -#if defined(Y_HAVE_INT128) - explicit constexpr operator unsigned __int128() const noexcept { - return (static_cast<unsigned __int128>(High_) << 64) + Low_; - } - - explicit constexpr operator signed __int128() const noexcept { - return (static_cast<__int128>(High_) << 64) + Low_; - } -#endif - -private: -#if defined(_little_endian_) - ui64 Low_; - ui64 High_; -#elif defined(_big_endian_) - ui64 High_; - ui64 Low_; -#endif - template <bool IsSigned2> - friend constexpr ui64 GetHigh(TInteger128<IsSigned2> value) noexcept; - - template <bool IsSigned2> - friend constexpr ui64 GetLow(TInteger128<IsSigned2> value) noexcept; - - friend IOutputStream& operator<<(IOutputStream& out, const TInteger128& other); -}; // class TInteger128 - -using ui128 = TInteger128<false>; -using i128 = TInteger128<true>; - -constexpr ui128 operator+(ui128 lhs, ui128 rhs) noexcept; -constexpr i128 operator+( i128 lhs, i128 rhs) noexcept; -constexpr ui128 operator-(ui128 lhs, ui128 rhs) noexcept; -constexpr i128 operator-( i128 lhs, i128 rhs) noexcept; -constexpr ui128 operator-(ui128 num) noexcept; -constexpr i128 operator-( i128 num) noexcept; -constexpr ui128 operator*(ui128 lhs, ui128 rhs) noexcept; -constexpr i128 operator*( i128 lhs, i128 rhs) noexcept; -constexpr ui128 operator/(ui128 lhs, ui128 rhs) noexcept; -constexpr i128 operator/( i128 lhs, i128 rhs) noexcept; -constexpr ui128 operator%(ui128 lhs, ui128 rhs) noexcept; -constexpr i128 operator%( i128 lhs, i128 rhs) noexcept; -constexpr ui128 operator|(ui128 lhs, ui128 rhs) noexcept; -constexpr i128 operator|( i128 lhs, i128 rhs) noexcept; -constexpr ui128 operator&(ui128 lhs, ui128 rhs) noexcept; -constexpr i128 operator&( i128 lhs, i128 rhs) noexcept; -constexpr ui128 operator^(ui128 lhs, ui128 rhs) noexcept; -constexpr i128 operator^( i128 lhs, i128 rhs) noexcept; -constexpr ui128 operator<<(ui128 lhs, int n) noexcept; -constexpr i128 operator<<( i128 lhs, int n) noexcept; -constexpr ui128 operator>>(ui128 lhs, int n) noexcept; -constexpr i128 operator>>( i128 lhs, int n) noexcept; - -template <bool IsSigned> -size_t MostSignificantBit(const TInteger128<IsSigned> v); - -namespace std { - //// type traits - template <bool IsSigned> - struct is_integral<TInteger128<IsSigned>> : public std::true_type{}; - - template <bool IsSigned> - struct is_class<TInteger128<IsSigned>> : public std::false_type{}; - - template <> - struct is_signed<ui128> : public std::false_type{}; - - template <> - struct is_signed<i128> : public std::true_type{}; -} - -template <bool IsSigned> -constexpr ui64 GetHigh(const TInteger128<IsSigned> value) noexcept { - return value.High_; -} - -template <bool IsSigned> -constexpr ui64 GetLow(const TInteger128<IsSigned> value) noexcept { - return value.Low_; -} - -template <class T, std::enable_if_t<std::is_same_v<std::remove_cv_t<T>, i128>>* = nullptr> -constexpr ui128 operator-(const ui128 lhs, const T rhs) noexcept { - return lhs - static_cast<ui128>(rhs); -} - -template <class T, std::enable_if_t<std::is_same_v<std::remove_cv_t<T>, ui128>>* = nullptr> -constexpr ui128 operator-(const i128 lhs, const T rhs) noexcept { - return static_cast<ui128>(lhs) - rhs; -} - -// specialize std templates -namespace std { - // numeric limits - // see full list at https://en.cppreference.com/w/cpp/types/numeric_limits - template <bool IsSigned> - struct numeric_limits<TInteger128<IsSigned>> { - static constexpr bool is_specialized = true; - static constexpr bool is_signed = IsSigned; - static constexpr bool is_integer = true; - static constexpr bool is_exact = true; - static constexpr bool has_infinity = false; - static constexpr bool has_quiet_NAN = false; - static constexpr bool has_signaling_NAN = false; - static constexpr float_denorm_style has_denorm = std::denorm_absent; - static constexpr bool has_denorm_loss = false; - static constexpr float_round_style round_style = std::round_toward_zero; - static constexpr bool is_iec559 = false; - static constexpr bool is_bounded = true; - static constexpr bool is_modulo = true; - static constexpr int digits = CHAR_BIT * sizeof(ui128) - (IsSigned ? 1 : 0); - static constexpr int digits10 = 38; // std::numeric_limits<ui128>::digits * std::log10(2); - static constexpr int max_digits10 = 0; - static constexpr int radix = 2; - static constexpr int min_exponent = 0; - static constexpr int min_exponent10 = 0; - static constexpr int max_exponent = 0; - static constexpr int max_exponent10 = 0; - static constexpr bool traps = std::numeric_limits<ui64>::traps; // same as of any other ui* - static constexpr bool tinyness_before = false; - - static constexpr TInteger128<IsSigned> min() noexcept { - if constexpr (IsSigned) { - return TInteger128<IsSigned>{ - static_cast<ui64>(std::numeric_limits<i64>::min()), - 0 - }; - } - else { - return 0; - } - } - - static constexpr TInteger128<IsSigned> lowest() noexcept { - return min(); - } - - static constexpr TInteger128<IsSigned> max() noexcept { - if constexpr (IsSigned) { - return TInteger128<IsSigned>{ - static_cast<ui64>(std::numeric_limits<i64>::max()), - std::numeric_limits<ui64>::max() - }; - } - else { - return TInteger128<IsSigned>{ - std::numeric_limits<ui64>::max(), - std::numeric_limits<ui64>::max() - }; - } - } - - static constexpr TInteger128<IsSigned> epsilon() noexcept { - return 0; - } - - static constexpr TInteger128<IsSigned> round_error() noexcept { - return 0; - } - - static constexpr TInteger128<IsSigned> infinity() noexcept { - return 0; - } - - static constexpr TInteger128<IsSigned> quiet_NAN() noexcept { - return 0; - } - - static constexpr TInteger128<IsSigned> signaling_NAN() noexcept { - return 0; - } - - static constexpr TInteger128<IsSigned> denorm_min() noexcept { - return 0; - } - }; - - constexpr bool signbit(const ui128 arg) noexcept { - Y_UNUSED(arg); - return false; - } - - constexpr bool signbit(const i128 arg) noexcept { - return GetHigh(arg) & 0x8000000000000000; - } - - constexpr ui128 abs(const ui128 arg) noexcept { - return arg; - } - - constexpr i128 abs(const i128 arg) noexcept { - return signbit(arg) ? (-arg) : arg; - } -} - -constexpr bool operator==(const ui128 lhs, const ui128 rhs) noexcept { - return GetLow(lhs) == GetLow(rhs) && GetHigh(lhs) == GetHigh(rhs); -} - -constexpr bool operator==(const i128 lhs, const i128 rhs) noexcept { - return GetLow(lhs) == GetLow(rhs) && GetHigh(lhs) == GetHigh(rhs); -} - -constexpr bool operator!=(const ui128 lhs, const ui128 rhs) noexcept { - return !(lhs == rhs); -} - -constexpr bool operator!=(const i128 lhs, const i128 rhs) noexcept { - return !(lhs == rhs); -} - -constexpr bool operator<(const ui128 lhs, const ui128 rhs) noexcept { - if (GetHigh(lhs) != GetHigh(rhs)) { - return GetHigh(lhs) < GetHigh(rhs); - } - - return GetLow(lhs) < GetLow(rhs); -} - -constexpr bool operator<(const i128 lhs, const i128 rhs) noexcept { - if (lhs == 0 && rhs == 0) { - return false; - } - - const bool lhsIsNegative = std::signbit(lhs); - const bool rhsIsNegative = std::signbit(rhs); - - if (lhsIsNegative && !rhsIsNegative) { - return true; - } - - if (!lhsIsNegative && rhsIsNegative) { - return false; - } - - // both are negative or both are positive - if (GetHigh(lhs) != GetHigh(rhs)) { - return GetHigh(lhs) < GetHigh(rhs); - } - - return GetLow(lhs) < GetLow(rhs); -} - -constexpr bool operator>(const ui128 lhs, const ui128 rhs) noexcept { - return rhs < lhs; -} - -constexpr bool operator>(const i128 lhs, const i128 rhs) noexcept { - return rhs < lhs; -} - -constexpr bool operator<=(const ui128 lhs, const ui128 rhs) noexcept { - return !(rhs < lhs); -} - -constexpr bool operator<=(const i128 lhs, const i128 rhs) noexcept { - return !(rhs < lhs); -} - -constexpr bool operator>=(const ui128 lhs, const ui128 rhs) noexcept { - return !(lhs < rhs); -} - -constexpr bool operator>=(const i128 lhs, const i128 rhs) noexcept { - return !(lhs < rhs); -} - -constexpr ui128 operator+(const ui128 lhs, const ui128 rhs) noexcept { - const ui128 result{GetHigh(lhs) + GetHigh(rhs), GetLow(lhs) + GetLow(rhs)}; - if (GetLow(result) < GetLow(lhs)) { - return ui128{GetHigh(result) + 1, GetLow(result)}; - } - return result; -} - -constexpr i128 operator+(const i128 lhs, const i128 rhs) noexcept { - const i128 result{GetHigh(lhs) + GetHigh(rhs), GetLow(lhs) + GetLow(rhs)}; - if (GetLow(result) < GetLow(lhs)) { - return i128{GetHigh(result) + 1, GetLow(result)}; - } - return result; -} - -constexpr ui128 operator-(const ui128 lhs, const ui128 rhs) noexcept { - const ui128 result{GetHigh(lhs) - GetHigh(rhs), GetLow(lhs) - GetLow(rhs)}; - if (GetLow(result) > GetLow(lhs)) { // underflow - return ui128{GetHigh(result) - 1, GetLow(result)}; - } - return result; -} - -constexpr i128 operator-(const i128 lhs, const i128 rhs) noexcept { - const i128 result{GetHigh(lhs) - GetHigh(rhs), GetLow(lhs) - GetLow(rhs)}; - if (GetLow(result) > GetLow(lhs)) { // underflow - return i128{GetHigh(result) - 1, GetLow(result)}; - } - return result; -} - -constexpr ui128 operator-(const ui128 num) noexcept { - const ui128 result{~GetHigh(num), ~GetLow(num) + 1}; - if (GetLow(result) == 0) { - return ui128{GetHigh(result) + 1, GetLow(result)}; - } - return result; -} - -constexpr i128 operator-(const i128 num) noexcept { - const i128 result{~GetHigh(num), ~GetLow(num) + 1}; - if (GetLow(result) == 0) { - return i128{GetHigh(result) + 1, GetLow(result)}; - } - return result; -} - -constexpr ui128 operator*(const ui128 lhs, const ui128 rhs) noexcept { - if (rhs == 0) { - return 0; - } - if (rhs == 1) { - return lhs; - } - - ui128 result{}; - ui128 t = rhs; - - for (size_t i = 0; i < 128; ++i) { - if ((t & 1) != 0) { - result += (lhs << i); - } - - t = t >> 1; - } - - return result; -} - -constexpr i128 operator*(const i128 lhs, const i128 rhs) noexcept { - if (rhs == 0) { - return 0; - } - if (rhs == 1) { - return lhs; - } - - i128 result{}; - i128 t = rhs; - - for (size_t i = 0; i < 128; ++i) { - if ((t & 1) != 0) { - result += (lhs << i); - } - - t = t >> 1; - } - - return result; -} - -namespace NPrivateInt128 { - // NOTE: division by zero is UB and can be changed in future - constexpr void DivMod128(const ui128 lhs, const ui128 rhs, ui128* const quo, ui128* const rem) { - if (!quo && !rem) { - return; - } - - constexpr size_t n_udword_bits = sizeof(ui64) * CHAR_BIT; - constexpr size_t n_utword_bits = sizeof(ui128) * CHAR_BIT; - - ui128 q{}; - ui128 r{}; - - unsigned sr{}; - - /* special cases, X is unknown, K != 0 */ - if (GetHigh(lhs) == 0) - { - if (GetHigh(rhs) == 0) - { - /* 0 X - * --- - * 0 X - */ - if (rem) { - *rem = GetLow(lhs) % GetLow(rhs); - } - if (quo) { - *quo = GetLow(lhs) / GetLow(rhs); - } - return; - } - /* 0 X - * --- - * K X - */ - if (rem) { - *rem = GetLow(lhs); - } - if (quo) { - *quo = 0; - } - return; - } - /* n.s.high != 0 */ - if (GetLow(rhs) == 0) - { - if (GetHigh(rhs) == 0) - { - /* K X - * --- - * 0 0 - */ - if (rem) { - *rem = GetHigh(lhs) % GetLow(rhs); - } - if (quo) { - *quo = GetHigh(lhs) / GetLow(rhs); - } - return; - } - /* d.s.high != 0 */ - if (GetLow(lhs) == 0) - { - /* K 0 - * --- - * K 0 - */ - if (rem) { - *rem = ui128{GetHigh(lhs) % GetHigh(rhs), 0}; - } - if (quo) { - *quo = GetHigh(lhs) / GetHigh(rhs); - } - return; - } - /* K K - * --- - * K 0 - */ - if ((GetHigh(rhs) & (GetHigh(rhs) - 1)) == 0) /* if d is a power of 2 */ - { - if (rem) { - *rem = ui128{GetHigh(lhs) & (GetHigh(rhs) - 1), GetLow(lhs)}; - } - if (quo) { - *quo = GetHigh(lhs) >> CountLeadingZeroBits(GetHigh(rhs)); - } - return; - } - /* K K - * --- - * K 0 - */ - sr = CountLeadingZeroBits(GetHigh(rhs)) - CountLeadingZeroBits(GetHigh(lhs)); - /* 0 <= sr <= n_udword_bits - 2 or sr large */ - if (sr > n_udword_bits - 2) - { - if (rem) { - *rem = lhs; - } - if (quo) { - *quo = 0; - } - return; - } - ++sr; - /* 1 <= sr <= n_udword_bits - 1 */ - /* q.all = n.all << (n_utword_bits - sr); */ - q = ui128{ - GetLow(lhs) << (n_udword_bits - sr), - 0 - }; - r = ui128{ - GetHigh(lhs) >> sr, - (GetHigh(lhs) << (n_udword_bits - sr)) | (GetLow(lhs) >> sr) - }; - } - else /* d.s.low != 0 */ - { - if (GetHigh(rhs) == 0) - { - /* K X - * --- - * 0 K - */ - if ((GetLow(rhs) & (GetLow(rhs) - 1)) == 0) /* if d is a power of 2 */ - { - if (rem) { - *rem = ui128{0, GetLow(lhs) & (GetLow(rhs) - 1)}; - } - if (GetLow(rhs) == 1) { - if (quo) { - *quo = lhs; - } - return; - } - sr = CountTrailingZeroBits(GetLow(rhs)); - if (quo) { - *quo = ui128{ - GetHigh(lhs) >> sr, - (GetHigh(lhs) << (n_udword_bits - sr)) | (GetLow(lhs) >> sr) - }; - return; - } - } - /* K X - * --- - * 0 K - */ - sr = 1 + n_udword_bits + CountLeadingZeroBits(GetLow(rhs)) - - CountLeadingZeroBits(GetHigh(lhs)); - /* 2 <= sr <= n_utword_bits - 1 - * q.all = n.all << (n_utword_bits - sr); - * r.all = n.all >> sr; - */ - if (sr == n_udword_bits) - { - q = ui128{GetLow(lhs), 0}; - r = ui128{0, GetHigh(lhs)}; - } - else if (sr < n_udword_bits) // 2 <= sr <= n_udword_bits - 1 - { - q = ui128{ - GetLow(lhs) << (n_udword_bits - sr), - 0 - }; - r = ui128{ - GetHigh(lhs) >> sr, - (GetHigh(lhs) << (n_udword_bits - sr)) | (GetLow(lhs) >> sr) - }; - } - else // n_udword_bits + 1 <= sr <= n_utword_bits - 1 - { - q = ui128{ - (GetHigh(lhs) << (n_utword_bits - sr)) | (GetLow(lhs) >> (sr - n_udword_bits)), - GetLow(lhs) << (n_utword_bits - sr) - }; - r = ui128{ - 0, - GetHigh(lhs) >> (sr - n_udword_bits) - }; - } - } - else - { - /* K X - * --- - * K K - */ - sr = CountLeadingZeroBits(GetHigh(rhs)) - CountLeadingZeroBits(GetHigh(lhs)); - /*0 <= sr <= n_udword_bits - 1 or sr large */ - if (sr > n_udword_bits - 1) - { - if (rem) { - *rem = lhs; - } - if (quo) { - *quo = 0; - } - return; - } - ++sr; - /* 1 <= sr <= n_udword_bits - * q.all = n.all << (n_utword_bits - sr); - * r.all = n.all >> sr; - */ - if (sr == n_udword_bits) - { - q = ui128{ - GetLow(lhs), - 0 - }; - r = ui128{ - 0, - GetHigh(lhs) - }; - } - else - { - r = ui128{ - GetHigh(lhs) >> sr, - (GetHigh(lhs) << (n_udword_bits - sr)) | (GetLow(lhs) >> sr) - }; - q = ui128{ - GetLow(lhs) << (n_udword_bits - sr), - 0 - }; - } - } - } - /* Not a special case - * q and r are initialized with: - * q = n << (128 - sr); - * r = n >> sr; - * 1 <= sr <= 128 - 1 - */ - ui32 carry = 0; - for (; sr > 0; --sr) - { - /* r:q = ((r:q) << 1) | carry */ - r = ui128{ - (GetHigh(r) << 1) | (GetLow(r) >> (n_udword_bits - 1)), - (GetLow(r) << 1) | (GetHigh(q) >> (n_udword_bits - 1)) - }; - q = ui128{ - (GetHigh(q) << 1) | (GetLow(q) >> (n_udword_bits - 1)), - (GetLow(q) << 1) | carry - }; - carry = 0; - if (r >= rhs) { - r -= rhs; - carry = 1; - } - } - q = (q << 1) | carry; - if (rem) { - *rem = r; - } - if (quo) { - *quo = q; - } - } - - struct TSignedDivisionResult { - i128 Quotient; - i128 Remainder; - }; - - constexpr TSignedDivisionResult Divide(i128 lhs, i128 rhs) noexcept; -} - -constexpr ui128 operator/(const ui128 lhs, const ui128 rhs) noexcept { - ui128 quotient{}; - NPrivateInt128::DivMod128(lhs, rhs, "ient, nullptr); - return quotient; -} - -constexpr i128 operator/(const i128 lhs, const i128 rhs) noexcept { - i128 a = std::abs(lhs); - i128 b = std::abs(rhs); - - ui128 quotient{}; - NPrivateInt128::DivMod128(a, b, "ient, nullptr); - if (std::signbit(lhs) ^ std::signbit(rhs)) { - quotient = -quotient; - } - return quotient; -} - -constexpr ui128 operator%(const ui128 lhs, const ui128 rhs) noexcept { - ui128 remainder{}; - NPrivateInt128::DivMod128(lhs, rhs, nullptr, &remainder); - return remainder; -} - -constexpr i128 operator%(const i128 lhs, const i128 rhs) noexcept { - i128 a = std::abs(lhs); - i128 b = std::abs(rhs); - ui128 remainder{}; - NPrivateInt128::DivMod128(a, b, nullptr, &remainder); - if (std::signbit(lhs)) { - remainder = -remainder; - } - return remainder; -} - -constexpr ui128 operator<<(const ui128 lhs, int n) noexcept { - if (n < 64) { - if (n != 0) { - return - ui128{ - (GetHigh(lhs) << n) | (GetLow(lhs) >> (64 - n)), - GetLow(lhs) << n - }; - } - return lhs; - } - return ui128{GetLow(lhs) << (n - 64), 0}; -} - -constexpr ui128 operator>>(const ui128 lhs, int n) noexcept { - if (n < 64) { - if (n != 0) { - return - ui128{ - GetHigh(lhs) >> n, - (GetLow(lhs) >> n) | (GetHigh(lhs) << (64 - n)) - }; - } - return lhs; - } - return ui128{0, GetHigh(lhs) >> (n - 64)}; -} - - -constexpr bool operator!(const ui128 num) noexcept { - return !GetHigh(num) && !GetLow(num); -} - -constexpr ui128 operator~(const ui128 num) noexcept { - return ui128{~GetHigh(num), ~GetLow(num)}; -} - -constexpr ui128 operator|(const ui128 lhs, const ui128 rhs) noexcept { - return ui128{GetHigh(lhs) | GetHigh(rhs), GetLow(lhs) | GetLow(rhs)}; -} - -constexpr ui128 operator&(const ui128 lhs, const ui128 rhs) noexcept { - return ui128{GetHigh(lhs) & GetHigh(rhs), GetLow(lhs) & GetLow(rhs)}; -} - -constexpr ui128 operator^(const ui128 lhs, const ui128 rhs) noexcept { - return ui128{GetHigh(lhs) ^ GetHigh(rhs), GetLow(lhs) ^ GetLow(rhs)}; -} - - -IOutputStream& operator<<(IOutputStream& out, const ui128& other); - -// For THashMap -template <> -struct THash<ui128> { - inline size_t operator()(const ui128& num) const { - return THash<ui64>()(GetHigh(num)) + THash<ui64>()(GetLow(num)); - } -}; - -template <> -class TSerializer<ui128> { -public: - static void Save(IOutputStream* out, const ui128& Number); - static void Load(IInputStream* in, ui128& Number); -}; - -template <> -inline TString ToString<ui128>(const ui128& number) { - return TStringBuilder{} << number; -} - -template <> -inline ui128 FromStringImpl<ui128>(const char* data, size_t length) { - if (length < 20) { - return ui128{ FromString<ui64>(data, length) }; - } else { - ui128 result = 0; - const TStringBuf string(data, length); - for (auto&& c : string) { - if (!std::isdigit(c)) { + } + + constexpr TInteger128& operator|=(const TInteger128 other) noexcept { + return *this = *this | other; + } + + constexpr TInteger128& operator<<=(int n) noexcept { + *this = *this << n; + return *this; + } + + constexpr TInteger128& operator>>=(int n) noexcept { + *this = *this >> n; + return *this; + } + + constexpr TInteger128& operator++() noexcept { + *this += 1; + return *this; + } + + constexpr TInteger128 operator++(int) noexcept { + const TInteger128 ret{*this}; + this->operator++(); + return ret; + } + + constexpr TInteger128& operator--() noexcept { + *this -= 1; + return *this; + } + + constexpr TInteger128 operator--(int) noexcept { + const TInteger128 ret{*this}; + this->operator--(); + return ret; + } + + explicit constexpr operator bool() const noexcept { + return Low_ || High_; + } + + explicit constexpr operator char() const noexcept { + return static_cast<char>(Low_); + } + + explicit constexpr operator ui8() const noexcept { + return static_cast<ui8>(Low_); + } + + explicit constexpr operator i8() const noexcept { + return static_cast<i8>(Low_); + } + + explicit constexpr operator ui16() const noexcept { + return static_cast<ui16>(Low_); + } + + explicit constexpr operator i16() const noexcept { + return static_cast<i16>(Low_); + } + + explicit constexpr operator ui32() const noexcept { + return static_cast<ui32>(Low_); + } + + explicit constexpr operator i32() const noexcept { + return static_cast<i32>(Low_); + } + + explicit constexpr operator ui64() const noexcept { + return static_cast<ui64>(Low_); + } + + explicit constexpr operator i64() const noexcept { + return static_cast<i64>(Low_); + } + +#if defined(Y_HAVE_INT128) + explicit constexpr operator unsigned __int128() const noexcept { + return (static_cast<unsigned __int128>(High_) << 64) + Low_; + } + + explicit constexpr operator signed __int128() const noexcept { + return (static_cast<__int128>(High_) << 64) + Low_; + } +#endif + +private: +#if defined(_little_endian_) + ui64 Low_; + ui64 High_; +#elif defined(_big_endian_) + ui64 High_; + ui64 Low_; +#endif + template <bool IsSigned2> + friend constexpr ui64 GetHigh(TInteger128<IsSigned2> value) noexcept; + + template <bool IsSigned2> + friend constexpr ui64 GetLow(TInteger128<IsSigned2> value) noexcept; + + friend IOutputStream& operator<<(IOutputStream& out, const TInteger128& other); +}; // class TInteger128 + +using ui128 = TInteger128<false>; +using i128 = TInteger128<true>; + +constexpr ui128 operator+(ui128 lhs, ui128 rhs) noexcept; +constexpr i128 operator+( i128 lhs, i128 rhs) noexcept; +constexpr ui128 operator-(ui128 lhs, ui128 rhs) noexcept; +constexpr i128 operator-( i128 lhs, i128 rhs) noexcept; +constexpr ui128 operator-(ui128 num) noexcept; +constexpr i128 operator-( i128 num) noexcept; +constexpr ui128 operator*(ui128 lhs, ui128 rhs) noexcept; +constexpr i128 operator*( i128 lhs, i128 rhs) noexcept; +constexpr ui128 operator/(ui128 lhs, ui128 rhs) noexcept; +constexpr i128 operator/( i128 lhs, i128 rhs) noexcept; +constexpr ui128 operator%(ui128 lhs, ui128 rhs) noexcept; +constexpr i128 operator%( i128 lhs, i128 rhs) noexcept; +constexpr ui128 operator|(ui128 lhs, ui128 rhs) noexcept; +constexpr i128 operator|( i128 lhs, i128 rhs) noexcept; +constexpr ui128 operator&(ui128 lhs, ui128 rhs) noexcept; +constexpr i128 operator&( i128 lhs, i128 rhs) noexcept; +constexpr ui128 operator^(ui128 lhs, ui128 rhs) noexcept; +constexpr i128 operator^( i128 lhs, i128 rhs) noexcept; +constexpr ui128 operator<<(ui128 lhs, int n) noexcept; +constexpr i128 operator<<( i128 lhs, int n) noexcept; +constexpr ui128 operator>>(ui128 lhs, int n) noexcept; +constexpr i128 operator>>( i128 lhs, int n) noexcept; + +template <bool IsSigned> +size_t MostSignificantBit(const TInteger128<IsSigned> v); + +namespace std { + //// type traits + template <bool IsSigned> + struct is_integral<TInteger128<IsSigned>> : public std::true_type{}; + + template <bool IsSigned> + struct is_class<TInteger128<IsSigned>> : public std::false_type{}; + + template <> + struct is_signed<ui128> : public std::false_type{}; + + template <> + struct is_signed<i128> : public std::true_type{}; +} + +template <bool IsSigned> +constexpr ui64 GetHigh(const TInteger128<IsSigned> value) noexcept { + return value.High_; +} + +template <bool IsSigned> +constexpr ui64 GetLow(const TInteger128<IsSigned> value) noexcept { + return value.Low_; +} + +template <class T, std::enable_if_t<std::is_same_v<std::remove_cv_t<T>, i128>>* = nullptr> +constexpr ui128 operator-(const ui128 lhs, const T rhs) noexcept { + return lhs - static_cast<ui128>(rhs); +} + +template <class T, std::enable_if_t<std::is_same_v<std::remove_cv_t<T>, ui128>>* = nullptr> +constexpr ui128 operator-(const i128 lhs, const T rhs) noexcept { + return static_cast<ui128>(lhs) - rhs; +} + +// specialize std templates +namespace std { + // numeric limits + // see full list at https://en.cppreference.com/w/cpp/types/numeric_limits + template <bool IsSigned> + struct numeric_limits<TInteger128<IsSigned>> { + static constexpr bool is_specialized = true; + static constexpr bool is_signed = IsSigned; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NAN = false; + static constexpr bool has_signaling_NAN = false; + static constexpr float_denorm_style has_denorm = std::denorm_absent; + static constexpr bool has_denorm_loss = false; + static constexpr float_round_style round_style = std::round_toward_zero; + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = true; + static constexpr int digits = CHAR_BIT * sizeof(ui128) - (IsSigned ? 1 : 0); + static constexpr int digits10 = 38; // std::numeric_limits<ui128>::digits * std::log10(2); + static constexpr int max_digits10 = 0; + static constexpr int radix = 2; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + static constexpr bool traps = std::numeric_limits<ui64>::traps; // same as of any other ui* + static constexpr bool tinyness_before = false; + + static constexpr TInteger128<IsSigned> min() noexcept { + if constexpr (IsSigned) { + return TInteger128<IsSigned>{ + static_cast<ui64>(std::numeric_limits<i64>::min()), + 0 + }; + } + else { + return 0; + } + } + + static constexpr TInteger128<IsSigned> lowest() noexcept { + return min(); + } + + static constexpr TInteger128<IsSigned> max() noexcept { + if constexpr (IsSigned) { + return TInteger128<IsSigned>{ + static_cast<ui64>(std::numeric_limits<i64>::max()), + std::numeric_limits<ui64>::max() + }; + } + else { + return TInteger128<IsSigned>{ + std::numeric_limits<ui64>::max(), + std::numeric_limits<ui64>::max() + }; + } + } + + static constexpr TInteger128<IsSigned> epsilon() noexcept { + return 0; + } + + static constexpr TInteger128<IsSigned> round_error() noexcept { + return 0; + } + + static constexpr TInteger128<IsSigned> infinity() noexcept { + return 0; + } + + static constexpr TInteger128<IsSigned> quiet_NAN() noexcept { + return 0; + } + + static constexpr TInteger128<IsSigned> signaling_NAN() noexcept { + return 0; + } + + static constexpr TInteger128<IsSigned> denorm_min() noexcept { + return 0; + } + }; + + constexpr bool signbit(const ui128 arg) noexcept { + Y_UNUSED(arg); + return false; + } + + constexpr bool signbit(const i128 arg) noexcept { + return GetHigh(arg) & 0x8000000000000000; + } + + constexpr ui128 abs(const ui128 arg) noexcept { + return arg; + } + + constexpr i128 abs(const i128 arg) noexcept { + return signbit(arg) ? (-arg) : arg; + } +} + +constexpr bool operator==(const ui128 lhs, const ui128 rhs) noexcept { + return GetLow(lhs) == GetLow(rhs) && GetHigh(lhs) == GetHigh(rhs); +} + +constexpr bool operator==(const i128 lhs, const i128 rhs) noexcept { + return GetLow(lhs) == GetLow(rhs) && GetHigh(lhs) == GetHigh(rhs); +} + +constexpr bool operator!=(const ui128 lhs, const ui128 rhs) noexcept { + return !(lhs == rhs); +} + +constexpr bool operator!=(const i128 lhs, const i128 rhs) noexcept { + return !(lhs == rhs); +} + +constexpr bool operator<(const ui128 lhs, const ui128 rhs) noexcept { + if (GetHigh(lhs) != GetHigh(rhs)) { + return GetHigh(lhs) < GetHigh(rhs); + } + + return GetLow(lhs) < GetLow(rhs); +} + +constexpr bool operator<(const i128 lhs, const i128 rhs) noexcept { + if (lhs == 0 && rhs == 0) { + return false; + } + + const bool lhsIsNegative = std::signbit(lhs); + const bool rhsIsNegative = std::signbit(rhs); + + if (lhsIsNegative && !rhsIsNegative) { + return true; + } + + if (!lhsIsNegative && rhsIsNegative) { + return false; + } + + // both are negative or both are positive + if (GetHigh(lhs) != GetHigh(rhs)) { + return GetHigh(lhs) < GetHigh(rhs); + } + + return GetLow(lhs) < GetLow(rhs); +} + +constexpr bool operator>(const ui128 lhs, const ui128 rhs) noexcept { + return rhs < lhs; +} + +constexpr bool operator>(const i128 lhs, const i128 rhs) noexcept { + return rhs < lhs; +} + +constexpr bool operator<=(const ui128 lhs, const ui128 rhs) noexcept { + return !(rhs < lhs); +} + +constexpr bool operator<=(const i128 lhs, const i128 rhs) noexcept { + return !(rhs < lhs); +} + +constexpr bool operator>=(const ui128 lhs, const ui128 rhs) noexcept { + return !(lhs < rhs); +} + +constexpr bool operator>=(const i128 lhs, const i128 rhs) noexcept { + return !(lhs < rhs); +} + +constexpr ui128 operator+(const ui128 lhs, const ui128 rhs) noexcept { + const ui128 result{GetHigh(lhs) + GetHigh(rhs), GetLow(lhs) + GetLow(rhs)}; + if (GetLow(result) < GetLow(lhs)) { + return ui128{GetHigh(result) + 1, GetLow(result)}; + } + return result; +} + +constexpr i128 operator+(const i128 lhs, const i128 rhs) noexcept { + const i128 result{GetHigh(lhs) + GetHigh(rhs), GetLow(lhs) + GetLow(rhs)}; + if (GetLow(result) < GetLow(lhs)) { + return i128{GetHigh(result) + 1, GetLow(result)}; + } + return result; +} + +constexpr ui128 operator-(const ui128 lhs, const ui128 rhs) noexcept { + const ui128 result{GetHigh(lhs) - GetHigh(rhs), GetLow(lhs) - GetLow(rhs)}; + if (GetLow(result) > GetLow(lhs)) { // underflow + return ui128{GetHigh(result) - 1, GetLow(result)}; + } + return result; +} + +constexpr i128 operator-(const i128 lhs, const i128 rhs) noexcept { + const i128 result{GetHigh(lhs) - GetHigh(rhs), GetLow(lhs) - GetLow(rhs)}; + if (GetLow(result) > GetLow(lhs)) { // underflow + return i128{GetHigh(result) - 1, GetLow(result)}; + } + return result; +} + +constexpr ui128 operator-(const ui128 num) noexcept { + const ui128 result{~GetHigh(num), ~GetLow(num) + 1}; + if (GetLow(result) == 0) { + return ui128{GetHigh(result) + 1, GetLow(result)}; + } + return result; +} + +constexpr i128 operator-(const i128 num) noexcept { + const i128 result{~GetHigh(num), ~GetLow(num) + 1}; + if (GetLow(result) == 0) { + return i128{GetHigh(result) + 1, GetLow(result)}; + } + return result; +} + +constexpr ui128 operator*(const ui128 lhs, const ui128 rhs) noexcept { + if (rhs == 0) { + return 0; + } + if (rhs == 1) { + return lhs; + } + + ui128 result{}; + ui128 t = rhs; + + for (size_t i = 0; i < 128; ++i) { + if ((t & 1) != 0) { + result += (lhs << i); + } + + t = t >> 1; + } + + return result; +} + +constexpr i128 operator*(const i128 lhs, const i128 rhs) noexcept { + if (rhs == 0) { + return 0; + } + if (rhs == 1) { + return lhs; + } + + i128 result{}; + i128 t = rhs; + + for (size_t i = 0; i < 128; ++i) { + if ((t & 1) != 0) { + result += (lhs << i); + } + + t = t >> 1; + } + + return result; +} + +namespace NPrivateInt128 { + // NOTE: division by zero is UB and can be changed in future + constexpr void DivMod128(const ui128 lhs, const ui128 rhs, ui128* const quo, ui128* const rem) { + if (!quo && !rem) { + return; + } + + constexpr size_t n_udword_bits = sizeof(ui64) * CHAR_BIT; + constexpr size_t n_utword_bits = sizeof(ui128) * CHAR_BIT; + + ui128 q{}; + ui128 r{}; + + unsigned sr{}; + + /* special cases, X is unknown, K != 0 */ + if (GetHigh(lhs) == 0) + { + if (GetHigh(rhs) == 0) + { + /* 0 X + * --- + * 0 X + */ + if (rem) { + *rem = GetLow(lhs) % GetLow(rhs); + } + if (quo) { + *quo = GetLow(lhs) / GetLow(rhs); + } + return; + } + /* 0 X + * --- + * K X + */ + if (rem) { + *rem = GetLow(lhs); + } + if (quo) { + *quo = 0; + } + return; + } + /* n.s.high != 0 */ + if (GetLow(rhs) == 0) + { + if (GetHigh(rhs) == 0) + { + /* K X + * --- + * 0 0 + */ + if (rem) { + *rem = GetHigh(lhs) % GetLow(rhs); + } + if (quo) { + *quo = GetHigh(lhs) / GetLow(rhs); + } + return; + } + /* d.s.high != 0 */ + if (GetLow(lhs) == 0) + { + /* K 0 + * --- + * K 0 + */ + if (rem) { + *rem = ui128{GetHigh(lhs) % GetHigh(rhs), 0}; + } + if (quo) { + *quo = GetHigh(lhs) / GetHigh(rhs); + } + return; + } + /* K K + * --- + * K 0 + */ + if ((GetHigh(rhs) & (GetHigh(rhs) - 1)) == 0) /* if d is a power of 2 */ + { + if (rem) { + *rem = ui128{GetHigh(lhs) & (GetHigh(rhs) - 1), GetLow(lhs)}; + } + if (quo) { + *quo = GetHigh(lhs) >> CountLeadingZeroBits(GetHigh(rhs)); + } + return; + } + /* K K + * --- + * K 0 + */ + sr = CountLeadingZeroBits(GetHigh(rhs)) - CountLeadingZeroBits(GetHigh(lhs)); + /* 0 <= sr <= n_udword_bits - 2 or sr large */ + if (sr > n_udword_bits - 2) + { + if (rem) { + *rem = lhs; + } + if (quo) { + *quo = 0; + } + return; + } + ++sr; + /* 1 <= sr <= n_udword_bits - 1 */ + /* q.all = n.all << (n_utword_bits - sr); */ + q = ui128{ + GetLow(lhs) << (n_udword_bits - sr), + 0 + }; + r = ui128{ + GetHigh(lhs) >> sr, + (GetHigh(lhs) << (n_udword_bits - sr)) | (GetLow(lhs) >> sr) + }; + } + else /* d.s.low != 0 */ + { + if (GetHigh(rhs) == 0) + { + /* K X + * --- + * 0 K + */ + if ((GetLow(rhs) & (GetLow(rhs) - 1)) == 0) /* if d is a power of 2 */ + { + if (rem) { + *rem = ui128{0, GetLow(lhs) & (GetLow(rhs) - 1)}; + } + if (GetLow(rhs) == 1) { + if (quo) { + *quo = lhs; + } + return; + } + sr = CountTrailingZeroBits(GetLow(rhs)); + if (quo) { + *quo = ui128{ + GetHigh(lhs) >> sr, + (GetHigh(lhs) << (n_udword_bits - sr)) | (GetLow(lhs) >> sr) + }; + return; + } + } + /* K X + * --- + * 0 K + */ + sr = 1 + n_udword_bits + CountLeadingZeroBits(GetLow(rhs)) + - CountLeadingZeroBits(GetHigh(lhs)); + /* 2 <= sr <= n_utword_bits - 1 + * q.all = n.all << (n_utword_bits - sr); + * r.all = n.all >> sr; + */ + if (sr == n_udword_bits) + { + q = ui128{GetLow(lhs), 0}; + r = ui128{0, GetHigh(lhs)}; + } + else if (sr < n_udword_bits) // 2 <= sr <= n_udword_bits - 1 + { + q = ui128{ + GetLow(lhs) << (n_udword_bits - sr), + 0 + }; + r = ui128{ + GetHigh(lhs) >> sr, + (GetHigh(lhs) << (n_udword_bits - sr)) | (GetLow(lhs) >> sr) + }; + } + else // n_udword_bits + 1 <= sr <= n_utword_bits - 1 + { + q = ui128{ + (GetHigh(lhs) << (n_utword_bits - sr)) | (GetLow(lhs) >> (sr - n_udword_bits)), + GetLow(lhs) << (n_utword_bits - sr) + }; + r = ui128{ + 0, + GetHigh(lhs) >> (sr - n_udword_bits) + }; + } + } + else + { + /* K X + * --- + * K K + */ + sr = CountLeadingZeroBits(GetHigh(rhs)) - CountLeadingZeroBits(GetHigh(lhs)); + /*0 <= sr <= n_udword_bits - 1 or sr large */ + if (sr > n_udword_bits - 1) + { + if (rem) { + *rem = lhs; + } + if (quo) { + *quo = 0; + } + return; + } + ++sr; + /* 1 <= sr <= n_udword_bits + * q.all = n.all << (n_utword_bits - sr); + * r.all = n.all >> sr; + */ + if (sr == n_udword_bits) + { + q = ui128{ + GetLow(lhs), + 0 + }; + r = ui128{ + 0, + GetHigh(lhs) + }; + } + else + { + r = ui128{ + GetHigh(lhs) >> sr, + (GetHigh(lhs) << (n_udword_bits - sr)) | (GetLow(lhs) >> sr) + }; + q = ui128{ + GetLow(lhs) << (n_udword_bits - sr), + 0 + }; + } + } + } + /* Not a special case + * q and r are initialized with: + * q = n << (128 - sr); + * r = n >> sr; + * 1 <= sr <= 128 - 1 + */ + ui32 carry = 0; + for (; sr > 0; --sr) + { + /* r:q = ((r:q) << 1) | carry */ + r = ui128{ + (GetHigh(r) << 1) | (GetLow(r) >> (n_udword_bits - 1)), + (GetLow(r) << 1) | (GetHigh(q) >> (n_udword_bits - 1)) + }; + q = ui128{ + (GetHigh(q) << 1) | (GetLow(q) >> (n_udword_bits - 1)), + (GetLow(q) << 1) | carry + }; + carry = 0; + if (r >= rhs) { + r -= rhs; + carry = 1; + } + } + q = (q << 1) | carry; + if (rem) { + *rem = r; + } + if (quo) { + *quo = q; + } + } + + struct TSignedDivisionResult { + i128 Quotient; + i128 Remainder; + }; + + constexpr TSignedDivisionResult Divide(i128 lhs, i128 rhs) noexcept; +} + +constexpr ui128 operator/(const ui128 lhs, const ui128 rhs) noexcept { + ui128 quotient{}; + NPrivateInt128::DivMod128(lhs, rhs, "ient, nullptr); + return quotient; +} + +constexpr i128 operator/(const i128 lhs, const i128 rhs) noexcept { + i128 a = std::abs(lhs); + i128 b = std::abs(rhs); + + ui128 quotient{}; + NPrivateInt128::DivMod128(a, b, "ient, nullptr); + if (std::signbit(lhs) ^ std::signbit(rhs)) { + quotient = -quotient; + } + return quotient; +} + +constexpr ui128 operator%(const ui128 lhs, const ui128 rhs) noexcept { + ui128 remainder{}; + NPrivateInt128::DivMod128(lhs, rhs, nullptr, &remainder); + return remainder; +} + +constexpr i128 operator%(const i128 lhs, const i128 rhs) noexcept { + i128 a = std::abs(lhs); + i128 b = std::abs(rhs); + ui128 remainder{}; + NPrivateInt128::DivMod128(a, b, nullptr, &remainder); + if (std::signbit(lhs)) { + remainder = -remainder; + } + return remainder; +} + +constexpr ui128 operator<<(const ui128 lhs, int n) noexcept { + if (n < 64) { + if (n != 0) { + return + ui128{ + (GetHigh(lhs) << n) | (GetLow(lhs) >> (64 - n)), + GetLow(lhs) << n + }; + } + return lhs; + } + return ui128{GetLow(lhs) << (n - 64), 0}; +} + +constexpr ui128 operator>>(const ui128 lhs, int n) noexcept { + if (n < 64) { + if (n != 0) { + return + ui128{ + GetHigh(lhs) >> n, + (GetLow(lhs) >> n) | (GetHigh(lhs) << (64 - n)) + }; + } + return lhs; + } + return ui128{0, GetHigh(lhs) >> (n - 64)}; +} + + +constexpr bool operator!(const ui128 num) noexcept { + return !GetHigh(num) && !GetLow(num); +} + +constexpr ui128 operator~(const ui128 num) noexcept { + return ui128{~GetHigh(num), ~GetLow(num)}; +} + +constexpr ui128 operator|(const ui128 lhs, const ui128 rhs) noexcept { + return ui128{GetHigh(lhs) | GetHigh(rhs), GetLow(lhs) | GetLow(rhs)}; +} + +constexpr ui128 operator&(const ui128 lhs, const ui128 rhs) noexcept { + return ui128{GetHigh(lhs) & GetHigh(rhs), GetLow(lhs) & GetLow(rhs)}; +} + +constexpr ui128 operator^(const ui128 lhs, const ui128 rhs) noexcept { + return ui128{GetHigh(lhs) ^ GetHigh(rhs), GetLow(lhs) ^ GetLow(rhs)}; +} + + +IOutputStream& operator<<(IOutputStream& out, const ui128& other); + +// For THashMap +template <> +struct THash<ui128> { + inline size_t operator()(const ui128& num) const { + return THash<ui64>()(GetHigh(num)) + THash<ui64>()(GetLow(num)); + } +}; + +template <> +class TSerializer<ui128> { +public: + static void Save(IOutputStream* out, const ui128& Number); + static void Load(IInputStream* in, ui128& Number); +}; + +template <> +inline TString ToString<ui128>(const ui128& number) { + return TStringBuilder{} << number; +} + +template <> +inline ui128 FromStringImpl<ui128>(const char* data, size_t length) { + if (length < 20) { + return ui128{ FromString<ui64>(data, length) }; + } else { + ui128 result = 0; + const TStringBuf string(data, length); + for (auto&& c : string) { + if (!std::isdigit(c)) { ythrow TFromStringException() << "Unexpected symbol \""sv << c << "\""sv; - } - - ui128 x1 = result; - ui128 x2 = x1 + x1; - ui128 x4 = x2 + x2; - ui128 x8 = x4 + x4; - ui128 x10 = x8 + x2; - ui128 s = c - '0'; - result = x10 + s; - - if (GetHigh(result) < GetHigh(x1)) { + } + + ui128 x1 = result; + ui128 x2 = x1 + x1; + ui128 x4 = x2 + x2; + ui128 x8 = x4 + x4; + ui128 x10 = x8 + x2; + ui128 s = c - '0'; + result = x10 + s; + + if (GetHigh(result) < GetHigh(x1)) { ythrow TFromStringException() << TStringBuf("Integer overflow"); - } - } - - return result; - } -} - -#if defined(Y_HAVE_INT128) -template <> -inline TString ToString<unsigned __int128>(const unsigned __int128& number) { - return ToString(ui128{number}); -} - -template <> -inline unsigned __int128 FromStringImpl<unsigned __int128>(const char* data, size_t length) { - return static_cast<unsigned __int128>(FromString<ui128>(data, length)); -} -#endif - -// operators - - -namespace NPrivateInt128 { - // very naive algorithm of division - // no contract for divide by zero (i.e. it is UB) (may be changed in future) - constexpr TSignedDivisionResult Divide(i128 lhs, i128 rhs) noexcept { - TSignedDivisionResult result {}; - - // check trivial cases - // X/0 = +/- inf, X%0 = X - if (rhs == 0) { - // UB, let's return: `X / 0 = +inf`, and `X % 0 = X` - result.Quotient = std::signbit(lhs) ? std::numeric_limits<i128>::min() : std::numeric_limits<i128>::max(); - result.Remainder = lhs; - } - - // 0/Y = 0, 0%Y = 0 - else if (lhs == 0) { - result.Quotient = 0; - result.Remainder = 0; - } - - // X/1 = X, X%1 = 0 - else if (rhs == 1) { - result.Quotient = lhs; - result.Remainder = 0; - } - - // X/-1 = -X, X%(-1) = 0 - else if (rhs == -1) { - result.Quotient = -lhs; - result.Remainder = 0; - } - - // abs(X)<abs(Y), X/Y = 0, X%Y = X - else if (std::abs(lhs) < std::abs(rhs)) { - result.Quotient = 0; - result.Remainder = lhs; - } - - else if (lhs == rhs) { - result.Quotient = 1; - result.Remainder = 0; - } - - else if (lhs == -rhs) { - result.Quotient = -1; - result.Remainder = 0; - } - - else if (std::abs(lhs) > std::abs(rhs)) { - const bool quotientMustBeNegative = std::signbit(lhs) ^ std::signbit(rhs); - const bool remainderMustBeNegative = std::signbit(lhs); - - lhs = std::abs(lhs); - rhs = std::abs(rhs); - - // result is division of two ui64 - if (GetHigh(lhs) == 0 && GetHigh(rhs) == 0) { - result.Quotient = GetLow(lhs) / GetLow(rhs); - result.Remainder = GetLow(lhs) % GetLow(rhs); - } - - // naive shift-and-subtract - // https://stackoverflow.com/questions/5386377/division-without-using - i128 denominator = rhs; - result.Quotient = 0; - result.Remainder = lhs; - - const size_t shift = MostSignificantBit(lhs) - MostSignificantBit(denominator); - denominator <<= shift; - - for (size_t i = 0; i <= shift; ++i) { - result.Quotient <<= 1; - if (result.Remainder >= denominator) { - result.Remainder -= denominator; - result.Quotient |= 1; - } - denominator >>= 1; - } - - if (quotientMustBeNegative) { - result.Quotient = -result.Quotient; - } - - if (remainderMustBeNegative) { - result.Remainder = -result.Remainder; - } - } - - return result; - } -} // namespace NPrivateInt128 - -constexpr i128 operator<<(const i128 lhs, int n) noexcept { - if (n < 64) { - if (n != 0) { - return - i128{ - (GetHigh(lhs) << n) | (GetLow(lhs) >> (64 - n)), - GetLow(lhs) << n - }; - } - return lhs; - } - return i128{GetLow(lhs) << (n - 64), 0}; -} - -constexpr i128 operator>>(const i128 lhs, int n) noexcept { - if (n < 64) { - if (n != 0) { - return - i128{ - GetHigh(lhs) >> n, - (GetLow(lhs) >> n) | (GetHigh(lhs) << (64 - n)) - }; - } - return lhs; - } - return i128{0, GetHigh(lhs) >> (n - 64)}; -} - -constexpr bool operator!(const i128 num) noexcept { - return !GetHigh(num) && !GetLow(num); -} - -constexpr i128 operator~(const i128 num) noexcept { - return i128{~GetHigh(num), ~GetLow(num)}; -} - -constexpr i128 operator|(const i128 lhs, const i128 rhs) noexcept { - return i128{GetHigh(lhs) | GetHigh(rhs), GetLow(lhs) | GetLow(rhs)}; -} - -constexpr i128 operator&(const i128 lhs, const i128 rhs) noexcept { - return i128{GetHigh(lhs) & GetHigh(rhs), GetLow(lhs) & GetLow(rhs)}; -} - -constexpr i128 operator^(const i128 lhs, const i128 rhs) noexcept { - return i128{GetHigh(lhs) ^ GetHigh(rhs), GetLow(lhs) ^ GetLow(rhs)}; -} - - -IOutputStream& operator<<(IOutputStream& out, const i128& other); - -// For THashMap -template <> -struct THash<i128> { - inline size_t operator()(const i128& num) const { - return THash<ui64>()(GetHigh(num)) + THash<ui64>()(GetLow(num)); - } -}; - -template <> -class TSerializer<i128> { -public: - static void Save(IOutputStream* out, const i128& Number); - static void Load(IInputStream* in, i128& Number); -}; - -template <> -inline TString ToString<i128>(const i128& number) { - return TStringBuilder{} << number; -} - -template <> -inline i128 FromStringImpl<i128>(const char* data, size_t length) { - if (length < 20) { - return i128{ FromString<ui64>(data, length) }; - } else { - i128 result = 0; - const TStringBuf string(data, length); - for (auto&& c : string) { - if (!std::isdigit(c)) { + } + } + + return result; + } +} + +#if defined(Y_HAVE_INT128) +template <> +inline TString ToString<unsigned __int128>(const unsigned __int128& number) { + return ToString(ui128{number}); +} + +template <> +inline unsigned __int128 FromStringImpl<unsigned __int128>(const char* data, size_t length) { + return static_cast<unsigned __int128>(FromString<ui128>(data, length)); +} +#endif + +// operators + + +namespace NPrivateInt128 { + // very naive algorithm of division + // no contract for divide by zero (i.e. it is UB) (may be changed in future) + constexpr TSignedDivisionResult Divide(i128 lhs, i128 rhs) noexcept { + TSignedDivisionResult result {}; + + // check trivial cases + // X/0 = +/- inf, X%0 = X + if (rhs == 0) { + // UB, let's return: `X / 0 = +inf`, and `X % 0 = X` + result.Quotient = std::signbit(lhs) ? std::numeric_limits<i128>::min() : std::numeric_limits<i128>::max(); + result.Remainder = lhs; + } + + // 0/Y = 0, 0%Y = 0 + else if (lhs == 0) { + result.Quotient = 0; + result.Remainder = 0; + } + + // X/1 = X, X%1 = 0 + else if (rhs == 1) { + result.Quotient = lhs; + result.Remainder = 0; + } + + // X/-1 = -X, X%(-1) = 0 + else if (rhs == -1) { + result.Quotient = -lhs; + result.Remainder = 0; + } + + // abs(X)<abs(Y), X/Y = 0, X%Y = X + else if (std::abs(lhs) < std::abs(rhs)) { + result.Quotient = 0; + result.Remainder = lhs; + } + + else if (lhs == rhs) { + result.Quotient = 1; + result.Remainder = 0; + } + + else if (lhs == -rhs) { + result.Quotient = -1; + result.Remainder = 0; + } + + else if (std::abs(lhs) > std::abs(rhs)) { + const bool quotientMustBeNegative = std::signbit(lhs) ^ std::signbit(rhs); + const bool remainderMustBeNegative = std::signbit(lhs); + + lhs = std::abs(lhs); + rhs = std::abs(rhs); + + // result is division of two ui64 + if (GetHigh(lhs) == 0 && GetHigh(rhs) == 0) { + result.Quotient = GetLow(lhs) / GetLow(rhs); + result.Remainder = GetLow(lhs) % GetLow(rhs); + } + + // naive shift-and-subtract + // https://stackoverflow.com/questions/5386377/division-without-using + i128 denominator = rhs; + result.Quotient = 0; + result.Remainder = lhs; + + const size_t shift = MostSignificantBit(lhs) - MostSignificantBit(denominator); + denominator <<= shift; + + for (size_t i = 0; i <= shift; ++i) { + result.Quotient <<= 1; + if (result.Remainder >= denominator) { + result.Remainder -= denominator; + result.Quotient |= 1; + } + denominator >>= 1; + } + + if (quotientMustBeNegative) { + result.Quotient = -result.Quotient; + } + + if (remainderMustBeNegative) { + result.Remainder = -result.Remainder; + } + } + + return result; + } +} // namespace NPrivateInt128 + +constexpr i128 operator<<(const i128 lhs, int n) noexcept { + if (n < 64) { + if (n != 0) { + return + i128{ + (GetHigh(lhs) << n) | (GetLow(lhs) >> (64 - n)), + GetLow(lhs) << n + }; + } + return lhs; + } + return i128{GetLow(lhs) << (n - 64), 0}; +} + +constexpr i128 operator>>(const i128 lhs, int n) noexcept { + if (n < 64) { + if (n != 0) { + return + i128{ + GetHigh(lhs) >> n, + (GetLow(lhs) >> n) | (GetHigh(lhs) << (64 - n)) + }; + } + return lhs; + } + return i128{0, GetHigh(lhs) >> (n - 64)}; +} + +constexpr bool operator!(const i128 num) noexcept { + return !GetHigh(num) && !GetLow(num); +} + +constexpr i128 operator~(const i128 num) noexcept { + return i128{~GetHigh(num), ~GetLow(num)}; +} + +constexpr i128 operator|(const i128 lhs, const i128 rhs) noexcept { + return i128{GetHigh(lhs) | GetHigh(rhs), GetLow(lhs) | GetLow(rhs)}; +} + +constexpr i128 operator&(const i128 lhs, const i128 rhs) noexcept { + return i128{GetHigh(lhs) & GetHigh(rhs), GetLow(lhs) & GetLow(rhs)}; +} + +constexpr i128 operator^(const i128 lhs, const i128 rhs) noexcept { + return i128{GetHigh(lhs) ^ GetHigh(rhs), GetLow(lhs) ^ GetLow(rhs)}; +} + + +IOutputStream& operator<<(IOutputStream& out, const i128& other); + +// For THashMap +template <> +struct THash<i128> { + inline size_t operator()(const i128& num) const { + return THash<ui64>()(GetHigh(num)) + THash<ui64>()(GetLow(num)); + } +}; + +template <> +class TSerializer<i128> { +public: + static void Save(IOutputStream* out, const i128& Number); + static void Load(IInputStream* in, i128& Number); +}; + +template <> +inline TString ToString<i128>(const i128& number) { + return TStringBuilder{} << number; +} + +template <> +inline i128 FromStringImpl<i128>(const char* data, size_t length) { + if (length < 20) { + return i128{ FromString<ui64>(data, length) }; + } else { + i128 result = 0; + const TStringBuf string(data, length); + for (auto&& c : string) { + if (!std::isdigit(c)) { ythrow TFromStringException() << "Unexpected symbol \""sv << c << "\""sv; - } - - i128 x1 = result; - i128 x2 = x1 + x1; - i128 x4 = x2 + x2; - i128 x8 = x4 + x4; - i128 x10 = x8 + x2; - i128 s = c - '0'; - result = x10 + s; - - if (GetHigh(result) < GetHigh(x1)) { + } + + i128 x1 = result; + i128 x2 = x1 + x1; + i128 x4 = x2 + x2; + i128 x8 = x4 + x4; + i128 x10 = x8 + x2; + i128 s = c - '0'; + result = x10 + s; + + if (GetHigh(result) < GetHigh(x1)) { ythrow TFromStringException() << TStringBuf("Integer overflow"); - } - } - - return result; - } -} - -#if defined(Y_HAVE_INT128) -template <> -inline TString ToString<signed __int128>(const signed __int128& number) { - return ToString(i128{number}); -} - -template <> -inline signed __int128 FromStringImpl<signed __int128>(const char* data, size_t length) { - return static_cast<signed __int128>(FromString<i128>(data, length)); -} -#endif - -template <bool IsSigned> -Y_FORCE_INLINE size_t MostSignificantBit(const TInteger128<IsSigned> v) { - if (ui64 hi = GetHigh(v)) { - return MostSignificantBit(hi) + 64; - } - return MostSignificantBit(GetLow(v)); -} + } + } + + return result; + } +} + +#if defined(Y_HAVE_INT128) +template <> +inline TString ToString<signed __int128>(const signed __int128& number) { + return ToString(i128{number}); +} + +template <> +inline signed __int128 FromStringImpl<signed __int128>(const char* data, size_t length) { + return static_cast<signed __int128>(FromString<i128>(data, length)); +} +#endif + +template <bool IsSigned> +Y_FORCE_INLINE size_t MostSignificantBit(const TInteger128<IsSigned> v) { + if (ui64 hi = GetHigh(v)) { + return MostSignificantBit(hi) + 64; + } + return MostSignificantBit(GetLow(v)); +} diff --git a/library/cpp/int128/int128_common.h b/library/cpp/int128/int128_common.h index 7ad6485b33..6f70f09bee 100644 --- a/library/cpp/int128/int128_common.h +++ b/library/cpp/int128/int128_common.h @@ -1 +1 @@ -#pragma once +#pragma once diff --git a/library/cpp/int128/int128_util.h b/library/cpp/int128/int128_util.h index b3208eaed3..7a5ca2c250 100644 --- a/library/cpp/int128/int128_util.h +++ b/library/cpp/int128/int128_util.h @@ -1,15 +1,15 @@ -#pragma once - -#include <util/generic/bitops.h> -#include <limits> - -namespace NPrivateInt128 { - // will be moved to util/ later - template <typename T> - constexpr unsigned CountLeadingZeroBits(const T value) { - if (value == 0) { - return std::numeric_limits<std::make_unsigned_t<T>>::digits; - } - return std::numeric_limits<std::make_unsigned_t<T>>::digits - GetValueBitCount(value); - } -} +#pragma once + +#include <util/generic/bitops.h> +#include <limits> + +namespace NPrivateInt128 { + // will be moved to util/ later + template <typename T> + constexpr unsigned CountLeadingZeroBits(const T value) { + if (value == 0) { + return std::numeric_limits<std::make_unsigned_t<T>>::digits; + } + return std::numeric_limits<std::make_unsigned_t<T>>::digits - GetValueBitCount(value); + } +} diff --git a/library/cpp/int128/ut/.gitignore b/library/cpp/int128/ut/.gitignore index 46c7056544..36abcb2a2c 100644 --- a/library/cpp/int128/ut/.gitignore +++ b/library/cpp/int128/ut/.gitignore @@ -1,2 +1,2 @@ -library-int128-ut - +library-int128-ut + diff --git a/library/cpp/int128/ut/i128_and_intrinsic_identity_ut.cpp b/library/cpp/int128/ut/i128_and_intrinsic_identity_ut.cpp index c7de9b36c7..dbb7507a73 100644 --- a/library/cpp/int128/ut/i128_and_intrinsic_identity_ut.cpp +++ b/library/cpp/int128/ut/i128_and_intrinsic_identity_ut.cpp @@ -1,598 +1,598 @@ -#include "int128_ut_helpers.h" - +#include "int128_ut_helpers.h" + #include <library/cpp/testing/unittest/registar.h> - + #include <library/cpp/int128/int128.h> - -#include <util/generic/cast.h> - -#include <array> -#include <type_traits> - -#if defined(Y_HAVE_INT128) -bool IsIdentical(const i128 a, const signed __int128 b) { - const std::array<ui8, 16> arrayA = NInt128Private::GetAsArray(a); - const std::array<ui8, 16> arrayB = NInt128Private::GetAsArray(b); - return arrayA == arrayB; -} - -Y_UNIT_TEST_SUITE(i128_And_i8_BitwiseIdentity) { - Y_UNIT_TEST(i128_from_i8_Zero) { - i8 n = 0; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i8_Minus1) { - i8 n = -1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i8_Plus1) { - i8 n = 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i8_Minus42) { - i8 n = -42; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i8_Plus42) { - i8 n = 42; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i8_Min) { - i8 n = std::numeric_limits<i8>::min(); - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i8_Max) { - i8 n = std::numeric_limits<i8>::max(); - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i8_MinPlus1) { - i8 n = std::numeric_limits<i8>::min() + 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i8_MaxMinus1) { - i8 n = std::numeric_limits<i8>::max() - 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } -} - -Y_UNIT_TEST_SUITE(i128_And_i16_BitwiseIdentity) { - Y_UNIT_TEST(i128_from_i16_Zero) { - i16 n = 0; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i16_Minus1) { - i16 n = -1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i16_Plus1) { - i16 n = 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i16_Minus42) { - i16 n = -42; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i16_Plus42) { - i16 n = 42; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i16_Min) { - i16 n = std::numeric_limits<i16>::min(); - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i16_Max) { - i16 n = std::numeric_limits<i16>::max(); - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i16_MinPlus1) { - i16 n = std::numeric_limits<i16>::min() + 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i16_MaxMinus1) { - i16 n = std::numeric_limits<i16>::max() - 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } -} - -Y_UNIT_TEST_SUITE(i128_And_i32_BitwiseIdentity) { - Y_UNIT_TEST(i128_from_i32_Zero) { - i32 n = 0; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i32_Minus1) { - i32 n = -1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i32_Plus1) { - i32 n = 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i32_Minus42) { - i32 n = -42; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i32_Plus42) { - i32 n = 42; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i32_Min) { - i32 n = std::numeric_limits<i32>::min(); - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i32_Max) { - i32 n = std::numeric_limits<i32>::max(); - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i32_MinPlus1) { - i32 n = std::numeric_limits<i32>::min() + 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i32_MaxMinus1) { - i32 n = std::numeric_limits<i32>::max() - 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } -} - -Y_UNIT_TEST_SUITE(i128_And_i64_BitwiseIdentity) { - Y_UNIT_TEST(i128_from_i64_Zero) { - i64 n = 0; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i64_Minus1) { - i64 n = -1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i64_Plus1) { - i64 n = 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i64_Minus42) { - i64 n = -42; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i64_Plus42) { - i64 n = 42; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i64_Min) { - i64 n = std::numeric_limits<i64>::min(); - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i64_Max) { - i64 n = std::numeric_limits<i64>::max(); - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i64_MinPlus1) { - i64 n = std::numeric_limits<i64>::min() + 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_i64_MaxMinus1) { - i64 n = std::numeric_limits<i64>::max() - 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } -} - -Y_UNIT_TEST_SUITE(i128_And_signed_int128_BitwiseIdentity) { - Y_UNIT_TEST(i128_from_signed_int128_Zero) { - signed __int128 n = 0; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_signed_int128_Minus1) { - signed __int128 n = -1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_signed_int128_Plus1) { - signed __int128 n = 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_signed_int128_Minus42) { - signed __int128 n = -42; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_signed_int128_Plus42) { - signed __int128 n = 42; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_signed_int128_Min) { - signed __int128 n = std::numeric_limits<signed __int128>::min(); - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_signed_int128_Max) { - signed __int128 n = std::numeric_limits<signed __int128>::max(); - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_signed_int128_MinPlus1) { - signed __int128 n = std::numeric_limits<signed __int128>::min() + 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_signed_int128_MaxMinus1) { - signed __int128 n = std::numeric_limits<signed __int128>::max() - 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } -} - -Y_UNIT_TEST_SUITE(i128_And_ui8_BitwiseIdentity) { - Y_UNIT_TEST(i128_from_ui8_Zero) { - ui8 n = 0; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_ui8_Plus1) { - ui8 n = 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_ui8_Plus42) { - ui8 n = 42; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_ui8_Min) { - ui8 n = std::numeric_limits<i8>::min(); - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_ui8_Max) { - ui8 n = std::numeric_limits<i8>::max(); - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_ui8_MinPlus1) { - ui8 n = std::numeric_limits<i8>::min() + 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_ui8_MaxMinus1) { - ui8 n = std::numeric_limits<i8>::max() - 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } -} - -Y_UNIT_TEST_SUITE(i128_And_ui16_BitwiseIdentity) { - Y_UNIT_TEST(i128_from_ui16_Zero) { - ui16 n = 0; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_ui16_Plus1) { - ui16 n = 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_ui16_Plus42) { - ui16 n = 42; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_ui16_Min) { - ui16 n = std::numeric_limits<i8>::min(); - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_ui16_Max) { - ui16 n = std::numeric_limits<i8>::max(); - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_ui16_MinPlus1) { - ui16 n = std::numeric_limits<i8>::min() + 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_ui16_MaxMinus1) { - ui16 n = std::numeric_limits<i8>::max() - 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } -} - -Y_UNIT_TEST_SUITE(i128_And_ui32_BitwiseIdentity) { - Y_UNIT_TEST(i128_from_ui32_Zero) { - ui32 n = 0; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_ui32_Plus1) { - ui32 n = 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_ui32_Plus42) { - ui32 n = 42; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_ui32_Min) { - ui32 n = std::numeric_limits<i8>::min(); - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_ui32_Max) { - ui32 n = std::numeric_limits<i8>::max(); - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_ui32_MinPlus1) { - ui32 n = std::numeric_limits<i8>::min() + 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_ui32_MaxMinus1) { - ui32 n = std::numeric_limits<i8>::max() - 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } -} - -Y_UNIT_TEST_SUITE(i128_And_ui64_BitwiseIdentity) { - Y_UNIT_TEST(i128_from_ui64_Zero) { - ui64 n = 0; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_ui64_Plus1) { - ui64 n = 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_ui64_Plus42) { - ui64 n = 42; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_ui64_Min) { - ui64 n = std::numeric_limits<i8>::min(); - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_ui64_Max) { - ui64 n = std::numeric_limits<i8>::max(); - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_ui64_MinPlus1) { - ui64 n = std::numeric_limits<i8>::min() + 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_ui64_MaxMinus1) { - ui64 n = std::numeric_limits<i8>::max() - 1; - i128 t1{n}; - signed __int128 t2{n}; - UNIT_ASSERT(IsIdentical(t1, t2)); - } -} - -Y_UNIT_TEST_SUITE(i128_And_unsigned_int128_BitwiseIdentity) { - Y_UNIT_TEST(i128_from_unsigned_int128_Zero) { - unsigned __int128 n = 0; - i128 t1{n}; - signed __int128 t2 = static_cast<signed __int128>(n); - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_unsigned_int128_Plus1) { - unsigned __int128 n = 1; - i128 t1{n}; - signed __int128 t2 = static_cast<signed __int128>(n); - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_unsigned_int128_Plus42) { - unsigned __int128 n = 42; - i128 t1{n}; - signed __int128 t2 = static_cast<signed __int128>(n); - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_unsigned_int128_Min) { - unsigned __int128 n = std::numeric_limits<i8>::min(); - i128 t1{n}; - signed __int128 t2 = static_cast<signed __int128>(n); - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_unsigned_int128_Max) { - unsigned __int128 n = std::numeric_limits<i8>::max(); - i128 t1{n}; - signed __int128 t2 = static_cast<signed __int128>(n); - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_unsigned_int128_MinPlus1) { - unsigned __int128 n = std::numeric_limits<i8>::min() + 1; - i128 t1{n}; - signed __int128 t2 = static_cast<signed __int128>(n); - UNIT_ASSERT(IsIdentical(t1, t2)); - } - - Y_UNIT_TEST(i128_from_unsigned_int128_MaxMinus1) { - unsigned __int128 n = std::numeric_limits<i8>::max() - 1; - i128 t1{n}; - signed __int128 t2 = static_cast<signed __int128>(n); - UNIT_ASSERT(IsIdentical(t1, t2)); - } -} -#endif + +#include <util/generic/cast.h> + +#include <array> +#include <type_traits> + +#if defined(Y_HAVE_INT128) +bool IsIdentical(const i128 a, const signed __int128 b) { + const std::array<ui8, 16> arrayA = NInt128Private::GetAsArray(a); + const std::array<ui8, 16> arrayB = NInt128Private::GetAsArray(b); + return arrayA == arrayB; +} + +Y_UNIT_TEST_SUITE(i128_And_i8_BitwiseIdentity) { + Y_UNIT_TEST(i128_from_i8_Zero) { + i8 n = 0; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i8_Minus1) { + i8 n = -1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i8_Plus1) { + i8 n = 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i8_Minus42) { + i8 n = -42; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i8_Plus42) { + i8 n = 42; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i8_Min) { + i8 n = std::numeric_limits<i8>::min(); + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i8_Max) { + i8 n = std::numeric_limits<i8>::max(); + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i8_MinPlus1) { + i8 n = std::numeric_limits<i8>::min() + 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i8_MaxMinus1) { + i8 n = std::numeric_limits<i8>::max() - 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } +} + +Y_UNIT_TEST_SUITE(i128_And_i16_BitwiseIdentity) { + Y_UNIT_TEST(i128_from_i16_Zero) { + i16 n = 0; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i16_Minus1) { + i16 n = -1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i16_Plus1) { + i16 n = 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i16_Minus42) { + i16 n = -42; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i16_Plus42) { + i16 n = 42; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i16_Min) { + i16 n = std::numeric_limits<i16>::min(); + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i16_Max) { + i16 n = std::numeric_limits<i16>::max(); + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i16_MinPlus1) { + i16 n = std::numeric_limits<i16>::min() + 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i16_MaxMinus1) { + i16 n = std::numeric_limits<i16>::max() - 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } +} + +Y_UNIT_TEST_SUITE(i128_And_i32_BitwiseIdentity) { + Y_UNIT_TEST(i128_from_i32_Zero) { + i32 n = 0; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i32_Minus1) { + i32 n = -1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i32_Plus1) { + i32 n = 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i32_Minus42) { + i32 n = -42; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i32_Plus42) { + i32 n = 42; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i32_Min) { + i32 n = std::numeric_limits<i32>::min(); + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i32_Max) { + i32 n = std::numeric_limits<i32>::max(); + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i32_MinPlus1) { + i32 n = std::numeric_limits<i32>::min() + 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i32_MaxMinus1) { + i32 n = std::numeric_limits<i32>::max() - 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } +} + +Y_UNIT_TEST_SUITE(i128_And_i64_BitwiseIdentity) { + Y_UNIT_TEST(i128_from_i64_Zero) { + i64 n = 0; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i64_Minus1) { + i64 n = -1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i64_Plus1) { + i64 n = 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i64_Minus42) { + i64 n = -42; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i64_Plus42) { + i64 n = 42; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i64_Min) { + i64 n = std::numeric_limits<i64>::min(); + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i64_Max) { + i64 n = std::numeric_limits<i64>::max(); + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i64_MinPlus1) { + i64 n = std::numeric_limits<i64>::min() + 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_i64_MaxMinus1) { + i64 n = std::numeric_limits<i64>::max() - 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } +} + +Y_UNIT_TEST_SUITE(i128_And_signed_int128_BitwiseIdentity) { + Y_UNIT_TEST(i128_from_signed_int128_Zero) { + signed __int128 n = 0; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_signed_int128_Minus1) { + signed __int128 n = -1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_signed_int128_Plus1) { + signed __int128 n = 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_signed_int128_Minus42) { + signed __int128 n = -42; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_signed_int128_Plus42) { + signed __int128 n = 42; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_signed_int128_Min) { + signed __int128 n = std::numeric_limits<signed __int128>::min(); + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_signed_int128_Max) { + signed __int128 n = std::numeric_limits<signed __int128>::max(); + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_signed_int128_MinPlus1) { + signed __int128 n = std::numeric_limits<signed __int128>::min() + 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_signed_int128_MaxMinus1) { + signed __int128 n = std::numeric_limits<signed __int128>::max() - 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } +} + +Y_UNIT_TEST_SUITE(i128_And_ui8_BitwiseIdentity) { + Y_UNIT_TEST(i128_from_ui8_Zero) { + ui8 n = 0; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_ui8_Plus1) { + ui8 n = 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_ui8_Plus42) { + ui8 n = 42; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_ui8_Min) { + ui8 n = std::numeric_limits<i8>::min(); + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_ui8_Max) { + ui8 n = std::numeric_limits<i8>::max(); + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_ui8_MinPlus1) { + ui8 n = std::numeric_limits<i8>::min() + 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_ui8_MaxMinus1) { + ui8 n = std::numeric_limits<i8>::max() - 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } +} + +Y_UNIT_TEST_SUITE(i128_And_ui16_BitwiseIdentity) { + Y_UNIT_TEST(i128_from_ui16_Zero) { + ui16 n = 0; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_ui16_Plus1) { + ui16 n = 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_ui16_Plus42) { + ui16 n = 42; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_ui16_Min) { + ui16 n = std::numeric_limits<i8>::min(); + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_ui16_Max) { + ui16 n = std::numeric_limits<i8>::max(); + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_ui16_MinPlus1) { + ui16 n = std::numeric_limits<i8>::min() + 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_ui16_MaxMinus1) { + ui16 n = std::numeric_limits<i8>::max() - 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } +} + +Y_UNIT_TEST_SUITE(i128_And_ui32_BitwiseIdentity) { + Y_UNIT_TEST(i128_from_ui32_Zero) { + ui32 n = 0; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_ui32_Plus1) { + ui32 n = 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_ui32_Plus42) { + ui32 n = 42; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_ui32_Min) { + ui32 n = std::numeric_limits<i8>::min(); + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_ui32_Max) { + ui32 n = std::numeric_limits<i8>::max(); + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_ui32_MinPlus1) { + ui32 n = std::numeric_limits<i8>::min() + 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_ui32_MaxMinus1) { + ui32 n = std::numeric_limits<i8>::max() - 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } +} + +Y_UNIT_TEST_SUITE(i128_And_ui64_BitwiseIdentity) { + Y_UNIT_TEST(i128_from_ui64_Zero) { + ui64 n = 0; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_ui64_Plus1) { + ui64 n = 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_ui64_Plus42) { + ui64 n = 42; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_ui64_Min) { + ui64 n = std::numeric_limits<i8>::min(); + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_ui64_Max) { + ui64 n = std::numeric_limits<i8>::max(); + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_ui64_MinPlus1) { + ui64 n = std::numeric_limits<i8>::min() + 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_ui64_MaxMinus1) { + ui64 n = std::numeric_limits<i8>::max() - 1; + i128 t1{n}; + signed __int128 t2{n}; + UNIT_ASSERT(IsIdentical(t1, t2)); + } +} + +Y_UNIT_TEST_SUITE(i128_And_unsigned_int128_BitwiseIdentity) { + Y_UNIT_TEST(i128_from_unsigned_int128_Zero) { + unsigned __int128 n = 0; + i128 t1{n}; + signed __int128 t2 = static_cast<signed __int128>(n); + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_unsigned_int128_Plus1) { + unsigned __int128 n = 1; + i128 t1{n}; + signed __int128 t2 = static_cast<signed __int128>(n); + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_unsigned_int128_Plus42) { + unsigned __int128 n = 42; + i128 t1{n}; + signed __int128 t2 = static_cast<signed __int128>(n); + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_unsigned_int128_Min) { + unsigned __int128 n = std::numeric_limits<i8>::min(); + i128 t1{n}; + signed __int128 t2 = static_cast<signed __int128>(n); + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_unsigned_int128_Max) { + unsigned __int128 n = std::numeric_limits<i8>::max(); + i128 t1{n}; + signed __int128 t2 = static_cast<signed __int128>(n); + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_unsigned_int128_MinPlus1) { + unsigned __int128 n = std::numeric_limits<i8>::min() + 1; + i128 t1{n}; + signed __int128 t2 = static_cast<signed __int128>(n); + UNIT_ASSERT(IsIdentical(t1, t2)); + } + + Y_UNIT_TEST(i128_from_unsigned_int128_MaxMinus1) { + unsigned __int128 n = std::numeric_limits<i8>::max() - 1; + i128 t1{n}; + signed __int128 t2 = static_cast<signed __int128>(n); + UNIT_ASSERT(IsIdentical(t1, t2)); + } +} +#endif diff --git a/library/cpp/int128/ut/i128_comparison_ut.cpp b/library/cpp/int128/ut/i128_comparison_ut.cpp index 8e38ac17e2..7b8d508815 100644 --- a/library/cpp/int128/ut/i128_comparison_ut.cpp +++ b/library/cpp/int128/ut/i128_comparison_ut.cpp @@ -1,145 +1,145 @@ #include <library/cpp/testing/unittest/registar.h> - + #include <library/cpp/int128/int128.h> - -#include <util/generic/cast.h> - -Y_UNIT_TEST_SUITE(I128ComparisonPositiveWithPositiveSuite) { - Y_UNIT_TEST(PositivePositiveGreater) { - UNIT_ASSERT(i128{1} > i128{0}); - UNIT_ASSERT(i128{2} > i128{1}); - UNIT_ASSERT(i128{42} > i128{0}); - UNIT_ASSERT(i128{42} > i128{1}); - i128 big = i128{1, 0}; - UNIT_ASSERT(big > i128{1}); - UNIT_ASSERT(std::numeric_limits<i128>::max() > i128{0}); - } - - Y_UNIT_TEST(PositivePositiveGreaterOrEqual) { - UNIT_ASSERT(i128{1} >= i128{0}); - UNIT_ASSERT(i128{2} >= i128{1}); - UNIT_ASSERT(i128{42} >= i128{0}); - UNIT_ASSERT(i128{42} >= i128{1}); - i128 big = i128{1, 0}; - UNIT_ASSERT(big >= i128{1}); - UNIT_ASSERT(std::numeric_limits<i128>::max() >= i128{0}); - - UNIT_ASSERT(i128{0} >= i128{0}); - UNIT_ASSERT(i128{1} >= i128{1}); - UNIT_ASSERT(i128{2} >= i128{2}); - UNIT_ASSERT(i128{42} >= i128{42}); - UNIT_ASSERT(big >= big); - UNIT_ASSERT(std::numeric_limits<i128>::max() >= std::numeric_limits<i128>::max()); - } - - Y_UNIT_TEST(PositivePositiveLess) { - UNIT_ASSERT(i128{0} < i128{1}); - UNIT_ASSERT(i128{1} < i128{2}); - UNIT_ASSERT(i128{0} < i128{42}); - UNIT_ASSERT(i128{1} < i128{42}); - i128 big = i128{1, 0}; - UNIT_ASSERT(i128{1} < big); - UNIT_ASSERT(i128{0} < std::numeric_limits<i128>::max()); - } - - Y_UNIT_TEST(PositivePositiveLessOrEqual) { - UNIT_ASSERT(i128{0} <= i128{1}); - UNIT_ASSERT(i128{1} <= i128{2}); - UNIT_ASSERT(i128{0} <= i128{42}); - UNIT_ASSERT(i128{1} <= i128{42}); - i128 big = i128{1, 0}; - UNIT_ASSERT(i128{1} <= big); - UNIT_ASSERT(i128{0} <= std::numeric_limits<i128>::max()); - - UNIT_ASSERT(i128{0} <= i128{0}); - UNIT_ASSERT(i128{1} <= i128{1}); - UNIT_ASSERT(i128{2} <= i128{2}); - UNIT_ASSERT(i128{42} <= i128{42}); - UNIT_ASSERT(big <= big); - UNIT_ASSERT(std::numeric_limits<i128>::max() <= std::numeric_limits<i128>::max()); - } -} - -Y_UNIT_TEST_SUITE(I128ComparisonPositiveWithNegativeSuite) { - Y_UNIT_TEST(PositiveNegativeGreater) { - UNIT_ASSERT(i128{0} > i128{-1}); - UNIT_ASSERT(i128{2} > i128{-1}); - UNIT_ASSERT(i128{0} > i128{-42}); - UNIT_ASSERT(i128{42} > i128{-1}); - i128 big = i128{1, 0}; - UNIT_ASSERT(big > i128{-1}); - UNIT_ASSERT(std::numeric_limits<i128>::max() > i128{-1}); - } - - Y_UNIT_TEST(PositiveNegativeGreaterOrEqual) { - UNIT_ASSERT(i128{0} >= i128{-1}); - UNIT_ASSERT(i128{2} >= i128{-1}); - UNIT_ASSERT(i128{0} >= i128{-42}); - UNIT_ASSERT(i128{42} >= i128{-1}); - i128 big = i128{1, 0}; - UNIT_ASSERT(big >= i128{-1}); - UNIT_ASSERT(std::numeric_limits<i128>::max() >= i128{-1}); - } - - Y_UNIT_TEST(NegativePositiveLess) { - UNIT_ASSERT(i128{-1} < i128{0}); - UNIT_ASSERT(i128{-1} < i128{2}); - UNIT_ASSERT(i128{-42} < i128{0}); - UNIT_ASSERT(i128{-1} < i128{42}); - i128 big = i128{1, 0}; - UNIT_ASSERT(i128{-1} < big); - UNIT_ASSERT(i128{-1} < std::numeric_limits<i128>::max()); - } - - Y_UNIT_TEST(NegativePositiveLessOrEqual) { - UNIT_ASSERT(i128{-1} <= i128{0}); - UNIT_ASSERT(i128{-1} <= i128{2}); - UNIT_ASSERT(i128{-42} <= i128{0}); - UNIT_ASSERT(i128{-1} <= i128{42}); - i128 big = i128{1, 0}; - UNIT_ASSERT(i128{-1} <= big); - UNIT_ASSERT(i128{-1} <= std::numeric_limits<i128>::max()); - } -} - -Y_UNIT_TEST_SUITE(I128ComparisonNegativeWithNegativeSuite) { - Y_UNIT_TEST(NegativeNegativeGreater) { - UNIT_ASSERT(i128{-1} > i128{-2}); - UNIT_ASSERT(i128{-2} > i128{-3}); - UNIT_ASSERT(i128{-1} > i128{-42}); - UNIT_ASSERT(i128{-42} > i128{-142}); - i128 big = -i128{1, 0}; - UNIT_ASSERT(i128{-1} > big); - UNIT_ASSERT(i128{-1} > std::numeric_limits<i128>::min()); - } - - Y_UNIT_TEST(NegativeNegativeGreaterOrEqual) { - UNIT_ASSERT(i128{-1} >= i128{-2}); - UNIT_ASSERT(i128{-2} >= i128{-3}); - UNIT_ASSERT(i128{-1} >= i128{-42}); - UNIT_ASSERT(i128{-42} >= i128{-142}); - i128 big = -i128{1, 0}; - UNIT_ASSERT(i128{-1} >= big); - UNIT_ASSERT(i128{-1} >= std::numeric_limits<i128>::min()); - } - - Y_UNIT_TEST(NegativeNegativeLess) { - UNIT_ASSERT(i128{-2} < i128{-1}); - UNIT_ASSERT(i128{-3} < i128{-2}); - UNIT_ASSERT(i128{-42} < i128{-1}); - UNIT_ASSERT(i128{-142} < i128{42}); - i128 big = -i128{1, 0}; - UNIT_ASSERT(big < i128{-1}); - UNIT_ASSERT(std::numeric_limits<i128>::min() < i128{-1}); - } - - Y_UNIT_TEST(NegativeNegativeLessOrEqual) { - UNIT_ASSERT(i128{-2} <= i128{-1}); - UNIT_ASSERT(i128{-3} <= i128{-2}); - UNIT_ASSERT(i128{-42} <= i128{-1}); - UNIT_ASSERT(i128{-142} <= i128{42}); - i128 big = -i128{1, 0}; - UNIT_ASSERT(big <= i128{-1}); - UNIT_ASSERT(std::numeric_limits<i128>::min() <= i128{-1}); - } -} + +#include <util/generic/cast.h> + +Y_UNIT_TEST_SUITE(I128ComparisonPositiveWithPositiveSuite) { + Y_UNIT_TEST(PositivePositiveGreater) { + UNIT_ASSERT(i128{1} > i128{0}); + UNIT_ASSERT(i128{2} > i128{1}); + UNIT_ASSERT(i128{42} > i128{0}); + UNIT_ASSERT(i128{42} > i128{1}); + i128 big = i128{1, 0}; + UNIT_ASSERT(big > i128{1}); + UNIT_ASSERT(std::numeric_limits<i128>::max() > i128{0}); + } + + Y_UNIT_TEST(PositivePositiveGreaterOrEqual) { + UNIT_ASSERT(i128{1} >= i128{0}); + UNIT_ASSERT(i128{2} >= i128{1}); + UNIT_ASSERT(i128{42} >= i128{0}); + UNIT_ASSERT(i128{42} >= i128{1}); + i128 big = i128{1, 0}; + UNIT_ASSERT(big >= i128{1}); + UNIT_ASSERT(std::numeric_limits<i128>::max() >= i128{0}); + + UNIT_ASSERT(i128{0} >= i128{0}); + UNIT_ASSERT(i128{1} >= i128{1}); + UNIT_ASSERT(i128{2} >= i128{2}); + UNIT_ASSERT(i128{42} >= i128{42}); + UNIT_ASSERT(big >= big); + UNIT_ASSERT(std::numeric_limits<i128>::max() >= std::numeric_limits<i128>::max()); + } + + Y_UNIT_TEST(PositivePositiveLess) { + UNIT_ASSERT(i128{0} < i128{1}); + UNIT_ASSERT(i128{1} < i128{2}); + UNIT_ASSERT(i128{0} < i128{42}); + UNIT_ASSERT(i128{1} < i128{42}); + i128 big = i128{1, 0}; + UNIT_ASSERT(i128{1} < big); + UNIT_ASSERT(i128{0} < std::numeric_limits<i128>::max()); + } + + Y_UNIT_TEST(PositivePositiveLessOrEqual) { + UNIT_ASSERT(i128{0} <= i128{1}); + UNIT_ASSERT(i128{1} <= i128{2}); + UNIT_ASSERT(i128{0} <= i128{42}); + UNIT_ASSERT(i128{1} <= i128{42}); + i128 big = i128{1, 0}; + UNIT_ASSERT(i128{1} <= big); + UNIT_ASSERT(i128{0} <= std::numeric_limits<i128>::max()); + + UNIT_ASSERT(i128{0} <= i128{0}); + UNIT_ASSERT(i128{1} <= i128{1}); + UNIT_ASSERT(i128{2} <= i128{2}); + UNIT_ASSERT(i128{42} <= i128{42}); + UNIT_ASSERT(big <= big); + UNIT_ASSERT(std::numeric_limits<i128>::max() <= std::numeric_limits<i128>::max()); + } +} + +Y_UNIT_TEST_SUITE(I128ComparisonPositiveWithNegativeSuite) { + Y_UNIT_TEST(PositiveNegativeGreater) { + UNIT_ASSERT(i128{0} > i128{-1}); + UNIT_ASSERT(i128{2} > i128{-1}); + UNIT_ASSERT(i128{0} > i128{-42}); + UNIT_ASSERT(i128{42} > i128{-1}); + i128 big = i128{1, 0}; + UNIT_ASSERT(big > i128{-1}); + UNIT_ASSERT(std::numeric_limits<i128>::max() > i128{-1}); + } + + Y_UNIT_TEST(PositiveNegativeGreaterOrEqual) { + UNIT_ASSERT(i128{0} >= i128{-1}); + UNIT_ASSERT(i128{2} >= i128{-1}); + UNIT_ASSERT(i128{0} >= i128{-42}); + UNIT_ASSERT(i128{42} >= i128{-1}); + i128 big = i128{1, 0}; + UNIT_ASSERT(big >= i128{-1}); + UNIT_ASSERT(std::numeric_limits<i128>::max() >= i128{-1}); + } + + Y_UNIT_TEST(NegativePositiveLess) { + UNIT_ASSERT(i128{-1} < i128{0}); + UNIT_ASSERT(i128{-1} < i128{2}); + UNIT_ASSERT(i128{-42} < i128{0}); + UNIT_ASSERT(i128{-1} < i128{42}); + i128 big = i128{1, 0}; + UNIT_ASSERT(i128{-1} < big); + UNIT_ASSERT(i128{-1} < std::numeric_limits<i128>::max()); + } + + Y_UNIT_TEST(NegativePositiveLessOrEqual) { + UNIT_ASSERT(i128{-1} <= i128{0}); + UNIT_ASSERT(i128{-1} <= i128{2}); + UNIT_ASSERT(i128{-42} <= i128{0}); + UNIT_ASSERT(i128{-1} <= i128{42}); + i128 big = i128{1, 0}; + UNIT_ASSERT(i128{-1} <= big); + UNIT_ASSERT(i128{-1} <= std::numeric_limits<i128>::max()); + } +} + +Y_UNIT_TEST_SUITE(I128ComparisonNegativeWithNegativeSuite) { + Y_UNIT_TEST(NegativeNegativeGreater) { + UNIT_ASSERT(i128{-1} > i128{-2}); + UNIT_ASSERT(i128{-2} > i128{-3}); + UNIT_ASSERT(i128{-1} > i128{-42}); + UNIT_ASSERT(i128{-42} > i128{-142}); + i128 big = -i128{1, 0}; + UNIT_ASSERT(i128{-1} > big); + UNIT_ASSERT(i128{-1} > std::numeric_limits<i128>::min()); + } + + Y_UNIT_TEST(NegativeNegativeGreaterOrEqual) { + UNIT_ASSERT(i128{-1} >= i128{-2}); + UNIT_ASSERT(i128{-2} >= i128{-3}); + UNIT_ASSERT(i128{-1} >= i128{-42}); + UNIT_ASSERT(i128{-42} >= i128{-142}); + i128 big = -i128{1, 0}; + UNIT_ASSERT(i128{-1} >= big); + UNIT_ASSERT(i128{-1} >= std::numeric_limits<i128>::min()); + } + + Y_UNIT_TEST(NegativeNegativeLess) { + UNIT_ASSERT(i128{-2} < i128{-1}); + UNIT_ASSERT(i128{-3} < i128{-2}); + UNIT_ASSERT(i128{-42} < i128{-1}); + UNIT_ASSERT(i128{-142} < i128{42}); + i128 big = -i128{1, 0}; + UNIT_ASSERT(big < i128{-1}); + UNIT_ASSERT(std::numeric_limits<i128>::min() < i128{-1}); + } + + Y_UNIT_TEST(NegativeNegativeLessOrEqual) { + UNIT_ASSERT(i128{-2} <= i128{-1}); + UNIT_ASSERT(i128{-3} <= i128{-2}); + UNIT_ASSERT(i128{-42} <= i128{-1}); + UNIT_ASSERT(i128{-142} <= i128{42}); + i128 big = -i128{1, 0}; + UNIT_ASSERT(big <= i128{-1}); + UNIT_ASSERT(std::numeric_limits<i128>::min() <= i128{-1}); + } +} diff --git a/library/cpp/int128/ut/i128_division_ut.cpp b/library/cpp/int128/ut/i128_division_ut.cpp index b58731dd7e..46b0ca27f5 100644 --- a/library/cpp/int128/ut/i128_division_ut.cpp +++ b/library/cpp/int128/ut/i128_division_ut.cpp @@ -1,413 +1,413 @@ #include <library/cpp/testing/unittest/registar.h> - + #include <library/cpp/int128/int128.h> - -#include <util/generic/cast.h> - -Y_UNIT_TEST_SUITE(I128DivisionBy1Suite) { - Y_UNIT_TEST(I128Divide0By1) { - i128 dividend = 0; - i128 divider = 1; - i128 expectedQuotient = 0; - i128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(I128Divide1By1) { - i128 dividend = 1; - i128 divider = 1; - i128 expectedQuotient = 1; - i128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(I128Divide2By1) { - i128 dividend = 2; - i128 divider = 1; - i128 expectedQuotient = 2; - i128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(I128Divide42By1) { - i128 dividend = 42; - i128 divider = 1; - i128 expectedQuotient = 42; - i128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(I128DivideMaxUi64By1) { - i128 dividend = std::numeric_limits<ui64>::max(); - i128 divider = 1; - i128 expectedQuotient = std::numeric_limits<ui64>::max(); - i128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(I128DivideMaxUi64Plus1By1) { - i128 dividend = i128{std::numeric_limits<ui64>::max()} + i128{1}; - i128 divider = 1; - i128 expectedQuotient = i128{std::numeric_limits<ui64>::max()} + i128{1}; - i128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(I128DivideMaxUi64Plus42By1) { - i128 dividend = i128{std::numeric_limits<ui64>::max()} + i128{42}; - i128 divider = 1; - i128 expectedQuotient = i128{std::numeric_limits<ui64>::max()} + i128{42}; - i128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(I128DivideMaxI128By1) { - i128 dividend = std::numeric_limits<i128>::max(); - i128 divider = 1; - i128 expectedQuotient = std::numeric_limits<i128>::max(); - i128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(I128DivideMaxI128Minus1By1) { - i128 dividend = std::numeric_limits<i128>::max() - 1; - i128 divider = 1; - i128 expectedQuotient = std::numeric_limits<i128>::max() - 1; - i128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } -} - -Y_UNIT_TEST_SUITE(I128DivisionByEqualSuite) { - Y_UNIT_TEST(I128Divide1ByEqual) { - i128 dividend = 1; - i128 divider = dividend; - i128 expectedQuotient = 1; - i128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(I128Divide2ByEqual) { - i128 dividend = 2; - i128 divider = dividend; - i128 expectedQuotient = 1; - i128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(I128Divide42ByEqual) { - i128 dividend = 42; - i128 divider = dividend; - i128 expectedQuotient = 1; - i128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(I128DivideMaxUi64ByEqual) { - i128 dividend = std::numeric_limits<ui64>::max(); - i128 divider = dividend; - i128 expectedQuotient = 1; - i128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(I128DivideMaxUi64Plus1ByEqual) { - i128 dividend = i128{std::numeric_limits<ui64>::max()} + i128{1}; - i128 divider = dividend; - i128 expectedQuotient = 1; - i128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(I128DivideMaxUi64Plus42ByEqual) { - i128 dividend = i128{std::numeric_limits<ui64>::max()} + i128{42}; - i128 divider = dividend; - i128 expectedQuotient = 1; - i128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(I128DivideMaxI128ByEqual) { - i128 dividend = std::numeric_limits<i128>::max(); - i128 divider = dividend; - i128 expectedQuotient = 1; - i128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(I128DivideMaxI128Minus1ByEqual) { - i128 dividend = std::numeric_limits<i128>::max() - 1; - i128 divider = dividend; - i128 expectedQuotient = 1; - i128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } -} - -Y_UNIT_TEST_SUITE(I128DivisionLessByHigherSuite) { - Y_UNIT_TEST(I128Divide42By84) { - i128 dividend = 42; - i128 divider = 84; - i128 expectedQuotient = 0; - i128 expectedRemainder = 42; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(I128Divide42ByMaxUi64) { - i128 dividend = 42; - i128 divider = std::numeric_limits<ui64>::max(); - i128 expectedQuotient = 0; - i128 expectedRemainder = 42; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(I128Divide42ByMaxUi64Plus1) { - i128 dividend = 42; - i128 divider = i128{std::numeric_limits<ui64>::max()} + i128{1}; - i128 expectedQuotient = 0; - i128 expectedRemainder = 42; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(I128DivideMaxUi64ByMaxUi64Plus1) { - i128 dividend = i128{std::numeric_limits<ui64>::max()}; - i128 divider = i128{std::numeric_limits<ui64>::max()} + i128{1}; - i128 expectedQuotient = 0; - i128 expectedRemainder = i128{std::numeric_limits<ui64>::max()}; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } -} - -Y_UNIT_TEST_SUITE(I128DivisionWithDifferentSigns) { - Y_UNIT_TEST(DivisionPositiveByNegative) { - i128 dividend = i128{100}; - i128 divider = i128{-33}; - i128 expectedQuotient = -3; - i128 expectedRemainder = 1; - i128 quotient = dividend / divider; - i128 remainder = dividend % divider; - - UNIT_ASSERT_EQUAL(quotient, expectedQuotient); - UNIT_ASSERT_EQUAL(remainder, expectedRemainder); - } - - Y_UNIT_TEST(DivisionNegativeByPositive) { - i128 dividend = i128{-100}; - i128 divider = i128{33}; - i128 expectedQuotient = -3; - i128 expectedRemainder = -1; - i128 quotient = dividend / divider; - i128 remainder = dividend % divider; - - UNIT_ASSERT_EQUAL(quotient, expectedQuotient); - UNIT_ASSERT_EQUAL(remainder, expectedRemainder); - } - - Y_UNIT_TEST(DivisionNegativeByNegative) { - i128 dividend = i128{-100}; - i128 divider = i128{-33}; - i128 expectedQuotient = 3; - i128 expectedRemainder = -1; - i128 quotient = dividend / divider; - i128 remainder = dividend % divider; - - UNIT_ASSERT_EQUAL(quotient, expectedQuotient); - UNIT_ASSERT_EQUAL(remainder, expectedRemainder); - } -} - -Y_UNIT_TEST_SUITE(i128DivisionBigByBigSuite) { - Y_UNIT_TEST(i128DivideBigByBig1) { - i128 dividend = {64, 0}; - i128 divider = {1, 0}; - i128 expectedQuotient = 64; - i128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(i128DivideBigByBig1_PosByNeg) { - i128 dividend = i128{64, 0}; - i128 divider = -i128{1, 0}; - i128 expectedQuotient = -i128{64}; - i128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(i128DivideBigByBig1_NegByPos) { - i128 dividend = -i128{64, 0}; - i128 divider = i128{1, 0}; - i128 expectedQuotient = -i128{64}; - i128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(i128DivideBigByBig1_NegByNeg) { - i128 dividend = -i128{64, 0}; - i128 divider = -i128{1, 0}; - i128 expectedQuotient = i128{64}; - i128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(i128DivideBigByBig2) { - i128 dividend = {64, 0}; - i128 divider = {12, 5}; - i128 expectedQuotient = 5; - i128 expectedRemainder = i128{3, 18446744073709551591ull}; // plz don't ask - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(i128DivideBigByBig2_PosByNeg) { - i128 dividend = i128{64, 0}; - i128 divider = -i128{12, 5}; - i128 expectedQuotient = -5; - i128 expectedRemainder = i128{3, 18446744073709551591ull}; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(i128DivideBigByBig2_NegByPos) { - i128 dividend = -i128{64, 0}; - i128 divider = i128{12, 5}; - i128 expectedQuotient = -5; - i128 expectedRemainder = -i128{3, 18446744073709551591ull}; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(i128DivideBigByBig2_NegByNeg) { - i128 dividend = -i128{64, 0}; - i128 divider = -i128{12, 5}; - i128 expectedQuotient = 5; - i128 expectedRemainder = -i128{3, 18446744073709551591ull}; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - -} - -Y_UNIT_TEST_SUITE(i128DivisionAlgo) { - Y_UNIT_TEST(ii128DivideAlgoCheck_PosByPos) { - /* - 49672666804009505000000 / 10000000 == 4967266680400950 - 49672666804009505000000 % 10000000 == 5000000 - */ - i128 dividend = {2692ull, 14031757583392049728ull}; - i64 divider = 10000000; - i128 expectedQuotient = {0, 4967266680400950ull}; - i128 expectedRemainder = {0, 5000000ull}; - - i128 quotient = dividend / divider; - i128 reminder = dividend % divider; - - UNIT_ASSERT_EQUAL(quotient, expectedQuotient); - UNIT_ASSERT_EQUAL(reminder, expectedRemainder); - } - - Y_UNIT_TEST(ii128DivideAlgoCheck_PosByNeg) { - /* - 49672666804009505000000 / -10000000 == -4967266680400950 - 49672666804009505000000 % -10000000 == 5000000 - */ - i128 dividend = {2692ull, 14031757583392049728ull}; - i64 divider = -10000000; - i128 expectedQuotient = -i128{0, 4967266680400950ull}; - i128 expectedRemainder = {0, 5000000ull}; - - i128 quotient = dividend / divider; - i128 reminder = dividend % divider; - - UNIT_ASSERT_EQUAL(quotient, expectedQuotient); - UNIT_ASSERT_EQUAL(reminder, expectedRemainder); - } - - Y_UNIT_TEST(ii128DivideAlgoCheck_NegByPos) { - /* - -49672666804009505000000 / 10000000 == -4967266680400950 - -49672666804009505000000 % 10000000 == -5000000 - */ - i128 dividend = -i128{2692ull, 14031757583392049728ull}; - i64 divider = 10000000; - i128 expectedQuotient = -i128{0, 4967266680400950ull}; - i128 expectedRemainder = -i128{0, 5000000ull}; - - i128 quotient = dividend / divider; - i128 reminder = dividend % divider; - - UNIT_ASSERT_EQUAL(quotient, expectedQuotient); - UNIT_ASSERT_EQUAL(reminder, expectedRemainder); - } - - Y_UNIT_TEST(ii128DivideAlgoCheck_NegByNeg) { - /* - -49672666804009505000000 / -10000000 == 4967266680400950 - -49672666804009505000000 % -10000000 == -5000000 - */ - i128 dividend = -i128{2692ull, 14031757583392049728ull}; - i64 divider = -10000000; - i128 expectedQuotient = {0, 4967266680400950ull}; - i128 expectedRemainder = -i128{0, 5000000ull}; - - i128 quotient = dividend / divider; - i128 reminder = dividend % divider; - - UNIT_ASSERT_EQUAL(quotient, expectedQuotient); - UNIT_ASSERT_EQUAL(reminder, expectedRemainder); - } - -} + +#include <util/generic/cast.h> + +Y_UNIT_TEST_SUITE(I128DivisionBy1Suite) { + Y_UNIT_TEST(I128Divide0By1) { + i128 dividend = 0; + i128 divider = 1; + i128 expectedQuotient = 0; + i128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(I128Divide1By1) { + i128 dividend = 1; + i128 divider = 1; + i128 expectedQuotient = 1; + i128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(I128Divide2By1) { + i128 dividend = 2; + i128 divider = 1; + i128 expectedQuotient = 2; + i128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(I128Divide42By1) { + i128 dividend = 42; + i128 divider = 1; + i128 expectedQuotient = 42; + i128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(I128DivideMaxUi64By1) { + i128 dividend = std::numeric_limits<ui64>::max(); + i128 divider = 1; + i128 expectedQuotient = std::numeric_limits<ui64>::max(); + i128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(I128DivideMaxUi64Plus1By1) { + i128 dividend = i128{std::numeric_limits<ui64>::max()} + i128{1}; + i128 divider = 1; + i128 expectedQuotient = i128{std::numeric_limits<ui64>::max()} + i128{1}; + i128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(I128DivideMaxUi64Plus42By1) { + i128 dividend = i128{std::numeric_limits<ui64>::max()} + i128{42}; + i128 divider = 1; + i128 expectedQuotient = i128{std::numeric_limits<ui64>::max()} + i128{42}; + i128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(I128DivideMaxI128By1) { + i128 dividend = std::numeric_limits<i128>::max(); + i128 divider = 1; + i128 expectedQuotient = std::numeric_limits<i128>::max(); + i128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(I128DivideMaxI128Minus1By1) { + i128 dividend = std::numeric_limits<i128>::max() - 1; + i128 divider = 1; + i128 expectedQuotient = std::numeric_limits<i128>::max() - 1; + i128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } +} + +Y_UNIT_TEST_SUITE(I128DivisionByEqualSuite) { + Y_UNIT_TEST(I128Divide1ByEqual) { + i128 dividend = 1; + i128 divider = dividend; + i128 expectedQuotient = 1; + i128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(I128Divide2ByEqual) { + i128 dividend = 2; + i128 divider = dividend; + i128 expectedQuotient = 1; + i128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(I128Divide42ByEqual) { + i128 dividend = 42; + i128 divider = dividend; + i128 expectedQuotient = 1; + i128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(I128DivideMaxUi64ByEqual) { + i128 dividend = std::numeric_limits<ui64>::max(); + i128 divider = dividend; + i128 expectedQuotient = 1; + i128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(I128DivideMaxUi64Plus1ByEqual) { + i128 dividend = i128{std::numeric_limits<ui64>::max()} + i128{1}; + i128 divider = dividend; + i128 expectedQuotient = 1; + i128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(I128DivideMaxUi64Plus42ByEqual) { + i128 dividend = i128{std::numeric_limits<ui64>::max()} + i128{42}; + i128 divider = dividend; + i128 expectedQuotient = 1; + i128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(I128DivideMaxI128ByEqual) { + i128 dividend = std::numeric_limits<i128>::max(); + i128 divider = dividend; + i128 expectedQuotient = 1; + i128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(I128DivideMaxI128Minus1ByEqual) { + i128 dividend = std::numeric_limits<i128>::max() - 1; + i128 divider = dividend; + i128 expectedQuotient = 1; + i128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } +} + +Y_UNIT_TEST_SUITE(I128DivisionLessByHigherSuite) { + Y_UNIT_TEST(I128Divide42By84) { + i128 dividend = 42; + i128 divider = 84; + i128 expectedQuotient = 0; + i128 expectedRemainder = 42; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(I128Divide42ByMaxUi64) { + i128 dividend = 42; + i128 divider = std::numeric_limits<ui64>::max(); + i128 expectedQuotient = 0; + i128 expectedRemainder = 42; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(I128Divide42ByMaxUi64Plus1) { + i128 dividend = 42; + i128 divider = i128{std::numeric_limits<ui64>::max()} + i128{1}; + i128 expectedQuotient = 0; + i128 expectedRemainder = 42; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(I128DivideMaxUi64ByMaxUi64Plus1) { + i128 dividend = i128{std::numeric_limits<ui64>::max()}; + i128 divider = i128{std::numeric_limits<ui64>::max()} + i128{1}; + i128 expectedQuotient = 0; + i128 expectedRemainder = i128{std::numeric_limits<ui64>::max()}; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } +} + +Y_UNIT_TEST_SUITE(I128DivisionWithDifferentSigns) { + Y_UNIT_TEST(DivisionPositiveByNegative) { + i128 dividend = i128{100}; + i128 divider = i128{-33}; + i128 expectedQuotient = -3; + i128 expectedRemainder = 1; + i128 quotient = dividend / divider; + i128 remainder = dividend % divider; + + UNIT_ASSERT_EQUAL(quotient, expectedQuotient); + UNIT_ASSERT_EQUAL(remainder, expectedRemainder); + } + + Y_UNIT_TEST(DivisionNegativeByPositive) { + i128 dividend = i128{-100}; + i128 divider = i128{33}; + i128 expectedQuotient = -3; + i128 expectedRemainder = -1; + i128 quotient = dividend / divider; + i128 remainder = dividend % divider; + + UNIT_ASSERT_EQUAL(quotient, expectedQuotient); + UNIT_ASSERT_EQUAL(remainder, expectedRemainder); + } + + Y_UNIT_TEST(DivisionNegativeByNegative) { + i128 dividend = i128{-100}; + i128 divider = i128{-33}; + i128 expectedQuotient = 3; + i128 expectedRemainder = -1; + i128 quotient = dividend / divider; + i128 remainder = dividend % divider; + + UNIT_ASSERT_EQUAL(quotient, expectedQuotient); + UNIT_ASSERT_EQUAL(remainder, expectedRemainder); + } +} + +Y_UNIT_TEST_SUITE(i128DivisionBigByBigSuite) { + Y_UNIT_TEST(i128DivideBigByBig1) { + i128 dividend = {64, 0}; + i128 divider = {1, 0}; + i128 expectedQuotient = 64; + i128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(i128DivideBigByBig1_PosByNeg) { + i128 dividend = i128{64, 0}; + i128 divider = -i128{1, 0}; + i128 expectedQuotient = -i128{64}; + i128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(i128DivideBigByBig1_NegByPos) { + i128 dividend = -i128{64, 0}; + i128 divider = i128{1, 0}; + i128 expectedQuotient = -i128{64}; + i128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(i128DivideBigByBig1_NegByNeg) { + i128 dividend = -i128{64, 0}; + i128 divider = -i128{1, 0}; + i128 expectedQuotient = i128{64}; + i128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(i128DivideBigByBig2) { + i128 dividend = {64, 0}; + i128 divider = {12, 5}; + i128 expectedQuotient = 5; + i128 expectedRemainder = i128{3, 18446744073709551591ull}; // plz don't ask + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(i128DivideBigByBig2_PosByNeg) { + i128 dividend = i128{64, 0}; + i128 divider = -i128{12, 5}; + i128 expectedQuotient = -5; + i128 expectedRemainder = i128{3, 18446744073709551591ull}; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(i128DivideBigByBig2_NegByPos) { + i128 dividend = -i128{64, 0}; + i128 divider = i128{12, 5}; + i128 expectedQuotient = -5; + i128 expectedRemainder = -i128{3, 18446744073709551591ull}; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(i128DivideBigByBig2_NegByNeg) { + i128 dividend = -i128{64, 0}; + i128 divider = -i128{12, 5}; + i128 expectedQuotient = 5; + i128 expectedRemainder = -i128{3, 18446744073709551591ull}; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + +} + +Y_UNIT_TEST_SUITE(i128DivisionAlgo) { + Y_UNIT_TEST(ii128DivideAlgoCheck_PosByPos) { + /* + 49672666804009505000000 / 10000000 == 4967266680400950 + 49672666804009505000000 % 10000000 == 5000000 + */ + i128 dividend = {2692ull, 14031757583392049728ull}; + i64 divider = 10000000; + i128 expectedQuotient = {0, 4967266680400950ull}; + i128 expectedRemainder = {0, 5000000ull}; + + i128 quotient = dividend / divider; + i128 reminder = dividend % divider; + + UNIT_ASSERT_EQUAL(quotient, expectedQuotient); + UNIT_ASSERT_EQUAL(reminder, expectedRemainder); + } + + Y_UNIT_TEST(ii128DivideAlgoCheck_PosByNeg) { + /* + 49672666804009505000000 / -10000000 == -4967266680400950 + 49672666804009505000000 % -10000000 == 5000000 + */ + i128 dividend = {2692ull, 14031757583392049728ull}; + i64 divider = -10000000; + i128 expectedQuotient = -i128{0, 4967266680400950ull}; + i128 expectedRemainder = {0, 5000000ull}; + + i128 quotient = dividend / divider; + i128 reminder = dividend % divider; + + UNIT_ASSERT_EQUAL(quotient, expectedQuotient); + UNIT_ASSERT_EQUAL(reminder, expectedRemainder); + } + + Y_UNIT_TEST(ii128DivideAlgoCheck_NegByPos) { + /* + -49672666804009505000000 / 10000000 == -4967266680400950 + -49672666804009505000000 % 10000000 == -5000000 + */ + i128 dividend = -i128{2692ull, 14031757583392049728ull}; + i64 divider = 10000000; + i128 expectedQuotient = -i128{0, 4967266680400950ull}; + i128 expectedRemainder = -i128{0, 5000000ull}; + + i128 quotient = dividend / divider; + i128 reminder = dividend % divider; + + UNIT_ASSERT_EQUAL(quotient, expectedQuotient); + UNIT_ASSERT_EQUAL(reminder, expectedRemainder); + } + + Y_UNIT_TEST(ii128DivideAlgoCheck_NegByNeg) { + /* + -49672666804009505000000 / -10000000 == 4967266680400950 + -49672666804009505000000 % -10000000 == -5000000 + */ + i128 dividend = -i128{2692ull, 14031757583392049728ull}; + i64 divider = -10000000; + i128 expectedQuotient = {0, 4967266680400950ull}; + i128 expectedRemainder = -i128{0, 5000000ull}; + + i128 quotient = dividend / divider; + i128 reminder = dividend % divider; + + UNIT_ASSERT_EQUAL(quotient, expectedQuotient); + UNIT_ASSERT_EQUAL(reminder, expectedRemainder); + } + +} diff --git a/library/cpp/int128/ut/i128_type_traits_ut.cpp b/library/cpp/int128/ut/i128_type_traits_ut.cpp index 87a49ad985..4ed87bf229 100644 --- a/library/cpp/int128/ut/i128_type_traits_ut.cpp +++ b/library/cpp/int128/ut/i128_type_traits_ut.cpp @@ -1,68 +1,68 @@ #include <library/cpp/testing/unittest/registar.h> - + #include <library/cpp/int128/int128.h> - -#include <util/generic/cast.h> - -Y_UNIT_TEST_SUITE(I128TypeTraitsSuite) { - Y_UNIT_TEST(OperatorNegate0) { - const i128 n = 0; - const i128 m = -n; - UNIT_ASSERT(n == m); - } - - Y_UNIT_TEST(OperatorNegate1) { - const i128 n = 1; - const i128 m = -n; - const i128 expected = -1; - UNIT_ASSERT(m == expected); - } - - Y_UNIT_TEST(OperatorNegate2Pow64) { - const i128 n = i128{1, 0}; - const i128 m = -n; - const i128 expected = {static_cast<ui64>(-1), 0}; - UNIT_ASSERT(m == expected); - } - - Y_UNIT_TEST(OperatorNegateNegate) { - const i128 x = 1; - const i128 y = -x; - const i128 z = -y; - UNIT_ASSERT(z == x); - } - - Y_UNIT_TEST(AbsFromPositive) { - const i128 n = 1; - const i128 m = std::abs(n); - UNIT_ASSERT(m == n); - } - - Y_UNIT_TEST(AbsFromNegative) { - const i128 n = -1; - const i128 m = std::abs(n); - const i128 expected = 1; - UNIT_ASSERT(m == expected); - } - - Y_UNIT_TEST(AbsFromZero) { - const i128 n = 0; - const i128 m = std::abs(n); - UNIT_ASSERT(m == n); - } - - Y_UNIT_TEST(SignbitOfPositive) { - const i128 n = 1; - UNIT_ASSERT(!std::signbit(n)); - } - - Y_UNIT_TEST(SignbitOfNegative) { - const i128 n = -1; - UNIT_ASSERT(std::signbit(n)); - } - - Y_UNIT_TEST(SignbitOfZero) { - const i128 n = 0; - UNIT_ASSERT(!std::signbit(n)); - } -} + +#include <util/generic/cast.h> + +Y_UNIT_TEST_SUITE(I128TypeTraitsSuite) { + Y_UNIT_TEST(OperatorNegate0) { + const i128 n = 0; + const i128 m = -n; + UNIT_ASSERT(n == m); + } + + Y_UNIT_TEST(OperatorNegate1) { + const i128 n = 1; + const i128 m = -n; + const i128 expected = -1; + UNIT_ASSERT(m == expected); + } + + Y_UNIT_TEST(OperatorNegate2Pow64) { + const i128 n = i128{1, 0}; + const i128 m = -n; + const i128 expected = {static_cast<ui64>(-1), 0}; + UNIT_ASSERT(m == expected); + } + + Y_UNIT_TEST(OperatorNegateNegate) { + const i128 x = 1; + const i128 y = -x; + const i128 z = -y; + UNIT_ASSERT(z == x); + } + + Y_UNIT_TEST(AbsFromPositive) { + const i128 n = 1; + const i128 m = std::abs(n); + UNIT_ASSERT(m == n); + } + + Y_UNIT_TEST(AbsFromNegative) { + const i128 n = -1; + const i128 m = std::abs(n); + const i128 expected = 1; + UNIT_ASSERT(m == expected); + } + + Y_UNIT_TEST(AbsFromZero) { + const i128 n = 0; + const i128 m = std::abs(n); + UNIT_ASSERT(m == n); + } + + Y_UNIT_TEST(SignbitOfPositive) { + const i128 n = 1; + UNIT_ASSERT(!std::signbit(n)); + } + + Y_UNIT_TEST(SignbitOfNegative) { + const i128 n = -1; + UNIT_ASSERT(std::signbit(n)); + } + + Y_UNIT_TEST(SignbitOfZero) { + const i128 n = 0; + UNIT_ASSERT(!std::signbit(n)); + } +} diff --git a/library/cpp/int128/ut/i128_ut.cpp b/library/cpp/int128/ut/i128_ut.cpp index 39408d4d37..c196d132a2 100644 --- a/library/cpp/int128/ut/i128_ut.cpp +++ b/library/cpp/int128/ut/i128_ut.cpp @@ -1,12 +1,12 @@ #include <library/cpp/testing/unittest/registar.h> - + #include <library/cpp/int128/int128.h> - -#include <util/generic/cast.h> - -Y_UNIT_TEST_SUITE(I128Suite) { - Y_UNIT_TEST(CreateI128FromUnsigned) { - i128 v{ui64(1)}; - Y_UNUSED(v); - } -} + +#include <util/generic/cast.h> + +Y_UNIT_TEST_SUITE(I128Suite) { + Y_UNIT_TEST(CreateI128FromUnsigned) { + i128 v{ui64(1)}; + Y_UNUSED(v); + } +} diff --git a/library/cpp/int128/ut/int128_old_ut.cpp b/library/cpp/int128/ut/int128_old_ut.cpp index e8dfbff5c2..2c5b9e9610 100644 --- a/library/cpp/int128/ut/int128_old_ut.cpp +++ b/library/cpp/int128/ut/int128_old_ut.cpp @@ -1,8 +1,8 @@ #include <library/cpp/testing/unittest/registar.h> #include <library/cpp/int128/int128.h> -#include "int128_ut_helpers.h" - +#include "int128_ut_helpers.h" + class TUInt128Test: public TTestBase { UNIT_TEST_SUITE(TUInt128Test); UNIT_TEST(Create); @@ -13,9 +13,9 @@ class TUInt128Test: public TTestBase { UNIT_TEST(Underflow); UNIT_TEST(ToStringTest); UNIT_TEST(FromStringTest); -#if defined(Y_HAVE_INT128) +#if defined(Y_HAVE_INT128) UNIT_TEST(FromSystemUint128); -#endif +#endif UNIT_TEST_SUITE_END(); private: @@ -25,30 +25,30 @@ private: void Shift(); void Overflow(); void Underflow(); - void ToStringTest(); - void FromStringTest(); -#if defined(Y_HAVE_INT128) - void FromSystemUint128(); -#endif + void ToStringTest(); + void FromStringTest(); +#if defined(Y_HAVE_INT128) + void FromSystemUint128(); +#endif }; UNIT_TEST_SUITE_REGISTRATION(TUInt128Test); void TUInt128Test::Create() { - const ui128 n1 = 10; + const ui128 n1 = 10; UNIT_ASSERT_EQUAL(n1, 10); - const ui128 n2 = n1; + const ui128 n2 = n1; UNIT_ASSERT_EQUAL(n2, 10); - const ui128 n3(10); + const ui128 n3(10); UNIT_ASSERT_EQUAL(n3, 10); } void TUInt128Test::Minus() { - const ui128 n2 = 20; - const ui128 n3 = 30; + const ui128 n2 = 20; + const ui128 n3 = 30; - ui128 n4 = n3 - n2; + ui128 n4 = n3 - n2; UNIT_ASSERT_EQUAL(n4, 10); n4 = n4 - 2; @@ -61,10 +61,10 @@ void TUInt128Test::Minus() { UNIT_ASSERT_EQUAL(n4, 4); } void TUInt128Test::Plus() { - const ui128 n2 = 20; - const ui128 n3 = 30; + const ui128 n2 = 20; + const ui128 n3 = 30; - ui128 n4 = n3 + n2; + ui128 n4 = n3 + n2; UNIT_ASSERT_EQUAL(n4, 50); n4 = n4 + 2; @@ -77,103 +77,103 @@ void TUInt128Test::Plus() { UNIT_ASSERT_EQUAL(n4, 64); } void TUInt128Test::Shift() { - ui128 n = 1; + ui128 n = 1; - const ui128 n4 = n << 4; - UNIT_ASSERT_EQUAL(n4, ui128(0x0, 0x0000000000000010)); + const ui128 n4 = n << 4; + UNIT_ASSERT_EQUAL(n4, ui128(0x0, 0x0000000000000010)); UNIT_ASSERT_EQUAL(n4 >> 4, 1); - const ui128 n8 = n << 8; - UNIT_ASSERT_EQUAL(n8, ui128(0x0, 0x0000000000000100)); + const ui128 n8 = n << 8; + UNIT_ASSERT_EQUAL(n8, ui128(0x0, 0x0000000000000100)); UNIT_ASSERT_EQUAL(n8 >> 8, 1); - const ui128 n60 = n << 60; - UNIT_ASSERT_EQUAL(n60, ui128(0x0, 0x1000000000000000)); + const ui128 n60 = n << 60; + UNIT_ASSERT_EQUAL(n60, ui128(0x0, 0x1000000000000000)); UNIT_ASSERT_EQUAL(n60 >> 60, 1); - const ui128 n64 = n << 64; - UNIT_ASSERT_EQUAL(n64, ui128(0x1, 0x0000000000000000)); + const ui128 n64 = n << 64; + UNIT_ASSERT_EQUAL(n64, ui128(0x1, 0x0000000000000000)); UNIT_ASSERT_EQUAL(n64 >> 64, 1); - const ui128 n124 = n << 124; - UNIT_ASSERT_EQUAL(n124, ui128(0x1000000000000000, 0x0000000000000000)); + const ui128 n124 = n << 124; + UNIT_ASSERT_EQUAL(n124, ui128(0x1000000000000000, 0x0000000000000000)); UNIT_ASSERT_EQUAL(n124 >> 124, 1); } void TUInt128Test::Overflow() { - ui128 n = ui128(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF); - const ui128 n2 = n + 2; + ui128 n = ui128(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF); + const ui128 n2 = n + 2; UNIT_ASSERT_EQUAL(n2, 1); } void TUInt128Test::Underflow() { - ui128 n = 1; - const ui128 n128 = n - 2; - UNIT_ASSERT_EQUAL(n128, ui128(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF)); + ui128 n = 1; + const ui128 n128 = n - 2; + UNIT_ASSERT_EQUAL(n128, ui128(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF)); +} + +void TUInt128Test::ToStringTest() { + ui128 n(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF); + TString correct = "340282366920938463463374607431768211455"; + UNIT_ASSERT_EQUAL(correct, ::ToString(n)); +} + +void TUInt128Test::FromStringTest() { + { + const TString originalString = "37778931862957161709568"; + const ui128 number = FromString<ui128>(originalString); + UNIT_ASSERT_EQUAL(ToString(number), originalString); + } + + { + const TString originalString = "1024"; + const ui128 number = FromString<ui128>(originalString); + UNIT_ASSERT_EQUAL(ToString(number), originalString); + UNIT_ASSERT_EQUAL(GetHigh(number), 0); + UNIT_ASSERT_EQUAL(GetLow(number), 1024); + } + + { + const TString originalString = "18446744073709551616"; // 2^64, i.e. UINT64_MAX + 1 + const ui128 number = FromString<ui128>(originalString); + UNIT_ASSERT_EQUAL(ToString(number), originalString); + UNIT_ASSERT_EQUAL(GetHigh(number), 1); + UNIT_ASSERT_EQUAL(GetLow(number), 0); + } + + { + const TString originalString = "340282366920938463463374607431768211455"; // 2^128-1, i.e. UINT128_MAX + const ui128 number = FromString<ui128>(originalString); + UNIT_ASSERT_EQUAL(ToString(number), originalString); + UNIT_ASSERT_EQUAL(GetHigh(number), 0xFFFFFFFFFFFFFFFF); + UNIT_ASSERT_EQUAL(GetLow(number), 0xFFFFFFFFFFFFFFFF); + } +} + +#if defined(Y_HAVE_INT128) +void TUInt128Test::FromSystemUint128() { + unsigned __int128 n = 1; + ui128 number{n}; + + UNIT_ASSERT_EQUAL(GetLow(number), 1); + UNIT_ASSERT_EQUAL(GetHigh(number), 0); + + auto byteArray = NInt128Private::GetAsArray(number); +#ifdef _little_endian_ + UNIT_ASSERT_EQUAL(byteArray[0], 1); + for (size_t i = 1; i < 16; i++) { + UNIT_ASSERT_EQUAL(byteArray[i], 0); + } +#elif defined(_big_endian_) + UNIT_ASSERT_EQUAL(byteArray[15], 1); + for (size_t i = 0; i < 15; i++) { + UNIT_ASSERT_EQUAL(byteArray[i], 0); + } +#endif + + UNIT_ASSERT_EQUAL(std::memcmp((void*)&n, (void*)&number, 16), 0); + + UNIT_ASSERT_EQUAL(ToString(n), "1"); + + UNIT_ASSERT_EQUAL(FromString<unsigned __int128>(ToString(n)), n); } - -void TUInt128Test::ToStringTest() { - ui128 n(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF); - TString correct = "340282366920938463463374607431768211455"; - UNIT_ASSERT_EQUAL(correct, ::ToString(n)); -} - -void TUInt128Test::FromStringTest() { - { - const TString originalString = "37778931862957161709568"; - const ui128 number = FromString<ui128>(originalString); - UNIT_ASSERT_EQUAL(ToString(number), originalString); - } - - { - const TString originalString = "1024"; - const ui128 number = FromString<ui128>(originalString); - UNIT_ASSERT_EQUAL(ToString(number), originalString); - UNIT_ASSERT_EQUAL(GetHigh(number), 0); - UNIT_ASSERT_EQUAL(GetLow(number), 1024); - } - - { - const TString originalString = "18446744073709551616"; // 2^64, i.e. UINT64_MAX + 1 - const ui128 number = FromString<ui128>(originalString); - UNIT_ASSERT_EQUAL(ToString(number), originalString); - UNIT_ASSERT_EQUAL(GetHigh(number), 1); - UNIT_ASSERT_EQUAL(GetLow(number), 0); - } - - { - const TString originalString = "340282366920938463463374607431768211455"; // 2^128-1, i.e. UINT128_MAX - const ui128 number = FromString<ui128>(originalString); - UNIT_ASSERT_EQUAL(ToString(number), originalString); - UNIT_ASSERT_EQUAL(GetHigh(number), 0xFFFFFFFFFFFFFFFF); - UNIT_ASSERT_EQUAL(GetLow(number), 0xFFFFFFFFFFFFFFFF); - } -} - -#if defined(Y_HAVE_INT128) -void TUInt128Test::FromSystemUint128() { - unsigned __int128 n = 1; - ui128 number{n}; - - UNIT_ASSERT_EQUAL(GetLow(number), 1); - UNIT_ASSERT_EQUAL(GetHigh(number), 0); - - auto byteArray = NInt128Private::GetAsArray(number); -#ifdef _little_endian_ - UNIT_ASSERT_EQUAL(byteArray[0], 1); - for (size_t i = 1; i < 16; i++) { - UNIT_ASSERT_EQUAL(byteArray[i], 0); - } -#elif defined(_big_endian_) - UNIT_ASSERT_EQUAL(byteArray[15], 1); - for (size_t i = 0; i < 15; i++) { - UNIT_ASSERT_EQUAL(byteArray[i], 0); - } -#endif - - UNIT_ASSERT_EQUAL(std::memcmp((void*)&n, (void*)&number, 16), 0); - - UNIT_ASSERT_EQUAL(ToString(n), "1"); - - UNIT_ASSERT_EQUAL(FromString<unsigned __int128>(ToString(n)), n); -} -#endif +#endif diff --git a/library/cpp/int128/ut/int128_typetraits_ut.cpp b/library/cpp/int128/ut/int128_typetraits_ut.cpp index 32be581dd0..fd5f19d7b8 100644 --- a/library/cpp/int128/ut/int128_typetraits_ut.cpp +++ b/library/cpp/int128/ut/int128_typetraits_ut.cpp @@ -1,306 +1,306 @@ #include <library/cpp/testing/unittest/registar.h> - + #include <library/cpp/int128/int128.h> - -#include <type_traits> - -Y_UNIT_TEST_SUITE(TypeTraitsSuite) { - Y_UNIT_TEST(Uint128TypeTraits) { - // checks that all type traits of ui128 are the same as of ui64 - // https://en.cppreference.com/w/cpp/header/type_traits - UNIT_ASSERT_EQUAL( - std::is_void<ui128>::value, - std::is_void<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_null_pointer<ui128>::value, - std::is_null_pointer<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_integral<ui128>::value, - std::is_integral<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_floating_point<ui128>::value, - std::is_floating_point<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_array<ui128>::value, - std::is_array<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_enum<ui128>::value, - std::is_enum<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_union<ui128>::value, - std::is_union<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_class<ui128>::value, - std::is_class<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_function<ui128>::value, - std::is_function<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_pointer<ui128>::value, - std::is_pointer<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_lvalue_reference<ui128>::value, - std::is_lvalue_reference<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_rvalue_reference<ui128>::value, - std::is_rvalue_reference<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_member_object_pointer<ui128>::value, - std::is_member_object_pointer<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_member_function_pointer<ui128>::value, - std::is_member_function_pointer<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_fundamental<ui128>::value, - std::is_fundamental<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_arithmetic<ui128>::value, - std::is_arithmetic<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_scalar<ui128>::value, - std::is_scalar<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_object<ui128>::value, - std::is_object<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_compound<ui128>::value, - std::is_compound<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_reference<ui128>::value, - std::is_reference<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_member_pointer<ui128>::value, - std::is_member_pointer<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_const<ui128>::value, - std::is_const<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_volatile<ui128>::value, - std::is_volatile<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_trivial<ui128>::value, - std::is_trivial<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_standard_layout<ui128>::value, - std::is_standard_layout<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_pod<ui128>::value, - std::is_pod<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_literal_type<ui128>::value, - std::is_literal_type<ui64>::value - ); -#ifndef _MSC_VER - UNIT_ASSERT_EQUAL( - std::has_unique_object_representations<ui128>::value, - std::has_unique_object_representations<ui64>::value - ); -#endif - UNIT_ASSERT_EQUAL( - std::is_empty<ui128>::value, - std::is_empty<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_polymorphic<ui128>::value, - std::is_polymorphic<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_abstract<ui128>::value, - std::is_abstract<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_final<ui128>::value, - std::is_final<ui64>::value - ); -#ifndef _MSC_VER - UNIT_ASSERT_EQUAL( - std::is_aggregate<ui128>::value, - std::is_aggregate<ui64>::value - ); -#endif - UNIT_ASSERT_EQUAL( - std::is_signed<ui128>::value, - std::is_signed<ui64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_unsigned<ui128>::value, - std::is_unsigned<ui64>::value - ); - } - - Y_UNIT_TEST(Int128TypeTraits) { - // checks that all type traits of i128 are the same as of i64 - // https://en.cppreference.com/w/cpp/header/type_traits - UNIT_ASSERT_EQUAL( - std::is_void<i128>::value, - std::is_void<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_null_pointer<i128>::value, - std::is_null_pointer<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_integral<i128>::value, - std::is_integral<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_floating_point<i128>::value, - std::is_floating_point<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_array<i128>::value, - std::is_array<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_enum<i128>::value, - std::is_enum<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_union<i128>::value, - std::is_union<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_class<i128>::value, - std::is_class<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_function<i128>::value, - std::is_function<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_pointer<i128>::value, - std::is_pointer<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_lvalue_reference<i128>::value, - std::is_lvalue_reference<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_rvalue_reference<i128>::value, - std::is_rvalue_reference<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_member_object_pointer<i128>::value, - std::is_member_object_pointer<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_member_function_pointer<i128>::value, - std::is_member_function_pointer<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_fundamental<i128>::value, - std::is_fundamental<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_arithmetic<i128>::value, - std::is_arithmetic<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_scalar<i128>::value, - std::is_scalar<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_object<i128>::value, - std::is_object<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_compound<i128>::value, - std::is_compound<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_reference<i128>::value, - std::is_reference<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_member_pointer<i128>::value, - std::is_member_pointer<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_const<i128>::value, - std::is_const<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_volatile<i128>::value, - std::is_volatile<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_trivial<i128>::value, - std::is_trivial<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_standard_layout<i128>::value, - std::is_standard_layout<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_pod<i128>::value, - std::is_pod<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_literal_type<i128>::value, - std::is_literal_type<i64>::value - ); -#ifndef _MSC_VER - UNIT_ASSERT_EQUAL( - std::has_unique_object_representations<i128>::value, - std::has_unique_object_representations<i64>::value - ); -#endif - UNIT_ASSERT_EQUAL( - std::is_empty<i128>::value, - std::is_empty<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_polymorphic<i128>::value, - std::is_polymorphic<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_abstract<i128>::value, - std::is_abstract<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_final<i128>::value, - std::is_final<i64>::value - ); -#ifndef _MSC_VER - UNIT_ASSERT_EQUAL( - std::is_aggregate<i128>::value, - std::is_aggregate<i64>::value - ); -#endif - UNIT_ASSERT_EQUAL( - std::is_signed<i128>::value, - std::is_signed<i64>::value - ); - UNIT_ASSERT_EQUAL( - std::is_unsigned<i128>::value, - std::is_unsigned<i64>::value - ); - } -} - + +#include <type_traits> + +Y_UNIT_TEST_SUITE(TypeTraitsSuite) { + Y_UNIT_TEST(Uint128TypeTraits) { + // checks that all type traits of ui128 are the same as of ui64 + // https://en.cppreference.com/w/cpp/header/type_traits + UNIT_ASSERT_EQUAL( + std::is_void<ui128>::value, + std::is_void<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_null_pointer<ui128>::value, + std::is_null_pointer<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_integral<ui128>::value, + std::is_integral<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_floating_point<ui128>::value, + std::is_floating_point<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_array<ui128>::value, + std::is_array<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_enum<ui128>::value, + std::is_enum<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_union<ui128>::value, + std::is_union<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_class<ui128>::value, + std::is_class<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_function<ui128>::value, + std::is_function<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_pointer<ui128>::value, + std::is_pointer<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_lvalue_reference<ui128>::value, + std::is_lvalue_reference<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_rvalue_reference<ui128>::value, + std::is_rvalue_reference<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_member_object_pointer<ui128>::value, + std::is_member_object_pointer<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_member_function_pointer<ui128>::value, + std::is_member_function_pointer<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_fundamental<ui128>::value, + std::is_fundamental<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_arithmetic<ui128>::value, + std::is_arithmetic<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_scalar<ui128>::value, + std::is_scalar<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_object<ui128>::value, + std::is_object<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_compound<ui128>::value, + std::is_compound<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_reference<ui128>::value, + std::is_reference<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_member_pointer<ui128>::value, + std::is_member_pointer<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_const<ui128>::value, + std::is_const<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_volatile<ui128>::value, + std::is_volatile<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_trivial<ui128>::value, + std::is_trivial<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_standard_layout<ui128>::value, + std::is_standard_layout<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_pod<ui128>::value, + std::is_pod<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_literal_type<ui128>::value, + std::is_literal_type<ui64>::value + ); +#ifndef _MSC_VER + UNIT_ASSERT_EQUAL( + std::has_unique_object_representations<ui128>::value, + std::has_unique_object_representations<ui64>::value + ); +#endif + UNIT_ASSERT_EQUAL( + std::is_empty<ui128>::value, + std::is_empty<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_polymorphic<ui128>::value, + std::is_polymorphic<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_abstract<ui128>::value, + std::is_abstract<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_final<ui128>::value, + std::is_final<ui64>::value + ); +#ifndef _MSC_VER + UNIT_ASSERT_EQUAL( + std::is_aggregate<ui128>::value, + std::is_aggregate<ui64>::value + ); +#endif + UNIT_ASSERT_EQUAL( + std::is_signed<ui128>::value, + std::is_signed<ui64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_unsigned<ui128>::value, + std::is_unsigned<ui64>::value + ); + } + + Y_UNIT_TEST(Int128TypeTraits) { + // checks that all type traits of i128 are the same as of i64 + // https://en.cppreference.com/w/cpp/header/type_traits + UNIT_ASSERT_EQUAL( + std::is_void<i128>::value, + std::is_void<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_null_pointer<i128>::value, + std::is_null_pointer<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_integral<i128>::value, + std::is_integral<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_floating_point<i128>::value, + std::is_floating_point<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_array<i128>::value, + std::is_array<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_enum<i128>::value, + std::is_enum<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_union<i128>::value, + std::is_union<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_class<i128>::value, + std::is_class<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_function<i128>::value, + std::is_function<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_pointer<i128>::value, + std::is_pointer<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_lvalue_reference<i128>::value, + std::is_lvalue_reference<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_rvalue_reference<i128>::value, + std::is_rvalue_reference<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_member_object_pointer<i128>::value, + std::is_member_object_pointer<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_member_function_pointer<i128>::value, + std::is_member_function_pointer<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_fundamental<i128>::value, + std::is_fundamental<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_arithmetic<i128>::value, + std::is_arithmetic<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_scalar<i128>::value, + std::is_scalar<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_object<i128>::value, + std::is_object<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_compound<i128>::value, + std::is_compound<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_reference<i128>::value, + std::is_reference<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_member_pointer<i128>::value, + std::is_member_pointer<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_const<i128>::value, + std::is_const<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_volatile<i128>::value, + std::is_volatile<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_trivial<i128>::value, + std::is_trivial<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_standard_layout<i128>::value, + std::is_standard_layout<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_pod<i128>::value, + std::is_pod<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_literal_type<i128>::value, + std::is_literal_type<i64>::value + ); +#ifndef _MSC_VER + UNIT_ASSERT_EQUAL( + std::has_unique_object_representations<i128>::value, + std::has_unique_object_representations<i64>::value + ); +#endif + UNIT_ASSERT_EQUAL( + std::is_empty<i128>::value, + std::is_empty<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_polymorphic<i128>::value, + std::is_polymorphic<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_abstract<i128>::value, + std::is_abstract<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_final<i128>::value, + std::is_final<i64>::value + ); +#ifndef _MSC_VER + UNIT_ASSERT_EQUAL( + std::is_aggregate<i128>::value, + std::is_aggregate<i64>::value + ); +#endif + UNIT_ASSERT_EQUAL( + std::is_signed<i128>::value, + std::is_signed<i64>::value + ); + UNIT_ASSERT_EQUAL( + std::is_unsigned<i128>::value, + std::is_unsigned<i64>::value + ); + } +} + diff --git a/library/cpp/int128/ut/int128_ut.cpp b/library/cpp/int128/ut/int128_ut.cpp index 0d68e42100..7339264017 100644 --- a/library/cpp/int128/ut/int128_ut.cpp +++ b/library/cpp/int128/ut/int128_ut.cpp @@ -1,56 +1,56 @@ #include <library/cpp/testing/unittest/registar.h> - + #include <library/cpp/int128/int128.h> - -#include <util/generic/cast.h> - -#include <type_traits> - -Y_UNIT_TEST_SUITE(Uint128Suite) { - Y_UNIT_TEST(Uint128DefaultCtor) { - const ui128 value{}; - UNIT_ASSERT_EQUAL(GetLow(value), 0); - UNIT_ASSERT_EQUAL(GetHigh(value), 0); - } - - Y_UNIT_TEST(Uint128NumericLimits) { - UNIT_ASSERT_EQUAL(std::numeric_limits<ui128>::digits, 128); - UNIT_ASSERT_EQUAL(std::numeric_limits<ui128>::max() + 1, ui128{0}); - } - - Y_UNIT_TEST(Uint128Sizeof) { - UNIT_ASSERT_EQUAL(sizeof(ui128), sizeof(ui64) * 2); - } - - Y_UNIT_TEST(Uint128Cast) { - // see util/generic/cast.h - const auto underlyingTypeIsSelf = std::is_same<::NPrivate::TUnderlyingTypeOrSelf<ui128>, ui128>::value; - UNIT_ASSERT_EQUAL(underlyingTypeIsSelf, true); - - const auto convertibleUi128Ui128 = ::NPrivate::TSafelyConvertible<ui128, ui128>::Result; - const auto convertibleUi64Ui128 = ::NPrivate::TSafelyConvertible<ui64, ui128>::Result; - const auto convertibleUi128Ui64 = ::NPrivate::TSafelyConvertible<ui128, ui64>::Result; - UNIT_ASSERT_EQUAL(convertibleUi128Ui128, true); // from ui128 to ui128 => safe - UNIT_ASSERT_EQUAL(convertibleUi64Ui128, false); // from ui128 to ui64 => not safe - UNIT_ASSERT_EQUAL(convertibleUi128Ui64, true); // from ui64 to ui128 => safe - } - - Y_UNIT_TEST(SafeIntegerCastTest) { - ui128 narrowNumber = 1; - - UNIT_ASSERT_NO_EXCEPTION(SafeIntegerCast<ui64>(narrowNumber)); - - ui128 wideNumber{0}; - wideNumber -= 1; - UNIT_ASSERT_EXCEPTION(SafeIntegerCast<ui64>(wideNumber), yexception); - } - - Y_UNIT_TEST(SignbitTest) { - UNIT_ASSERT(!std::signbit(ui128{0})); - UNIT_ASSERT(!std::signbit(ui128{-1})); - UNIT_ASSERT(!std::signbit(i128{0})); - UNIT_ASSERT(std::signbit(i128{-1})); - } + +#include <util/generic/cast.h> + +#include <type_traits> + +Y_UNIT_TEST_SUITE(Uint128Suite) { + Y_UNIT_TEST(Uint128DefaultCtor) { + const ui128 value{}; + UNIT_ASSERT_EQUAL(GetLow(value), 0); + UNIT_ASSERT_EQUAL(GetHigh(value), 0); + } + + Y_UNIT_TEST(Uint128NumericLimits) { + UNIT_ASSERT_EQUAL(std::numeric_limits<ui128>::digits, 128); + UNIT_ASSERT_EQUAL(std::numeric_limits<ui128>::max() + 1, ui128{0}); + } + + Y_UNIT_TEST(Uint128Sizeof) { + UNIT_ASSERT_EQUAL(sizeof(ui128), sizeof(ui64) * 2); + } + + Y_UNIT_TEST(Uint128Cast) { + // see util/generic/cast.h + const auto underlyingTypeIsSelf = std::is_same<::NPrivate::TUnderlyingTypeOrSelf<ui128>, ui128>::value; + UNIT_ASSERT_EQUAL(underlyingTypeIsSelf, true); + + const auto convertibleUi128Ui128 = ::NPrivate::TSafelyConvertible<ui128, ui128>::Result; + const auto convertibleUi64Ui128 = ::NPrivate::TSafelyConvertible<ui64, ui128>::Result; + const auto convertibleUi128Ui64 = ::NPrivate::TSafelyConvertible<ui128, ui64>::Result; + UNIT_ASSERT_EQUAL(convertibleUi128Ui128, true); // from ui128 to ui128 => safe + UNIT_ASSERT_EQUAL(convertibleUi64Ui128, false); // from ui128 to ui64 => not safe + UNIT_ASSERT_EQUAL(convertibleUi128Ui64, true); // from ui64 to ui128 => safe + } + + Y_UNIT_TEST(SafeIntegerCastTest) { + ui128 narrowNumber = 1; + + UNIT_ASSERT_NO_EXCEPTION(SafeIntegerCast<ui64>(narrowNumber)); + + ui128 wideNumber{0}; + wideNumber -= 1; + UNIT_ASSERT_EXCEPTION(SafeIntegerCast<ui64>(wideNumber), yexception); + } + + Y_UNIT_TEST(SignbitTest) { + UNIT_ASSERT(!std::signbit(ui128{0})); + UNIT_ASSERT(!std::signbit(ui128{-1})); + UNIT_ASSERT(!std::signbit(i128{0})); + UNIT_ASSERT(std::signbit(i128{-1})); + } Y_UNIT_TEST(ToStringTest) { // int128 @@ -80,4 +80,4 @@ Y_UNIT_TEST_SUITE(Uint128Suite) { ), "235108557486403940296800289353599800327"); } -} +} diff --git a/library/cpp/int128/ut/int128_ut_helpers.cpp b/library/cpp/int128/ut/int128_ut_helpers.cpp index cb712f869a..e6c3e24d10 100644 --- a/library/cpp/int128/ut/int128_ut_helpers.cpp +++ b/library/cpp/int128/ut/int128_ut_helpers.cpp @@ -1,56 +1,56 @@ -#include "int128_ut_helpers.h" - -namespace NInt128Private { -#if defined(_little_endian_) - std::array<ui8, 16> GetAsArray(const ui128 value) { - std::array<ui8, 16> result; - const ui64 low = GetLow(value); - const ui64 high = GetHigh(value); - MemCopy(result.data(), reinterpret_cast<const ui8*>(&low), sizeof(low)); - MemCopy(result.data() + sizeof(low), reinterpret_cast<const ui8*>(&high), sizeof(high)); - return result; - } - - std::array<ui8, 16> GetAsArray(const i128 value) { - std::array<ui8, 16> result; - const ui64 low = GetLow(value); - const ui64 high = GetHigh(value); - MemCopy(result.data(), reinterpret_cast<const ui8*>(&low), sizeof(low)); - MemCopy(result.data() + sizeof(low), reinterpret_cast<const ui8*>(&high), sizeof(high)); - return result; - } -#elif defined(_big_endian_) - std::array<ui8, 16> GetAsArray(const i128 value) { - std::array<ui8, 16> result; - const ui64 low = GetLow(value); - const ui64 high = GetHigh(value); - MemCopy(result.data(), reinterpret_cast<const ui8*>(&high), sizeof(high)); - MemCopy(result.data() + sizeof(high), reinterpret_cast<const ui8*>(&low), sizeof(low)); - return result; - } - - std::array<ui8, 16> GetAsArray(const ui128 value) { - std::array<ui8, 16> result; - const ui64 low = GetLow(value); - const ui64 high = GetHigh(value); - MemCopy(result.data(), reinterpret_cast<const ui8*>(&high), sizeof(high)); - MemCopy(result.data() + sizeof(high), reinterpret_cast<const ui8*>(&low), sizeof(low)); - return result; - } -#endif - -#if defined(Y_HAVE_INT128) - std::array<ui8, 16> GetAsArray(const unsigned __int128 value) { - std::array<ui8, 16> result; - MemCopy(result.data(), reinterpret_cast<const ui8*>(&value), sizeof(value)); - return result; - } - - std::array<ui8, 16> GetAsArray(const signed __int128 value) { - std::array<ui8, 16> result; - MemCopy(result.data(), reinterpret_cast<const ui8*>(&value), sizeof(value)); - return result; - } -#endif - -} +#include "int128_ut_helpers.h" + +namespace NInt128Private { +#if defined(_little_endian_) + std::array<ui8, 16> GetAsArray(const ui128 value) { + std::array<ui8, 16> result; + const ui64 low = GetLow(value); + const ui64 high = GetHigh(value); + MemCopy(result.data(), reinterpret_cast<const ui8*>(&low), sizeof(low)); + MemCopy(result.data() + sizeof(low), reinterpret_cast<const ui8*>(&high), sizeof(high)); + return result; + } + + std::array<ui8, 16> GetAsArray(const i128 value) { + std::array<ui8, 16> result; + const ui64 low = GetLow(value); + const ui64 high = GetHigh(value); + MemCopy(result.data(), reinterpret_cast<const ui8*>(&low), sizeof(low)); + MemCopy(result.data() + sizeof(low), reinterpret_cast<const ui8*>(&high), sizeof(high)); + return result; + } +#elif defined(_big_endian_) + std::array<ui8, 16> GetAsArray(const i128 value) { + std::array<ui8, 16> result; + const ui64 low = GetLow(value); + const ui64 high = GetHigh(value); + MemCopy(result.data(), reinterpret_cast<const ui8*>(&high), sizeof(high)); + MemCopy(result.data() + sizeof(high), reinterpret_cast<const ui8*>(&low), sizeof(low)); + return result; + } + + std::array<ui8, 16> GetAsArray(const ui128 value) { + std::array<ui8, 16> result; + const ui64 low = GetLow(value); + const ui64 high = GetHigh(value); + MemCopy(result.data(), reinterpret_cast<const ui8*>(&high), sizeof(high)); + MemCopy(result.data() + sizeof(high), reinterpret_cast<const ui8*>(&low), sizeof(low)); + return result; + } +#endif + +#if defined(Y_HAVE_INT128) + std::array<ui8, 16> GetAsArray(const unsigned __int128 value) { + std::array<ui8, 16> result; + MemCopy(result.data(), reinterpret_cast<const ui8*>(&value), sizeof(value)); + return result; + } + + std::array<ui8, 16> GetAsArray(const signed __int128 value) { + std::array<ui8, 16> result; + MemCopy(result.data(), reinterpret_cast<const ui8*>(&value), sizeof(value)); + return result; + } +#endif + +} diff --git a/library/cpp/int128/ut/int128_ut_helpers.h b/library/cpp/int128/ut/int128_ut_helpers.h index 99a8fa7436..b7778c3f32 100644 --- a/library/cpp/int128/ut/int128_ut_helpers.h +++ b/library/cpp/int128/ut/int128_ut_helpers.h @@ -1,15 +1,15 @@ -#pragma once - +#pragma once + #include <library/cpp/int128/int128.h> - -#include <array> - -namespace NInt128Private { - std::array<ui8, 16> GetAsArray(const ui128 value); - std::array<ui8, 16> GetAsArray(const i128 value); - -#if defined(Y_HAVE_INT128) - std::array<ui8, 16> GetAsArray(const unsigned __int128 value); - std::array<ui8, 16> GetAsArray(const signed __int128 value); -#endif -} + +#include <array> + +namespace NInt128Private { + std::array<ui8, 16> GetAsArray(const ui128 value); + std::array<ui8, 16> GetAsArray(const i128 value); + +#if defined(Y_HAVE_INT128) + std::array<ui8, 16> GetAsArray(const unsigned __int128 value); + std::array<ui8, 16> GetAsArray(const signed __int128 value); +#endif +} diff --git a/library/cpp/int128/ut/int128_via_intrinsic_ut.cpp b/library/cpp/int128/ut/int128_via_intrinsic_ut.cpp index e1eff5fcb3..9decc2fd48 100644 --- a/library/cpp/int128/ut/int128_via_intrinsic_ut.cpp +++ b/library/cpp/int128/ut/int128_via_intrinsic_ut.cpp @@ -2,33 +2,33 @@ #include <library/cpp/testing/unittest/registar.h> -// from https://a.yandex-team.ru/arc/trunk/arcadia/library/ticket_parser/c/src/ut/utils_ut.cpp?rev=4221861 +// from https://a.yandex-team.ru/arc/trunk/arcadia/library/ticket_parser/c/src/ut/utils_ut.cpp?rev=4221861 -#if defined(Y_HAVE_INT128) -Y_UNIT_TEST_SUITE(Int128ViaIntrinsicSuite) { +#if defined(Y_HAVE_INT128) +Y_UNIT_TEST_SUITE(Int128ViaIntrinsicSuite) { using guint128_t = unsigned __int128; - guint128_t toGcc(ui128 num) { + guint128_t toGcc(ui128 num) { guint128_t res = 0; - res |= GetLow(num); - res |= guint128_t(GetHigh(num)) << 64; + res |= GetLow(num); + res |= guint128_t(GetHigh(num)) << 64; return res; } Y_UNIT_TEST(bigintTest) { - UNIT_ASSERT(guint128_t(127) == toGcc(ui128(127))); - UNIT_ASSERT(guint128_t(127) * guint128_t(127) == toGcc(ui128(127) * ui128(127))); - UNIT_ASSERT(guint128_t(127) + guint128_t(127) == toGcc(ui128(127) + ui128(127))); - UNIT_ASSERT(guint128_t(127) << 3 == toGcc(ui128(127) << 3)); - UNIT_ASSERT(guint128_t(127) >> 1 == toGcc(ui128(127) >> 1)); + UNIT_ASSERT(guint128_t(127) == toGcc(ui128(127))); + UNIT_ASSERT(guint128_t(127) * guint128_t(127) == toGcc(ui128(127) * ui128(127))); + UNIT_ASSERT(guint128_t(127) + guint128_t(127) == toGcc(ui128(127) + ui128(127))); + UNIT_ASSERT(guint128_t(127) << 3 == toGcc(ui128(127) << 3)); + UNIT_ASSERT(guint128_t(127) >> 1 == toGcc(ui128(127) >> 1)); - UNIT_ASSERT(guint128_t(1000000000027UL) * guint128_t(1000000000027UL) == toGcc(ui128(1000000000027UL) * ui128(1000000000027UL))); - UNIT_ASSERT(guint128_t(1000000000027UL) + guint128_t(1000000000027UL) == toGcc(ui128(1000000000027UL) + ui128(1000000000027UL))); - UNIT_ASSERT(guint128_t(1000000000027UL) << 3 == toGcc(ui128(1000000000027UL) << 3)); - UNIT_ASSERT(guint128_t(1000000000027UL) >> 1 == toGcc(ui128(1000000000027UL) >> 1)); - UNIT_ASSERT((guint128_t(1000000000027UL) * guint128_t(1000000000027UL)) << 3 == toGcc((ui128(1000000000027UL) * ui128(1000000000027UL)) << 3)); - UNIT_ASSERT((guint128_t(1000000000027UL) + guint128_t(1000000000027UL)) >> 1 == toGcc((ui128(1000000000027UL) + ui128(1000000000027UL)) >> 1)); + UNIT_ASSERT(guint128_t(1000000000027UL) * guint128_t(1000000000027UL) == toGcc(ui128(1000000000027UL) * ui128(1000000000027UL))); + UNIT_ASSERT(guint128_t(1000000000027UL) + guint128_t(1000000000027UL) == toGcc(ui128(1000000000027UL) + ui128(1000000000027UL))); + UNIT_ASSERT(guint128_t(1000000000027UL) << 3 == toGcc(ui128(1000000000027UL) << 3)); + UNIT_ASSERT(guint128_t(1000000000027UL) >> 1 == toGcc(ui128(1000000000027UL) >> 1)); + UNIT_ASSERT((guint128_t(1000000000027UL) * guint128_t(1000000000027UL)) << 3 == toGcc((ui128(1000000000027UL) * ui128(1000000000027UL)) << 3)); + UNIT_ASSERT((guint128_t(1000000000027UL) + guint128_t(1000000000027UL)) >> 1 == toGcc((ui128(1000000000027UL) + ui128(1000000000027UL)) >> 1)); - UNIT_ASSERT((ui64)(guint128_t(1000000000027UL) * guint128_t(1000000000027UL)) == GetLow(ui128(1000000000027UL) * ui128(1000000000027UL))); + UNIT_ASSERT((ui64)(guint128_t(1000000000027UL) * guint128_t(1000000000027UL)) == GetLow(ui128(1000000000027UL) * ui128(1000000000027UL))); } } -#endif +#endif diff --git a/library/cpp/int128/ut/ui128_division_ut.cpp b/library/cpp/int128/ut/ui128_division_ut.cpp index 488738d429..4826a531e0 100644 --- a/library/cpp/int128/ut/ui128_division_ut.cpp +++ b/library/cpp/int128/ut/ui128_division_ut.cpp @@ -1,262 +1,262 @@ #include <library/cpp/testing/unittest/registar.h> - + #include <library/cpp/int128/int128.h> - -#include <util/generic/cast.h> - -Y_UNIT_TEST_SUITE(Ui128DivisionBy1Suite) { - Y_UNIT_TEST(Ui128Divide0By1) { - ui128 dividend = 0; - ui128 divider = 1; - ui128 expectedQuotient = 0; - ui128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(Ui128Divide1By1) { - ui128 dividend = 1; - ui128 divider = 1; - ui128 expectedQuotient = 1; - ui128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(Ui128Divide2By1) { - ui128 dividend = 2; - ui128 divider = 1; - ui128 expectedQuotient = 2; - ui128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(Ui128Divide42By1) { - ui128 dividend = 42; - ui128 divider = 1; - ui128 expectedQuotient = 42; - ui128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(Ui128DivideMaxUi64By1) { - ui128 dividend = std::numeric_limits<ui64>::max(); - ui128 divider = 1; - ui128 expectedQuotient = std::numeric_limits<ui64>::max(); - ui128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(Ui128DivideMaxUi64Plus1By1) { - ui128 dividend = ui128{std::numeric_limits<ui64>::max()} + ui128{1}; - ui128 divider = 1; - ui128 expectedQuotient = ui128{std::numeric_limits<ui64>::max()} + ui128{1}; - ui128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(Ui128DivideMaxUi64Plus42By1) { - ui128 dividend = ui128{std::numeric_limits<ui64>::max()} + ui128{42}; - ui128 divider = 1; - ui128 expectedQuotient = ui128{std::numeric_limits<ui64>::max()} + ui128{42}; - ui128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(Ui128DivideMaxUi128By1) { - ui128 dividend = std::numeric_limits<ui128>::max(); - ui128 divider = 1; - ui128 expectedQuotient = std::numeric_limits<ui128>::max(); - ui128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(Ui128DivideMaxUi128Minus1By1) { - ui128 dividend = std::numeric_limits<ui128>::max() - 1; - ui128 divider = 1; - ui128 expectedQuotient = std::numeric_limits<ui128>::max() - 1; - ui128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } -} - -Y_UNIT_TEST_SUITE(Ui128DivisionByEqualSuite) { - Y_UNIT_TEST(Ui128Divide1ByEqual) { - ui128 dividend = 1; - ui128 divider = dividend; - ui128 expectedQuotient = 1; - ui128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(Ui128Divide2ByEqual) { - ui128 dividend = 2; - ui128 divider = dividend; - ui128 expectedQuotient = 1; - ui128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(Ui128Divide42ByEqual) { - ui128 dividend = 42; - ui128 divider = dividend; - ui128 expectedQuotient = 1; - ui128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(Ui128DivideMaxUi64ByEqual) { - ui128 dividend = std::numeric_limits<ui64>::max(); - ui128 divider = dividend; - ui128 expectedQuotient = 1; - ui128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(Ui128DivideMaxUi64Plus1ByEqual) { - ui128 dividend = ui128{std::numeric_limits<ui64>::max()} + ui128{1}; - ui128 divider = dividend; - ui128 expectedQuotient = 1; - ui128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(Ui128DivideMaxUi64Plus42ByEqual) { - ui128 dividend = ui128{std::numeric_limits<ui64>::max()} + ui128{42}; - ui128 divider = dividend; - ui128 expectedQuotient = 1; - ui128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(Ui128DivideMaxUi128ByEqual) { - ui128 dividend = std::numeric_limits<ui128>::max(); - ui128 divider = dividend; - ui128 expectedQuotient = 1; - ui128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(Ui128DivideMaxUi128Minus1ByEqual) { - ui128 dividend = std::numeric_limits<ui128>::max() - 1; - ui128 divider = dividend; - ui128 expectedQuotient = 1; - ui128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } -} - -Y_UNIT_TEST_SUITE(Ui128DivisionLessByHigherSuite) { - Y_UNIT_TEST(Ui128Divide42By84) { - ui128 dividend = 42; - ui128 divider = 84; - ui128 expectedQuotient = 0; - ui128 expectedRemainder = 42; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(Ui128Divide42ByMaxUi64) { - ui128 dividend = 42; - ui128 divider = std::numeric_limits<ui64>::max(); - ui128 expectedQuotient = 0; - ui128 expectedRemainder = 42; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(Ui128Divide42ByMaxUi64Plus1) { - ui128 dividend = 42; - ui128 divider = ui128{std::numeric_limits<ui64>::max()} + ui128{1}; - ui128 expectedQuotient = 0; - ui128 expectedRemainder = 42; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(Ui128DivideMaxUi64ByMaxUi64Plus1) { - ui128 dividend = ui128{std::numeric_limits<ui64>::max()}; - ui128 divider = ui128{std::numeric_limits<ui64>::max()} + ui128{1}; - ui128 expectedQuotient = 0; - ui128 expectedRemainder = ui128{std::numeric_limits<ui64>::max()}; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } -} - -Y_UNIT_TEST_SUITE(Ui128DivisionBigByBigSuite) { - Y_UNIT_TEST(Ui128DivideBigByBig1) { - ui128 dividend = {64, 0}; - ui128 divider = {1, 0}; - ui128 expectedQuotient = 64; - ui128 expectedRemainder = 0; - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } - - Y_UNIT_TEST(Ui128DivideBigByBig2) { - ui128 dividend = {64, 0}; - ui128 divider = {12, 5}; - ui128 expectedQuotient = 5; - ui128 expectedRemainder = ui128{3, 18446744073709551591ull}; // plz don't ask - - UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); - UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); - } -} - -Y_UNIT_TEST_SUITE(Ui128DivisionAlgo) { - Y_UNIT_TEST(Ui128DivideAlgoCheck) { - /* - 49672666804009505000000 / 10000000 == 4967266680400950 - 49672666804009505000000 % 10000000 == 5000000 - */ - ui128 dividend = {2692ull, 14031757583392049728ull}; - ui64 divider = 10000000; - ui128 expectedQuotient = {0, 4967266680400950ull}; - ui128 expectedRemainder = {0, 5000000ull}; - - ui128 quotient = dividend / divider; - ui128 reminder = dividend % divider; - - UNIT_ASSERT_EQUAL(quotient, expectedQuotient); - UNIT_ASSERT_EQUAL(reminder, expectedRemainder); - } -} + +#include <util/generic/cast.h> + +Y_UNIT_TEST_SUITE(Ui128DivisionBy1Suite) { + Y_UNIT_TEST(Ui128Divide0By1) { + ui128 dividend = 0; + ui128 divider = 1; + ui128 expectedQuotient = 0; + ui128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(Ui128Divide1By1) { + ui128 dividend = 1; + ui128 divider = 1; + ui128 expectedQuotient = 1; + ui128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(Ui128Divide2By1) { + ui128 dividend = 2; + ui128 divider = 1; + ui128 expectedQuotient = 2; + ui128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(Ui128Divide42By1) { + ui128 dividend = 42; + ui128 divider = 1; + ui128 expectedQuotient = 42; + ui128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(Ui128DivideMaxUi64By1) { + ui128 dividend = std::numeric_limits<ui64>::max(); + ui128 divider = 1; + ui128 expectedQuotient = std::numeric_limits<ui64>::max(); + ui128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(Ui128DivideMaxUi64Plus1By1) { + ui128 dividend = ui128{std::numeric_limits<ui64>::max()} + ui128{1}; + ui128 divider = 1; + ui128 expectedQuotient = ui128{std::numeric_limits<ui64>::max()} + ui128{1}; + ui128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(Ui128DivideMaxUi64Plus42By1) { + ui128 dividend = ui128{std::numeric_limits<ui64>::max()} + ui128{42}; + ui128 divider = 1; + ui128 expectedQuotient = ui128{std::numeric_limits<ui64>::max()} + ui128{42}; + ui128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(Ui128DivideMaxUi128By1) { + ui128 dividend = std::numeric_limits<ui128>::max(); + ui128 divider = 1; + ui128 expectedQuotient = std::numeric_limits<ui128>::max(); + ui128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(Ui128DivideMaxUi128Minus1By1) { + ui128 dividend = std::numeric_limits<ui128>::max() - 1; + ui128 divider = 1; + ui128 expectedQuotient = std::numeric_limits<ui128>::max() - 1; + ui128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } +} + +Y_UNIT_TEST_SUITE(Ui128DivisionByEqualSuite) { + Y_UNIT_TEST(Ui128Divide1ByEqual) { + ui128 dividend = 1; + ui128 divider = dividend; + ui128 expectedQuotient = 1; + ui128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(Ui128Divide2ByEqual) { + ui128 dividend = 2; + ui128 divider = dividend; + ui128 expectedQuotient = 1; + ui128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(Ui128Divide42ByEqual) { + ui128 dividend = 42; + ui128 divider = dividend; + ui128 expectedQuotient = 1; + ui128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(Ui128DivideMaxUi64ByEqual) { + ui128 dividend = std::numeric_limits<ui64>::max(); + ui128 divider = dividend; + ui128 expectedQuotient = 1; + ui128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(Ui128DivideMaxUi64Plus1ByEqual) { + ui128 dividend = ui128{std::numeric_limits<ui64>::max()} + ui128{1}; + ui128 divider = dividend; + ui128 expectedQuotient = 1; + ui128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(Ui128DivideMaxUi64Plus42ByEqual) { + ui128 dividend = ui128{std::numeric_limits<ui64>::max()} + ui128{42}; + ui128 divider = dividend; + ui128 expectedQuotient = 1; + ui128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(Ui128DivideMaxUi128ByEqual) { + ui128 dividend = std::numeric_limits<ui128>::max(); + ui128 divider = dividend; + ui128 expectedQuotient = 1; + ui128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(Ui128DivideMaxUi128Minus1ByEqual) { + ui128 dividend = std::numeric_limits<ui128>::max() - 1; + ui128 divider = dividend; + ui128 expectedQuotient = 1; + ui128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } +} + +Y_UNIT_TEST_SUITE(Ui128DivisionLessByHigherSuite) { + Y_UNIT_TEST(Ui128Divide42By84) { + ui128 dividend = 42; + ui128 divider = 84; + ui128 expectedQuotient = 0; + ui128 expectedRemainder = 42; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(Ui128Divide42ByMaxUi64) { + ui128 dividend = 42; + ui128 divider = std::numeric_limits<ui64>::max(); + ui128 expectedQuotient = 0; + ui128 expectedRemainder = 42; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(Ui128Divide42ByMaxUi64Plus1) { + ui128 dividend = 42; + ui128 divider = ui128{std::numeric_limits<ui64>::max()} + ui128{1}; + ui128 expectedQuotient = 0; + ui128 expectedRemainder = 42; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(Ui128DivideMaxUi64ByMaxUi64Plus1) { + ui128 dividend = ui128{std::numeric_limits<ui64>::max()}; + ui128 divider = ui128{std::numeric_limits<ui64>::max()} + ui128{1}; + ui128 expectedQuotient = 0; + ui128 expectedRemainder = ui128{std::numeric_limits<ui64>::max()}; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } +} + +Y_UNIT_TEST_SUITE(Ui128DivisionBigByBigSuite) { + Y_UNIT_TEST(Ui128DivideBigByBig1) { + ui128 dividend = {64, 0}; + ui128 divider = {1, 0}; + ui128 expectedQuotient = 64; + ui128 expectedRemainder = 0; + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } + + Y_UNIT_TEST(Ui128DivideBigByBig2) { + ui128 dividend = {64, 0}; + ui128 divider = {12, 5}; + ui128 expectedQuotient = 5; + ui128 expectedRemainder = ui128{3, 18446744073709551591ull}; // plz don't ask + + UNIT_ASSERT_EQUAL(dividend / divider, expectedQuotient); + UNIT_ASSERT_EQUAL(dividend % divider, expectedRemainder); + } +} + +Y_UNIT_TEST_SUITE(Ui128DivisionAlgo) { + Y_UNIT_TEST(Ui128DivideAlgoCheck) { + /* + 49672666804009505000000 / 10000000 == 4967266680400950 + 49672666804009505000000 % 10000000 == 5000000 + */ + ui128 dividend = {2692ull, 14031757583392049728ull}; + ui64 divider = 10000000; + ui128 expectedQuotient = {0, 4967266680400950ull}; + ui128 expectedRemainder = {0, 5000000ull}; + + ui128 quotient = dividend / divider; + ui128 reminder = dividend % divider; + + UNIT_ASSERT_EQUAL(quotient, expectedQuotient); + UNIT_ASSERT_EQUAL(reminder, expectedRemainder); + } +} diff --git a/library/cpp/int128/ut/ya.make b/library/cpp/int128/ut/ya.make index 63211431bc..fd43531c5f 100644 --- a/library/cpp/int128/ut/ya.make +++ b/library/cpp/int128/ut/ya.make @@ -1,20 +1,20 @@ UNITTEST_FOR(library/cpp/int128) - -OWNER(vladon) + +OWNER(vladon) SRCS( - int128_ut_helpers.cpp - int128_ut_helpers.h - int128_ut.cpp - int128_typetraits_ut.cpp - int128_old_ut.cpp - int128_via_intrinsic_ut.cpp - i128_ut.cpp - i128_and_intrinsic_identity_ut.cpp - i128_comparison_ut.cpp - i128_division_ut.cpp - i128_type_traits_ut.cpp - ui128_division_ut.cpp + int128_ut_helpers.cpp + int128_ut_helpers.h + int128_ut.cpp + int128_typetraits_ut.cpp + int128_old_ut.cpp + int128_via_intrinsic_ut.cpp + i128_ut.cpp + i128_and_intrinsic_identity_ut.cpp + i128_comparison_ut.cpp + i128_division_ut.cpp + i128_type_traits_ut.cpp + ui128_division_ut.cpp ) END() diff --git a/library/cpp/int128/ya.make b/library/cpp/int128/ya.make index ae581746c7..95e453e6f1 100644 --- a/library/cpp/int128/ya.make +++ b/library/cpp/int128/ya.make @@ -1,13 +1,13 @@ LIBRARY() -OWNER( - vladon +OWNER( + vladon # g:zora -) +) SRCS( - int128.cpp - int128.h + int128.cpp + int128.h ) END() |