// Copyright 2017 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "absl/random/internal/fast_uniform_bits.h" #include #include "gtest/gtest.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace random_internal { namespace { template class FastUniformBitsTypedTest : public ::testing::Test {}; using IntTypes = ::testing::Types; TYPED_TEST_SUITE(FastUniformBitsTypedTest, IntTypes); TYPED_TEST(FastUniformBitsTypedTest, BasicTest) { using Limits = std::numeric_limits; using FastBits = FastUniformBits; EXPECT_EQ(0, FastBits::min()); EXPECT_EQ(Limits::max(), FastBits::max()); constexpr int kIters = 10000; std::random_device rd; std::mt19937 gen(rd()); FastBits fast; for (int i = 0; i < kIters; i++) { const auto v = fast(gen); EXPECT_LE(v, FastBits::max()); EXPECT_GE(v, FastBits::min()); } } template struct FakeUrbg { using result_type = UIntType; static constexpr result_type(max)() { return Hi; } static constexpr result_type(min)() { return Lo; } result_type operator()() { return Val; } }; using UrngOddbits = FakeUrbg; using Urng4bits = FakeUrbg; using Urng31bits = FakeUrbg; using Urng32bits = FakeUrbg; TEST(FastUniformBitsTest, IsPowerOfTwoOrZero) { EXPECT_TRUE(IsPowerOfTwoOrZero(uint8_t{0})); EXPECT_TRUE(IsPowerOfTwoOrZero(uint8_t{1})); EXPECT_TRUE(IsPowerOfTwoOrZero(uint8_t{2})); EXPECT_FALSE(IsPowerOfTwoOrZero(uint8_t{3})); EXPECT_TRUE(IsPowerOfTwoOrZero(uint8_t{16})); EXPECT_FALSE(IsPowerOfTwoOrZero(uint8_t{17})); EXPECT_FALSE(IsPowerOfTwoOrZero((std::numeric_limits::max)())); EXPECT_TRUE(IsPowerOfTwoOrZero(uint16_t{0})); EXPECT_TRUE(IsPowerOfTwoOrZero(uint16_t{1})); EXPECT_TRUE(IsPowerOfTwoOrZero(uint16_t{2})); EXPECT_FALSE(IsPowerOfTwoOrZero(uint16_t{3})); EXPECT_TRUE(IsPowerOfTwoOrZero(uint16_t{16})); EXPECT_FALSE(IsPowerOfTwoOrZero(uint16_t{17})); EXPECT_FALSE(IsPowerOfTwoOrZero((std::numeric_limits::max)())); EXPECT_TRUE(IsPowerOfTwoOrZero(uint32_t{0})); EXPECT_TRUE(IsPowerOfTwoOrZero(uint32_t{1})); EXPECT_TRUE(IsPowerOfTwoOrZero(uint32_t{2})); EXPECT_FALSE(IsPowerOfTwoOrZero(uint32_t{3})); EXPECT_TRUE(IsPowerOfTwoOrZero(uint32_t{32})); EXPECT_FALSE(IsPowerOfTwoOrZero(uint32_t{17})); EXPECT_FALSE(IsPowerOfTwoOrZero((std::numeric_limits::max)())); EXPECT_TRUE(IsPowerOfTwoOrZero(uint64_t{0})); EXPECT_TRUE(IsPowerOfTwoOrZero(uint64_t{1})); EXPECT_TRUE(IsPowerOfTwoOrZero(uint64_t{2})); EXPECT_FALSE(IsPowerOfTwoOrZero(uint64_t{3})); EXPECT_TRUE(IsPowerOfTwoOrZero(uint64_t{64})); EXPECT_FALSE(IsPowerOfTwoOrZero(uint64_t{17})); EXPECT_FALSE(IsPowerOfTwoOrZero((std::numeric_limits::max)())); } TEST(FastUniformBitsTest, IntegerLog2) { EXPECT_EQ(IntegerLog2(uint16_t{0}), 0); EXPECT_EQ(IntegerLog2(uint16_t{1}), 0); EXPECT_EQ(IntegerLog2(uint16_t{2}), 1); EXPECT_EQ(IntegerLog2(uint16_t{3}), 1); EXPECT_EQ(IntegerLog2(uint16_t{4}), 2); EXPECT_EQ(IntegerLog2(uint16_t{5}), 2); EXPECT_EQ(IntegerLog2(std::numeric_limits::max()), 63); } TEST(FastUniformBitsTest, RangeSize) { EXPECT_EQ((RangeSize>()), 4); EXPECT_EQ((RangeSize>()), 1); EXPECT_EQ((RangeSize>()), 4); EXPECT_EQ((RangeSize>()), 5); EXPECT_EQ((RangeSize>()), 9); EXPECT_EQ( (RangeSize::max()>>()), 0); EXPECT_EQ((RangeSize>()), 4); EXPECT_EQ((RangeSize>()), 1); EXPECT_EQ((RangeSize>()), 4); EXPECT_EQ((RangeSize>()), 5); EXPECT_EQ((RangeSize>()), 18); EXPECT_EQ((RangeSize< FakeUrbg::max()>>()), 0); EXPECT_EQ((RangeSize>()), 4); EXPECT_EQ((RangeSize>()), 1); EXPECT_EQ((RangeSize>()), 4); EXPECT_EQ((RangeSize>()), 5); EXPECT_EQ((RangeSize>()), 18); EXPECT_EQ((RangeSize>()), 0); EXPECT_EQ((RangeSize>()), 0xffffffff); EXPECT_EQ((RangeSize>()), 0xfffffffe); EXPECT_EQ((RangeSize>()), 0xfffffffd); EXPECT_EQ((RangeSize< FakeUrbg::max()>>()), 0); EXPECT_EQ((RangeSize>()), 4); EXPECT_EQ((RangeSize>()), 1); EXPECT_EQ((RangeSize>()), 4); EXPECT_EQ((RangeSize>()), 5); EXPECT_EQ((RangeSize>()), 18); EXPECT_EQ((RangeSize>()), 0x100000000ull); EXPECT_EQ((RangeSize>()), 0xffffffffull); EXPECT_EQ((RangeSize>()), 0xfffffffeull); EXPECT_EQ((RangeSize>()), 0xfffffffdull); EXPECT_EQ((RangeSize>()), 0ull); EXPECT_EQ((RangeSize>()), 0xffffffffffffffffull); EXPECT_EQ((RangeSize>()), 0xfffffffffffffffeull); EXPECT_EQ((RangeSize>()), 0xfffffffffffffffdull); EXPECT_EQ((RangeSize< FakeUrbg::max()>>()), 0); } TEST(FastUniformBitsTest, PowerOfTwoSubRangeSize) { EXPECT_EQ((PowerOfTwoSubRangeSize>()), 4); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 1); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 4); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 4); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 8); EXPECT_EQ((PowerOfTwoSubRangeSize< FakeUrbg::max()>>()), 0); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 4); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 1); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 4); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 4); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 16); EXPECT_EQ((PowerOfTwoSubRangeSize< FakeUrbg::max()>>()), 0); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 4); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 1); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 4); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 4); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 16); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 0); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 0x80000000); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 0x80000000); EXPECT_EQ((PowerOfTwoSubRangeSize< FakeUrbg::max()>>()), 0); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 4); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 1); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 4); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 4); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 16); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 0x100000000ull); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 0x80000000ull); EXPECT_EQ((PowerOfTwoSubRangeSize>()), 0x80000000ull); EXPECT_EQ( (PowerOfTwoSubRangeSize>()), 0); EXPECT_EQ( (PowerOfTwoSubRangeSize>()), 0x8000000000000000ull); EXPECT_EQ( (PowerOfTwoSubRangeSize>()), 0x8000000000000000ull); EXPECT_EQ((PowerOfTwoSubRangeSize< FakeUrbg::max()>>()), 0); } TEST(FastUniformBitsTest, Urng4_VariousOutputs) { // Tests that how values are composed; the single-bit deltas should be spread // across each invocation. Urng4bits urng4; Urng31bits urng31; Urng32bits urng32; // 8-bit types { FastUniformBits fast8; EXPECT_EQ(0x11, fast8(urng4)); EXPECT_EQ(0x2, fast8(urng31)); EXPECT_EQ(0x1, fast8(urng32)); } // 16-bit types { FastUniformBits fast16; EXPECT_EQ(0x1111, fast16(urng4)); EXPECT_EQ(0xf02, fast16(urng31)); EXPECT_EQ(0xf01, fast16(urng32)); } // 32-bit types { FastUniformBits fast32; EXPECT_EQ(0x11111111, fast32(urng4)); EXPECT_EQ(0x0f020f02, fast32(urng31)); EXPECT_EQ(0x74010f01, fast32(urng32)); } // 64-bit types { FastUniformBits fast64; EXPECT_EQ(0x1111111111111111, fast64(urng4)); EXPECT_EQ(0x387811c3c0870f02, fast64(urng31)); EXPECT_EQ(0x74010f0174010f01, fast64(urng32)); } } TEST(FastUniformBitsTest, URBG32bitRegression) { // Validate with deterministic 32-bit std::minstd_rand // to ensure that operator() performs as expected. std::minstd_rand gen(1); FastUniformBits fast64; EXPECT_EQ(0x05e47095f847c122ull, fast64(gen)); EXPECT_EQ(0x8f82c1ba30b64d22ull, fast64(gen)); EXPECT_EQ(0x3b971a3558155039ull, fast64(gen)); } } // namespace } // namespace random_internal ABSL_NAMESPACE_END } // namespace absl