diff options
Diffstat (limited to 'absl/numeric')
-rw-r--r-- | absl/numeric/BUILD.bazel | 1 | ||||
-rw-r--r-- | absl/numeric/CMakeLists.txt | 1 | ||||
-rw-r--r-- | absl/numeric/bits_benchmark.cc | 40 | ||||
-rw-r--r-- | absl/numeric/int128.cc | 16 | ||||
-rw-r--r-- | absl/numeric/int128.h | 58 | ||||
-rw-r--r-- | absl/numeric/int128_no_intrinsic.inc | 77 | ||||
-rw-r--r-- | absl/numeric/int128_stream_test.cc | 50 | ||||
-rw-r--r-- | absl/numeric/int128_test.cc | 28 |
8 files changed, 144 insertions, 127 deletions
diff --git a/absl/numeric/BUILD.bazel b/absl/numeric/BUILD.bazel index eaa27dfd..ec0b8701 100644 --- a/absl/numeric/BUILD.bazel +++ b/absl/numeric/BUILD.bazel @@ -95,7 +95,6 @@ cc_test( deps = [ ":int128", "//absl/base", - "//absl/base:core_headers", "//absl/hash:hash_testing", "//absl/meta:type_traits", "@com_google_googletest//:gtest_main", diff --git a/absl/numeric/CMakeLists.txt b/absl/numeric/CMakeLists.txt index 26df5cf7..384c0fc0 100644 --- a/absl/numeric/CMakeLists.txt +++ b/absl/numeric/CMakeLists.txt @@ -70,7 +70,6 @@ absl_cc_test( DEPS absl::int128 absl::base - absl::core_headers absl::hash_testing absl::type_traits GTest::gmock_main diff --git a/absl/numeric/bits_benchmark.cc b/absl/numeric/bits_benchmark.cc index b9759583..2c89afdb 100644 --- a/absl/numeric/bits_benchmark.cc +++ b/absl/numeric/bits_benchmark.cc @@ -24,50 +24,50 @@ namespace absl { namespace { template <typename T> -static void BM_bitwidth(benchmark::State& state) { - const int count = state.range(0); +static void BM_bit_width(benchmark::State& state) { + const auto count = static_cast<size_t>(state.range(0)); absl::BitGen rng; std::vector<T> values; values.reserve(count); - for (int i = 0; i < count; ++i) { + for (size_t i = 0; i < count; ++i) { values.push_back(absl::Uniform<T>(rng, 0, std::numeric_limits<T>::max())); } - while (state.KeepRunningBatch(count)) { - for (int i = 0; i < count; ++i) { - benchmark::DoNotOptimize(values[i]); + while (state.KeepRunningBatch(static_cast<int64_t>(count))) { + for (size_t i = 0; i < count; ++i) { + benchmark::DoNotOptimize(absl::bit_width(values[i])); } } } -BENCHMARK_TEMPLATE(BM_bitwidth, uint8_t)->Range(1, 1 << 20); -BENCHMARK_TEMPLATE(BM_bitwidth, uint16_t)->Range(1, 1 << 20); -BENCHMARK_TEMPLATE(BM_bitwidth, uint32_t)->Range(1, 1 << 20); -BENCHMARK_TEMPLATE(BM_bitwidth, uint64_t)->Range(1, 1 << 20); +BENCHMARK_TEMPLATE(BM_bit_width, uint8_t)->Range(1, 1 << 20); +BENCHMARK_TEMPLATE(BM_bit_width, uint16_t)->Range(1, 1 << 20); +BENCHMARK_TEMPLATE(BM_bit_width, uint32_t)->Range(1, 1 << 20); +BENCHMARK_TEMPLATE(BM_bit_width, uint64_t)->Range(1, 1 << 20); template <typename T> -static void BM_bitwidth_nonzero(benchmark::State& state) { - const int count = state.range(0); +static void BM_bit_width_nonzero(benchmark::State& state) { + const auto count = static_cast<size_t>(state.range(0)); absl::BitGen rng; std::vector<T> values; values.reserve(count); - for (int i = 0; i < count; ++i) { + for (size_t i = 0; i < count; ++i) { values.push_back(absl::Uniform<T>(rng, 1, std::numeric_limits<T>::max())); } - while (state.KeepRunningBatch(count)) { - for (int i = 0; i < count; ++i) { + while (state.KeepRunningBatch(static_cast<int64_t>(count))) { + for (size_t i = 0; i < count; ++i) { const T value = values[i]; ABSL_ASSUME(value > 0); - benchmark::DoNotOptimize(value); + benchmark::DoNotOptimize(absl::bit_width(value)); } } } -BENCHMARK_TEMPLATE(BM_bitwidth_nonzero, uint8_t)->Range(1, 1 << 20); -BENCHMARK_TEMPLATE(BM_bitwidth_nonzero, uint16_t)->Range(1, 1 << 20); -BENCHMARK_TEMPLATE(BM_bitwidth_nonzero, uint32_t)->Range(1, 1 << 20); -BENCHMARK_TEMPLATE(BM_bitwidth_nonzero, uint64_t)->Range(1, 1 << 20); +BENCHMARK_TEMPLATE(BM_bit_width_nonzero, uint8_t)->Range(1, 1 << 20); +BENCHMARK_TEMPLATE(BM_bit_width_nonzero, uint16_t)->Range(1, 1 << 20); +BENCHMARK_TEMPLATE(BM_bit_width_nonzero, uint32_t)->Range(1, 1 << 20); +BENCHMARK_TEMPLATE(BM_bit_width_nonzero, uint64_t)->Range(1, 1 << 20); } // namespace } // namespace absl diff --git a/absl/numeric/int128.cc b/absl/numeric/int128.cc index e5526c6f..6ffe43d5 100644 --- a/absl/numeric/int128.cc +++ b/absl/numeric/int128.cc @@ -111,7 +111,7 @@ uint128 MakeUint128FromFloat(T v) { return MakeUint128(0, static_cast<uint64_t>(v)); } -#if defined(__clang__) && !defined(__SSE3__) +#if defined(__clang__) && (__clang_major__ < 9) && !defined(__SSE3__) // Workaround for clang bug: https://bugs.llvm.org/show_bug.cgi?id=38289 // Casting from long double to uint64_t is miscompiled and drops bits. // It is more work, so only use when we need the workaround. @@ -131,7 +131,7 @@ uint128 MakeUint128FromFloat(long double v) { return (static_cast<uint128>(w0) << 100) | (static_cast<uint128>(w1) << 50) | static_cast<uint128>(w2); } -#endif // __clang__ && !__SSE3__ +#endif // __clang__ && (__clang_major__ < 9) && !__SSE3__ } // namespace uint128::uint128(float v) : uint128(MakeUint128FromFloat(v)) {} @@ -216,9 +216,9 @@ std::ostream& operator<<(std::ostream& os, uint128 v) { } else if (adjustfield == std::ios::internal && (flags & std::ios::showbase) && (flags & std::ios::basefield) == std::ios::hex && v != 0) { - rep.insert(2, count, os.fill()); + rep.insert(size_t{2}, count, os.fill()); } else { - rep.insert(0, count, os.fill()); + rep.insert(size_t{0}, count, os.fill()); } } @@ -314,16 +314,16 @@ std::ostream& operator<<(std::ostream& os, int128 v) { break; case std::ios::internal: if (print_as_decimal && (rep[0] == '+' || rep[0] == '-')) { - rep.insert(1, count, os.fill()); + rep.insert(size_t{1}, count, os.fill()); } else if ((flags & std::ios::basefield) == std::ios::hex && (flags & std::ios::showbase) && v != 0) { - rep.insert(2, count, os.fill()); + rep.insert(size_t{2}, count, os.fill()); } else { - rep.insert(0, count, os.fill()); + rep.insert(size_t{0}, count, os.fill()); } break; default: // std::ios::right - rep.insert(0, count, os.fill()); + rep.insert(size_t{0}, count, os.fill()); break; } } diff --git a/absl/numeric/int128.h b/absl/numeric/int128.h index 7a899eec..aa0f86f7 100644 --- a/absl/numeric/int128.h +++ b/absl/numeric/int128.h @@ -119,8 +119,8 @@ class #ifdef ABSL_HAVE_INTRINSIC_INT128 constexpr uint128(__int128 v); // NOLINT(runtime/explicit) constexpr uint128(unsigned __int128 v); // NOLINT(runtime/explicit) -#endif // ABSL_HAVE_INTRINSIC_INT128 - constexpr uint128(int128 v); // NOLINT(runtime/explicit) +#endif // ABSL_HAVE_INTRINSIC_INT128 + constexpr uint128(int128 v); // NOLINT(runtime/explicit) explicit uint128(float v); explicit uint128(double v); explicit uint128(long double v); @@ -286,9 +286,9 @@ class numeric_limits<absl::uint128> { #endif // ABSL_HAVE_INTRINSIC_INT128 static constexpr bool tinyness_before = false; - static constexpr absl::uint128 (min)() { return 0; } + static constexpr absl::uint128(min)() { return 0; } static constexpr absl::uint128 lowest() { return 0; } - static constexpr absl::uint128 (max)() { return absl::Uint128Max(); } + static constexpr absl::uint128(max)() { return absl::Uint128Max(); } static constexpr absl::uint128 epsilon() { return 0; } static constexpr absl::uint128 round_error() { return 0; } static constexpr absl::uint128 infinity() { return 0; } @@ -521,9 +521,9 @@ class numeric_limits<absl::int128> { #endif // ABSL_HAVE_INTRINSIC_INT128 static constexpr bool tinyness_before = false; - static constexpr absl::int128 (min)() { return absl::Int128Min(); } + static constexpr absl::int128(min)() { return absl::Int128Min(); } static constexpr absl::int128 lowest() { return absl::Int128Min(); } - static constexpr absl::int128 (max)() { return absl::Int128Max(); } + static constexpr absl::int128(max)() { return absl::Int128Max(); } static constexpr absl::int128 epsilon() { return 0; } static constexpr absl::int128 round_error() { return 0; } static constexpr absl::int128 infinity() { return 0; } @@ -561,9 +561,7 @@ inline uint128& uint128::operator=(unsigned long v) { } // NOLINTNEXTLINE(runtime/int) -inline uint128& uint128::operator=(long long v) { - return *this = uint128(v); -} +inline uint128& uint128::operator=(long long v) { return *this = uint128(v); } // NOLINTNEXTLINE(runtime/int) inline uint128& uint128::operator=(unsigned long long v) { @@ -571,18 +569,14 @@ inline uint128& uint128::operator=(unsigned long long v) { } #ifdef ABSL_HAVE_INTRINSIC_INT128 -inline uint128& uint128::operator=(__int128 v) { - return *this = uint128(v); -} +inline uint128& uint128::operator=(__int128 v) { return *this = uint128(v); } inline uint128& uint128::operator=(unsigned __int128 v) { return *this = uint128(v); } #endif // ABSL_HAVE_INTRINSIC_INT128 -inline uint128& uint128::operator=(int128 v) { - return *this = uint128(v); -} +inline uint128& uint128::operator=(int128 v) { return *this = uint128(v); } // Arithmetic operators. @@ -637,8 +631,7 @@ constexpr uint64_t Uint128High64(uint128 v) { return v.hi_; } #if defined(ABSL_IS_LITTLE_ENDIAN) -constexpr uint128::uint128(uint64_t high, uint64_t low) - : lo_{low}, hi_{high} {} +constexpr uint128::uint128(uint64_t high, uint64_t low) : lo_{low}, hi_{high} {} constexpr uint128::uint128(int v) : lo_{static_cast<uint64_t>(v)}, @@ -670,8 +663,7 @@ constexpr uint128::uint128(int128 v) #elif defined(ABSL_IS_BIG_ENDIAN) -constexpr uint128::uint128(uint64_t high, uint64_t low) - : hi_{high}, lo_{low} {} +constexpr uint128::uint128(uint64_t high, uint64_t low) : hi_{high}, lo_{low} {} constexpr uint128::uint128(int v) : hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0}, @@ -817,13 +809,9 @@ constexpr bool operator>=(uint128 lhs, uint128 rhs) { return !(lhs < rhs); } // Unary operators. -constexpr inline uint128 operator+(uint128 val) { - return val; -} +constexpr inline uint128 operator+(uint128 val) { return val; } -constexpr inline int128 operator+(int128 val) { - return val; -} +constexpr inline int128 operator+(int128 val) { return val; } constexpr uint128 operator-(uint128 val) { #if defined(ABSL_HAVE_INTRINSIC_INT128) @@ -906,7 +894,7 @@ constexpr uint128 operator<<(uint128 lhs, int amount) { #else // uint64_t shifts of >= 64 are undefined, so we will need some // special-casing. - return amount >= 64 ? MakeUint128(Uint128Low64(lhs) << (amount - 64), 0) + return amount >= 64 ? MakeUint128(Uint128Low64(lhs) << (amount - 64), 0) : amount == 0 ? lhs : MakeUint128((Uint128High64(lhs) << amount) | (Uint128Low64(lhs) >> (64 - amount)), @@ -920,7 +908,7 @@ constexpr uint128 operator>>(uint128 lhs, int amount) { #else // uint64_t shifts of >= 64 are undefined, so we will need some // special-casing. - return amount >= 64 ? MakeUint128(0, Uint128High64(lhs) >> (amount - 64)) + return amount >= 64 ? MakeUint128(0, Uint128High64(lhs) >> (amount - 64)) : amount == 0 ? lhs : MakeUint128(Uint128High64(lhs) >> amount, (Uint128Low64(lhs) >> amount) | @@ -1042,27 +1030,19 @@ constexpr int128 MakeInt128(int64_t high, uint64_t low) { } // Assignment from integer types. -inline int128& int128::operator=(int v) { - return *this = int128(v); -} +inline int128& int128::operator=(int v) { return *this = int128(v); } -inline int128& int128::operator=(unsigned int v) { - return *this = int128(v); -} +inline int128& int128::operator=(unsigned int v) { return *this = int128(v); } inline int128& int128::operator=(long v) { // NOLINT(runtime/int) return *this = int128(v); } // NOLINTNEXTLINE(runtime/int) -inline int128& int128::operator=(unsigned long v) { - return *this = int128(v); -} +inline int128& int128::operator=(unsigned long v) { return *this = int128(v); } // NOLINTNEXTLINE(runtime/int) -inline int128& int128::operator=(long long v) { - return *this = int128(v); -} +inline int128& int128::operator=(long long v) { return *this = int128(v); } // NOLINTNEXTLINE(runtime/int) inline int128& int128::operator=(unsigned long long v) { diff --git a/absl/numeric/int128_no_intrinsic.inc b/absl/numeric/int128_no_intrinsic.inc index 8834804c..6f5d8377 100644 --- a/absl/numeric/int128_no_intrinsic.inc +++ b/absl/numeric/int128_no_intrinsic.inc @@ -23,8 +23,7 @@ constexpr int64_t Int128High64(int128 v) { return v.hi_; } #if defined(ABSL_IS_LITTLE_ENDIAN) -constexpr int128::int128(int64_t high, uint64_t low) : - lo_(low), hi_(high) {} +constexpr int128::int128(int64_t high, uint64_t low) : lo_(low), hi_(high) {} constexpr int128::int128(int v) : lo_{static_cast<uint64_t>(v)}, hi_{v < 0 ? ~int64_t{0} : 0} {} @@ -44,8 +43,7 @@ constexpr int128::int128(uint128 v) #elif defined(ABSL_IS_BIG_ENDIAN) -constexpr int128::int128(int64_t high, uint64_t low) : - hi_{high}, lo_{low} {} +constexpr int128::int128(int64_t high, uint64_t low) : hi_{high}, lo_{low} {} constexpr int128::int128(int v) : hi_{v < 0 ? ~int64_t{0} : 0}, lo_{static_cast<uint64_t>(v)} {} @@ -279,33 +277,52 @@ constexpr int128 operator^(int128 lhs, int128 rhs) { } constexpr int128 operator<<(int128 lhs, int amount) { - // int64_t shifts of >= 64 are undefined, so we need some special-casing. - return amount >= 64 - ? MakeInt128( - static_cast<int64_t>(Int128Low64(lhs) << (amount - 64)), 0) - : amount == 0 - ? lhs - : MakeInt128( - (Int128High64(lhs) << amount) | - static_cast<int64_t>(Int128Low64(lhs) >> (64 - amount)), - Int128Low64(lhs) << amount); + // int64_t shifts of >= 63 are undefined, so we need some special-casing. + assert(amount >= 0 && amount < 127); + if (amount <= 0) { + return lhs; + } else if (amount < 63) { + return MakeInt128( + (Int128High64(lhs) << amount) | + static_cast<int64_t>(Int128Low64(lhs) >> (64 - amount)), + Int128Low64(lhs) << amount); + } else if (amount == 63) { + return MakeInt128(((Int128High64(lhs) << 32) << 31) | + static_cast<int64_t>(Int128Low64(lhs) >> 1), + (Int128Low64(lhs) << 32) << 31); + } else if (amount == 127) { + return MakeInt128(static_cast<int64_t>(Int128Low64(lhs) << 63), 0); + } else if (amount > 127) { + return MakeInt128(0, 0); + } else { + // amount >= 64 && amount < 127 + return MakeInt128(static_cast<int64_t>(Int128Low64(lhs) << (amount - 64)), + 0); + } } constexpr int128 operator>>(int128 lhs, int amount) { - // int64_t shifts of >= 64 are undefined, so we need some special-casing. - // The (Int128High64(lhs) >> 32) >> 32 "trick" causes the the most significant - // int64 to be inititialized with all zeros or all ones correctly. It takes - // into account whether the number is negative or positive, and whether the - // current architecture does arithmetic or logical right shifts for negative - // numbers. - return amount >= 64 - ? MakeInt128( - (Int128High64(lhs) >> 32) >> 32, - static_cast<uint64_t>(Int128High64(lhs) >> (amount - 64))) - : amount == 0 - ? lhs - : MakeInt128(Int128High64(lhs) >> amount, - (Int128Low64(lhs) >> amount) | - (static_cast<uint64_t>(Int128High64(lhs)) - << (64 - amount))); + // int64_t shifts of >= 63 are undefined, so we need some special-casing. + assert(amount >= 0 && amount < 127); + if (amount <= 0) { + return lhs; + } else if (amount < 63) { + return MakeInt128( + Int128High64(lhs) >> amount, + Int128Low64(lhs) >> amount | static_cast<uint64_t>(Int128High64(lhs)) + << (64 - amount)); + } else if (amount == 63) { + return MakeInt128((Int128High64(lhs) >> 32) >> 31, + static_cast<uint64_t>(Int128High64(lhs) << 1) | + (Int128Low64(lhs) >> 32) >> 31); + + } else if (amount >= 127) { + return MakeInt128((Int128High64(lhs) >> 32) >> 31, + static_cast<uint64_t>((Int128High64(lhs) >> 32) >> 31)); + } else { + // amount >= 64 && amount < 127 + return MakeInt128( + (Int128High64(lhs) >> 32) >> 31, + static_cast<uint64_t>(Int128High64(lhs) >> (amount - 64))); + } } diff --git a/absl/numeric/int128_stream_test.cc b/absl/numeric/int128_stream_test.cc index 479ad66c..81d2adee 100644 --- a/absl/numeric/int128_stream_test.cc +++ b/absl/numeric/int128_stream_test.cc @@ -76,16 +76,6 @@ std::string StreamFormatToString(std::ios_base::fmtflags flags, return msg.str(); } -void CheckUint128Case(const Uint128TestCase& test_case) { - std::ostringstream os; - os.flags(test_case.flags); - os.width(test_case.width); - os.fill(kFill); - os << test_case.value; - SCOPED_TRACE(StreamFormatToString(test_case.flags, test_case.width)); - EXPECT_EQ(test_case.expected, os.str()); -} - constexpr std::ios::fmtflags kDec = std::ios::dec; constexpr std::ios::fmtflags kOct = std::ios::oct; constexpr std::ios::fmtflags kHex = std::ios::hex; @@ -96,6 +86,16 @@ constexpr std::ios::fmtflags kUpper = std::ios::uppercase; constexpr std::ios::fmtflags kBase = std::ios::showbase; constexpr std::ios::fmtflags kPos = std::ios::showpos; +void CheckUint128Case(const Uint128TestCase& test_case) { + std::ostringstream os; + os.flags(test_case.flags); + os.width(test_case.width); + os.fill(kFill); + os << test_case.value; + SCOPED_TRACE(StreamFormatToString(test_case.flags, test_case.width)); + EXPECT_EQ(os.str(), test_case.expected); +} + TEST(Uint128, OStreamValueTest) { CheckUint128Case({1, kDec, /*width = */ 0, "1"}); CheckUint128Case({1, kOct, /*width = */ 0, "1"}); @@ -161,7 +161,7 @@ void CheckInt128Case(const Int128TestCase& test_case) { os.fill(kFill); os << test_case.value; SCOPED_TRACE(StreamFormatToString(test_case.flags, test_case.width)); - EXPECT_EQ(test_case.expected, os.str()); + EXPECT_EQ(os.str(), test_case.expected); } TEST(Int128, OStreamValueTest) { @@ -194,35 +194,33 @@ TEST(Int128, OStreamValueTest) { {absl::MakeInt128(1, 0), kHex, /*width = */ 0, "10000000000000000"}); CheckInt128Case({absl::MakeInt128(std::numeric_limits<int64_t>::max(), std::numeric_limits<uint64_t>::max()), - std::ios::dec, /*width = */ 0, + kDec, /*width = */ 0, "170141183460469231731687303715884105727"}); CheckInt128Case({absl::MakeInt128(std::numeric_limits<int64_t>::max(), std::numeric_limits<uint64_t>::max()), - std::ios::oct, /*width = */ 0, + kOct, /*width = */ 0, "1777777777777777777777777777777777777777777"}); CheckInt128Case({absl::MakeInt128(std::numeric_limits<int64_t>::max(), std::numeric_limits<uint64_t>::max()), - std::ios::hex, /*width = */ 0, - "7fffffffffffffffffffffffffffffff"}); + kHex, /*width = */ 0, "7fffffffffffffffffffffffffffffff"}); CheckInt128Case({absl::MakeInt128(std::numeric_limits<int64_t>::min(), 0), - std::ios::dec, /*width = */ 0, + kDec, /*width = */ 0, "-170141183460469231731687303715884105728"}); CheckInt128Case({absl::MakeInt128(std::numeric_limits<int64_t>::min(), 0), - std::ios::oct, /*width = */ 0, + kOct, /*width = */ 0, "2000000000000000000000000000000000000000000"}); CheckInt128Case({absl::MakeInt128(std::numeric_limits<int64_t>::min(), 0), - std::ios::hex, /*width = */ 0, - "80000000000000000000000000000000"}); - CheckInt128Case({-1, std::ios::dec, /*width = */ 0, "-1"}); - CheckInt128Case({-1, std::ios::oct, /*width = */ 0, + kHex, /*width = */ 0, "80000000000000000000000000000000"}); + CheckInt128Case({-1, kDec, /*width = */ 0, "-1"}); + CheckInt128Case({-1, kOct, /*width = */ 0, "3777777777777777777777777777777777777777777"}); CheckInt128Case( - {-1, std::ios::hex, /*width = */ 0, "ffffffffffffffffffffffffffffffff"}); - CheckInt128Case({-12345, std::ios::dec, /*width = */ 0, "-12345"}); - CheckInt128Case({-12345, std::ios::oct, /*width = */ 0, + {-1, kHex, /*width = */ 0, "ffffffffffffffffffffffffffffffff"}); + CheckInt128Case({-12345, kDec, /*width = */ 0, "-12345"}); + CheckInt128Case({-12345, kOct, /*width = */ 0, "3777777777777777777777777777777777777747707"}); - CheckInt128Case({-12345, std::ios::hex, /*width = */ 0, - "ffffffffffffffffffffffffffffcfc7"}); + CheckInt128Case( + {-12345, kHex, /*width = */ 0, "ffffffffffffffffffffffffffffcfc7"}); } std::vector<Int128TestCase> GetInt128FormatCases(); diff --git a/absl/numeric/int128_test.cc b/absl/numeric/int128_test.cc index dd9425d7..01e3eb5c 100644 --- a/absl/numeric/int128_test.cc +++ b/absl/numeric/int128_test.cc @@ -32,6 +32,8 @@ #pragma warning(disable:4146) #endif +#define MAKE_INT128(HI, LO) absl::MakeInt128(static_cast<int64_t>(HI), LO) + namespace { template <typename T> @@ -283,8 +285,9 @@ TEST(Uint128, ConversionTests) { EXPECT_EQ(from_precise_double, from_precise_ints); EXPECT_DOUBLE_EQ(static_cast<double>(from_precise_ints), precise_double); - double approx_double = 0xffffeeeeddddcccc * std::pow(2.0, 64.0) + - 0xbbbbaaaa99998888; + double approx_double = + static_cast<double>(0xffffeeeeddddcccc) * std::pow(2.0, 64.0) + + static_cast<double>(0xbbbbaaaa99998888); absl::uint128 from_approx_double(approx_double); EXPECT_DOUBLE_EQ(static_cast<double>(from_approx_double), approx_double); @@ -1245,6 +1248,27 @@ TEST(Int128, BitwiseShiftTest) { absl::MakeInt128(uint64_t{1} << j, 0) >>= (j - i)); } } + + // Manually calculated cases with shift count for positive (val1) and negative + // (val2) values + absl::int128 val1 = MAKE_INT128(0x123456789abcdef0, 0x123456789abcdef0); + absl::int128 val2 = MAKE_INT128(0xfedcba0987654321, 0xfedcba0987654321); + + EXPECT_EQ(val1 << 63, MAKE_INT128(0x91a2b3c4d5e6f78, 0x0)); + EXPECT_EQ(val1 << 64, MAKE_INT128(0x123456789abcdef0, 0x0)); + EXPECT_EQ(val2 << 63, MAKE_INT128(0xff6e5d04c3b2a190, 0x8000000000000000)); + EXPECT_EQ(val2 << 64, MAKE_INT128(0xfedcba0987654321, 0x0)); + + EXPECT_EQ(val1 << 126, MAKE_INT128(0x0, 0x0)); + EXPECT_EQ(val2 << 126, MAKE_INT128(0x4000000000000000, 0x0)); + + EXPECT_EQ(val1 >> 63, MAKE_INT128(0x0, 0x2468acf13579bde0)); + EXPECT_EQ(val1 >> 64, MAKE_INT128(0x0, 0x123456789abcdef0)); + EXPECT_EQ(val2 >> 63, MAKE_INT128(0xffffffffffffffff, 0xfdb974130eca8643)); + EXPECT_EQ(val2 >> 64, MAKE_INT128(0xffffffffffffffff, 0xfedcba0987654321)); + + EXPECT_EQ(val1 >> 126, MAKE_INT128(0x0, 0x0)); + EXPECT_EQ(val2 >> 126, MAKE_INT128(0xffffffffffffffff, 0xffffffffffffffff)); } TEST(Int128, NumericLimitsTest) { |