// 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/randen_engine.h" #include #include #include #include #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/base/internal/raw_logging.h" #include "absl/random/internal/explicit_seed_seq.h" #include "absl/strings/str_cat.h" #include "absl/time/clock.h" #define UPDATE_GOLDEN 0 using randen_u64 = absl::random_internal::randen_engine; using randen_u32 = absl::random_internal::randen_engine; using absl::random_internal::ExplicitSeedSeq; namespace { template class RandenEngineTypedTest : public ::testing::Test {}; using UIntTypes = ::testing::Types; TYPED_TEST_SUITE(RandenEngineTypedTest, UIntTypes); TYPED_TEST(RandenEngineTypedTest, VerifyReseedChangesAllValues) { using randen = typename absl::random_internal::randen_engine; using result_type = typename randen::result_type; const size_t kNumOutputs = (sizeof(randen) * 2 / sizeof(TypeParam)) + 1; randen engine; // MSVC emits error 2719 without the use of std::ref below. // * formal parameter with __declspec(align('#')) won't be aligned { std::seed_seq seq1{1, 2, 3, 4, 5, 6, 7}; engine.seed(seq1); } result_type a[kNumOutputs]; std::generate(std::begin(a), std::end(a), std::ref(engine)); { std::random_device rd; std::seed_seq seq2{rd(), rd(), rd()}; engine.seed(seq2); } result_type b[kNumOutputs]; std::generate(std::begin(b), std::end(b), std::ref(engine)); // Test that generated sequence changed as sequence of bits, i.e. if about // half of the bites were flipped between two non-correlated values. size_t changed_bits = 0; size_t unchanged_bits = 0; size_t total_set = 0; size_t total_bits = 0; size_t equal_count = 0; for (size_t i = 0; i < kNumOutputs; ++i) { equal_count += (a[i] == b[i]) ? 1 : 0; std::bitset bitset(a[i] ^ b[i]); changed_bits += bitset.count(); unchanged_bits += bitset.size() - bitset.count(); std::bitset a_set(a[i]); std::bitset b_set(b[i]); total_set += a_set.count() + b_set.count(); total_bits += 2 * 8 * sizeof(result_type); } // On average, half the bits are changed between two calls. EXPECT_LE(changed_bits, 0.60 * (changed_bits + unchanged_bits)); EXPECT_GE(changed_bits, 0.40 * (changed_bits + unchanged_bits)); // Verify using a quick normal-approximation to the binomial. EXPECT_NEAR(total_set, total_bits * 0.5, 4 * std::sqrt(total_bits)) << "@" << total_set / static_cast(total_bits); // Also, A[i] == B[i] with probability (1/range) * N. // Give this a pretty wide latitude, though. const double kExpected = kNumOutputs / (1.0 * sizeof(result_type) * 8); EXPECT_LE(equal_count, 1.0 + kExpected); } // Number of values that needs to be consumed to clean two sizes of buffer // and trigger third refresh. (slightly overestimates the actual state size). constexpr size_t kTwoBufferValues = sizeof(randen_u64) / sizeof(uint16_t) + 1; TYPED_TEST(RandenEngineTypedTest, VerifyDiscard) { using randen = typename absl::random_internal::randen_engine; for (size_t num_used = 0; num_used < kTwoBufferValues; ++num_used) { randen engine_used; for (size_t i = 0; i < num_used; ++i) { engine_used(); } for (size_t num_discard = 0; num_discard < kTwoBufferValues; ++num_discard) { randen engine1 = engine_used; randen engine2 = engine_used; for (size_t i = 0; i < num_discard; ++i) { engine1(); } engine2.discard(num_discard); for (size_t i = 0; i < kTwoBufferValues; ++i) { const auto r1 = engine1(); const auto r2 = engine2(); ASSERT_EQ(r1, r2) << "used=" << num_used << " discard=" << num_discard; } } } } TYPED_TEST(RandenEngineTypedTest, StreamOperatorsResult) { using randen = typename absl::random_internal::randen_engine; std::wostringstream os; std::wistringstream is; randen engine; EXPECT_EQ(&(os << engine), &os); EXPECT_EQ(&(is >> engine), &is); } TYPED_TEST(RandenEngineTypedTest, StreamSerialization) { using randen = typename absl::random_internal::randen_engine; for (size_t discard = 0; discard < kTwoBufferValues; ++discard) { ExplicitSeedSeq seed_sequence{12, 34, 56}; randen engine(seed_sequence); engine.discard(discard); std::stringstream stream; stream << engine; randen new_engine; stream >> new_engine; for (size_t i = 0; i < 64; ++i) { EXPECT_EQ(engine(), new_engine()) << " " << i; } } } constexpr size_t kNumGoldenOutputs = 127; // This test is checking if randen_engine is meets interface requirements // defined in [rand.req.urbg]. TYPED_TEST(RandenEngineTypedTest, RandomNumberEngineInterface) { using randen = typename absl::random_internal::randen_engine; using E = randen; using T = typename E::result_type; static_assert(std::is_copy_constructible::value, "randen_engine must be copy constructible"); static_assert(absl::is_copy_assignable::value, "randen_engine must be copy assignable"); static_assert(std::is_move_constructible::value, "randen_engine must be move constructible"); static_assert(absl::is_move_assignable::value, "randen_engine must be move assignable"); static_assert(std::is_same()()), T>::value, "return type of operator() must be result_type"); // Names after definition of [rand.req.urbg] in C++ standard. // e us a value of E // v is a lvalue of E // x, y are possibly const values of E // s is a value of T // q is a value satisfying requirements of seed_sequence // z is a value of type unsigned long long // os is a some specialization of basic_ostream // is is a some specialization of basic_istream E e, v; const E x, y; T s = 1; std::seed_seq q{1, 2, 3}; unsigned long long z = 1; // NOLINT(runtime/int) std::wostringstream os; std::wistringstream is; E{}; E{x}; E{s}; E{q}; e.seed(); // MSVC emits error 2718 when using EXPECT_EQ(e, x) // * actual parameter with __declspec(align('#')) won't be aligned EXPECT_TRUE(e == x); e.seed(q); { E tmp(q); EXPECT_TRUE(e == tmp); } e(); { E tmp(q); EXPECT_TRUE(e != tmp); } e.discard(z); static_assert(std::is_same::value, "return type of operator== must be bool"); static_assert(std::is_same::value, "return type of operator== must be bool"); } TYPED_TEST(RandenEngineTypedTest, RandenEngineSFINAETest) { using randen = typename absl::random_internal::randen_engine; using result_type = typename randen::result_type; { randen engine(result_type(1)); engine.seed(result_type(1)); } { result_type n = 1; randen engine(n); engine.seed(n); } { randen engine(1); engine.seed(1); } { int n = 1; randen engine(n); engine.seed(n); } { std::seed_seq seed_seq; randen engine(seed_seq); engine.seed(seed_seq); } { randen engine{std::seed_seq()}; engine.seed(std::seed_seq()); } } TEST(RandenTest, VerifyGoldenRanden64Default) { constexpr uint64_t kGolden[kNumGoldenOutputs] = { 0xc3c14f134e433977, 0xdda9f47cd90410ee, 0x887bf3087fd8ca10, 0xf0b780f545c72912, 0x15dbb1d37696599f, 0x30ec63baff3c6d59, 0xb29f73606f7f20a6, 0x02808a316f49a54c, 0x3b8feaf9d5c8e50e, 0x9cbf605e3fd9de8a, 0xc970ae1a78183bbb, 0xd8b2ffd356301ed5, 0xf4b327fe0fc73c37, 0xcdfd8d76eb8f9a19, 0xc3a506eb91420c9d, 0xd5af05dd3eff9556, 0x48db1bb78f83c4a1, 0x7023920e0d6bfe8c, 0x58d3575834956d42, 0xed1ef4c26b87b840, 0x8eef32a23e0b2df3, 0x497cabf3431154fc, 0x4e24370570029a8b, 0xd88b5749f090e5ea, 0xc651a582a970692f, 0x78fcec2cbb6342f5, 0x463cb745612f55db, 0x352ee4ad1816afe3, 0x026ff374c101da7e, 0x811ef0821c3de851, 0x6f7e616704c4fa59, 0xa0660379992d58fc, 0x04b0a374a3b795c7, 0x915f3445685da798, 0x26802a8ac76571ce, 0x4663352533ce1882, 0xb9fdefb4a24dc738, 0x5588ba3a4d6e6c51, 0xa2101a42d35f1956, 0x607195a5e200f5fd, 0x7e100308f3290764, 0xe1e5e03c759c0709, 0x082572cc5da6606f, 0xcbcf585399e432f1, 0xe8a2be4f8335d8f1, 0x0904469acbfee8f2, 0xf08bd31b6daecd51, 0x08e8a1f1a69da69a, 0x6542a20aad57bff5, 0x2e9705bb053d6b46, 0xda2fc9db0713c391, 0x78e3a810213b6ffb, 0xdc16a59cdd85f8a6, 0xc0932718cd55781f, 0xb9bfb29c2b20bfe5, 0xb97289c1be0f2f9c, 0xc0a2a0e403a892d4, 0x5524bb834771435b, 0x8265da3d39d1a750, 0xff4af3ab8d1b78c5, 0xf0ec5f424bcad77f, 0x66e455f627495189, 0xc82d3120b57e3270, 0x3424e47dc22596e3, 0xbc0c95129ccedcdd, 0xc191c595afc4dcbf, 0x120392bd2bb70939, 0x7f90650ea6cd6ab4, 0x7287491832695ad3, 0xa7c8fac5a7917eb0, 0xd088cb9418be0361, 0x7c1bf9839c7c1ce5, 0xe2e991fa58e1e79e, 0x78565cdefd28c4ad, 0x7351b9fef98bafad, 0x2a9eac28b08c96bf, 0x6c4f179696cb2225, 0x13a685861bab87e0, 0x64c6de5aa0501971, 0x30537425cac70991, 0x01590d9dc6c532b7, 0x7e05e3aa8ec720dc, 0x74a07d9c54e3e63f, 0x738184388f3bc1d2, 0x26ffdc5067be3acb, 0x6bcdf185561f255f, 0xa0eaf2e1cf99b1c6, 0x171df81934f68604, 0x7ea5a21665683e5a, 0x5d1cb02075ba1cea, 0x957f38cbd2123fdf, 0xba6364eff80de02f, 0x606e0a0e41d452ee, 0x892d8317de82f7a2, 0xe707b1db50f7b43e, 0x4eb28826766fcf5b, 0x5a362d56e80a0951, 0x6ee217df16527d78, 0xf6737962ba6b23dd, 0x443e63857d4076ca, 0x790d9a5f048adfeb, 0xd796b052151ee94d, 0x033ed95c12b04a03, 0x8b833ff84893da5d, 0x3d6724b1bb15eab9, 0x9877c4225061ca76, 0xd68d6810adf74fb3, 0x42e5352fe30ce989, 0x265b565a7431fde7, 0x3cdbf7e358df4b8b, 0x2922a47f6d3e8779, 0x52d2242f65b37f88, 0x5d836d6e2958d6b5, 0x29d40f00566d5e26, 0x288db0e1124b14a0, 0x6c056608b7d9c1b6, 0x0b9471bdb8f19d32, 0x8fb946504faa6c9d, 0x8943a9464540251c, 0xfd1fe27d144a09e0, 0xea6ac458da141bda, 0x8048f217633fce36, 0xfeda1384ade74d31, 0x4334b8b02ff7612f, 0xdbc8441f5227e216, 0x096d119a3605c85b, 0x2b72b31c21b7d7d0}; randen_u64 engine; #if UPDATE_GOLDEN (void)kGolden; // Silence warning. for (size_t i = 0; i < kNumGoldenOutputs; ++i) { printf("0x%016lx, ", engine()); if (i % 3 == 2) { printf("\n"); } } printf("\n\n\n"); #else for (const auto& elem : kGolden) { EXPECT_EQ(elem, engine()); } engine.seed(); for (const auto& elem : kGolden) { EXPECT_EQ(elem, engine()); } #endif } TEST(RandenTest, VerifyGoldenRanden64Seeded) { constexpr uint64_t kGolden[kNumGoldenOutputs] = { 0x83a9e58f94d3dcd5, 0x70bbdff3d97949fb, 0x0438481f7471c1b4, 0x34fdc58ee5fb5930, 0xceee4f2d2a937d17, 0xb5a26a68e432aea9, 0x8b64774a3fb51740, 0xd89ac1fc74249c74, 0x03910d1d23fc3fdf, 0xd38f630878aa897f, 0x0ee8f0f5615f7e44, 0x98f5a53df8279d52, 0xb403f52c25938d0e, 0x240072996ea6e838, 0xd3a791246190fa61, 0xaaedd3df7a7b4f80, 0xc6eacabe05deaf6e, 0xb7967dd8790edf4d, 0x9a0a8e67e049d279, 0x0494f606aebc23e7, 0x598dcd687bc3e0ee, 0x010ac81802d452a1, 0x6407c87160aa2842, 0x5a56e276486f93a0, 0xc887a399d46a8f02, 0x9e1e6100fe93b740, 0x12d02e330f8901f6, 0xc39ca52b47e790b7, 0xb0b0a2fa11e82e61, 0x1542d841a303806a, 0x1fe659fd7d6e9d86, 0xb8c90d80746541ac, 0x239d56a5669ddc94, 0xd40db57c8123d13c, 0x3abc2414153a0db0, 0x9bad665630cb8d61, 0x0bd1fb90ee3f4bbc, 0x8f0b4d7e079b4e42, 0xfa0fb0e0ee59e793, 0x51080b283e071100, 0x2c4b9e715081cc15, 0xbe10ed49de4941df, 0xf8eaac9d4b1b0d37, 0x4bcce4b54605e139, 0xa64722b76765dda6, 0xb9377d738ca28ab5, 0x779fad81a8ccc1af, 0x65cb3ee61ffd3ba7, 0xd74e79087862836f, 0xd05b9c584c3f25bf, 0x2ba93a4693579827, 0xd81530aff05420ce, 0xec06cea215478621, 0x4b1798a6796d65ad, 0xf142f3fb3a6f6fa6, 0x002b7bf7e237b560, 0xf47f2605ef65b4f8, 0x9804ec5517effc18, 0xaed3d7f8b7d481cd, 0x5651c24c1ce338d1, 0x3e7a38208bf0a3c6, 0x6796a7b614534aed, 0x0d0f3b848358460f, 0x0fa5fe7600b19524, 0x2b0cf38253faaedc, 0x10df9188233a9fd6, 0x3a10033880138b59, 0x5fb0b0d23948e80f, 0x9e76f7b02fbf5350, 0x0816052304b1a985, 0x30c9880db41fd218, 0x14aa399b65e20f28, 0xe1454a8cace787b4, 0x325ac971b6c6f0f5, 0x716b1aa2784f3d36, 0x3d5ce14accfd144f, 0x6c0c97710f651792, 0xbc5b0f59fb333532, 0x2a90a7d2140470bc, 0x8da269f55c1e1c8d, 0xcfc37143895792ca, 0xbe21eab1f30b238f, 0x8c47229dee4d65fd, 0x5743614ed1ed7d54, 0x351372a99e9c476e, 0x2bd5ea15e5db085f, 0x6925fde46e0af4ca, 0xed3eda2bdc1f45bd, 0xdef68c68d460fa6e, 0xe42a0de76253e2b5, 0x4e5176dcbc29c305, 0xbfd85fba9f810f6e, 0x76a5a2a9beb815c6, 0x01edc4ddceaf414c, 0xa4e98904b4bb3b4b, 0x00bd63ac7d2f1ddd, 0xb8491fe6e998ddbb, 0xb386a3463dda6800, 0x0081887688871619, 0x33d394b3344e9a38, 0x815dba65a3a8baf9, 0x4232f6ec02c2fd1a, 0xb5cff603edd20834, 0x580189243f687663, 0xa8d5a2cbdc27fe99, 0x725d881693fa0131, 0xa2be2c13db2c7ac5, 0x7b6a9614b509fd78, 0xb6b136d71e717636, 0x660f1a71aff046ea, 0x0ba10ae346c8ec9e, 0xe66dde53e3145b41, 0x3b18288c88c26be6, 0x4d9d9d2ff02db933, 0x4167da8c70f46e8a, 0xf183beef8c6318b4, 0x4d889e1e71eeeef1, 0x7175c71ad6689b6b, 0xfb9e42beacd1b7dd, 0xc33d0e91b29b5e0d, 0xd39b83291ce47922, 0xc4d570fb8493d12e, 0x23d5a5724f424ae6, 0x5245f161876b6616, 0x38d77dbd21ab578d, 0x9c3423311f4ecbfe, 0x76fe31389bacd9d5, }; ExplicitSeedSeq seed_sequence{12, 34, 56}; randen_u64 engine(seed_sequence); #if UPDATE_GOLDEN (void)kGolden; // Silence warning. for (size_t i = 0; i < kNumGoldenOutputs; ++i) { printf("0x%016lx, ", engine()); if (i % 3 == 2) { printf("\n"); } } printf("\n\n\n"); #else for (const auto& elem : kGolden) { EXPECT_EQ(elem, engine()); } engine.seed(seed_sequence); for (const auto& elem : kGolden) { EXPECT_EQ(elem, engine()); } #endif } TEST(RandenTest, VerifyGoldenRanden32Default) { constexpr uint64_t kGolden[2 * kNumGoldenOutputs] = { 0x4e433977, 0xc3c14f13, 0xd90410ee, 0xdda9f47c, 0x7fd8ca10, 0x887bf308, 0x45c72912, 0xf0b780f5, 0x7696599f, 0x15dbb1d3, 0xff3c6d59, 0x30ec63ba, 0x6f7f20a6, 0xb29f7360, 0x6f49a54c, 0x02808a31, 0xd5c8e50e, 0x3b8feaf9, 0x3fd9de8a, 0x9cbf605e, 0x78183bbb, 0xc970ae1a, 0x56301ed5, 0xd8b2ffd3, 0x0fc73c37, 0xf4b327fe, 0xeb8f9a19, 0xcdfd8d76, 0x91420c9d, 0xc3a506eb, 0x3eff9556, 0xd5af05dd, 0x8f83c4a1, 0x48db1bb7, 0x0d6bfe8c, 0x7023920e, 0x34956d42, 0x58d35758, 0x6b87b840, 0xed1ef4c2, 0x3e0b2df3, 0x8eef32a2, 0x431154fc, 0x497cabf3, 0x70029a8b, 0x4e243705, 0xf090e5ea, 0xd88b5749, 0xa970692f, 0xc651a582, 0xbb6342f5, 0x78fcec2c, 0x612f55db, 0x463cb745, 0x1816afe3, 0x352ee4ad, 0xc101da7e, 0x026ff374, 0x1c3de851, 0x811ef082, 0x04c4fa59, 0x6f7e6167, 0x992d58fc, 0xa0660379, 0xa3b795c7, 0x04b0a374, 0x685da798, 0x915f3445, 0xc76571ce, 0x26802a8a, 0x33ce1882, 0x46633525, 0xa24dc738, 0xb9fdefb4, 0x4d6e6c51, 0x5588ba3a, 0xd35f1956, 0xa2101a42, 0xe200f5fd, 0x607195a5, 0xf3290764, 0x7e100308, 0x759c0709, 0xe1e5e03c, 0x5da6606f, 0x082572cc, 0x99e432f1, 0xcbcf5853, 0x8335d8f1, 0xe8a2be4f, 0xcbfee8f2, 0x0904469a, 0x6daecd51, 0xf08bd31b, 0xa69da69a, 0x08e8a1f1, 0xad57bff5, 0x6542a20a, 0x053d6b46, 0x2e9705bb, 0x0713c391, 0xda2fc9db, 0x213b6ffb, 0x78e3a810, 0xdd85f8a6, 0xdc16a59c, 0xcd55781f, 0xc0932718, 0x2b20bfe5, 0xb9bfb29c, 0xbe0f2f9c, 0xb97289c1, 0x03a892d4, 0xc0a2a0e4, 0x4771435b, 0x5524bb83, 0x39d1a750, 0x8265da3d, 0x8d1b78c5, 0xff4af3ab, 0x4bcad77f, 0xf0ec5f42, 0x27495189, 0x66e455f6, 0xb57e3270, 0xc82d3120, 0xc22596e3, 0x3424e47d, 0x9ccedcdd, 0xbc0c9512, 0xafc4dcbf, 0xc191c595, 0x2bb70939, 0x120392bd, 0xa6cd6ab4, 0x7f90650e, 0x32695ad3, 0x72874918, 0xa7917eb0, 0xa7c8fac5, 0x18be0361, 0xd088cb94, 0x9c7c1ce5, 0x7c1bf983, 0x58e1e79e, 0xe2e991fa, 0xfd28c4ad, 0x78565cde, 0xf98bafad, 0x7351b9fe, 0xb08c96bf, 0x2a9eac28, 0x96cb2225, 0x6c4f1796, 0x1bab87e0, 0x13a68586, 0xa0501971, 0x64c6de5a, 0xcac70991, 0x30537425, 0xc6c532b7, 0x01590d9d, 0x8ec720dc, 0x7e05e3aa, 0x54e3e63f, 0x74a07d9c, 0x8f3bc1d2, 0x73818438, 0x67be3acb, 0x26ffdc50, 0x561f255f, 0x6bcdf185, 0xcf99b1c6, 0xa0eaf2e1, 0x34f68604, 0x171df819, 0x65683e5a, 0x7ea5a216, 0x75ba1cea, 0x5d1cb020, 0xd2123fdf, 0x957f38cb, 0xf80de02f, 0xba6364ef, 0x41d452ee, 0x606e0a0e, 0xde82f7a2, 0x892d8317, 0x50f7b43e, 0xe707b1db, 0x766fcf5b, 0x4eb28826, 0xe80a0951, 0x5a362d56, 0x16527d78, 0x6ee217df, 0xba6b23dd, 0xf6737962, 0x7d4076ca, 0x443e6385, 0x048adfeb, 0x790d9a5f, 0x151ee94d, 0xd796b052, 0x12b04a03, 0x033ed95c, 0x4893da5d, 0x8b833ff8, 0xbb15eab9, 0x3d6724b1, 0x5061ca76, 0x9877c422, 0xadf74fb3, 0xd68d6810, 0xe30ce989, 0x42e5352f, 0x7431fde7, 0x265b565a, 0x58df4b8b, 0x3cdbf7e3, 0x6d3e8779, 0x2922a47f, 0x65b37f88, 0x52d2242f, 0x2958d6b5, 0x5d836d6e, 0x566d5e26, 0x29d40f00, 0x124b14a0, 0x288db0e1, 0xb7d9c1b6, 0x6c056608, 0xb8f19d32, 0x0b9471bd, 0x4faa6c9d, 0x8fb94650, 0x4540251c, 0x8943a946, 0x144a09e0, 0xfd1fe27d, 0xda141bda, 0xea6ac458, 0x633fce36, 0x8048f217, 0xade74d31, 0xfeda1384, 0x2ff7612f, 0x4334b8b0, 0x5227e216, 0xdbc8441f, 0x3605c85b, 0x096d119a, 0x21b7d7d0, 0x2b72b31c}; randen_u32 engine; #if UPDATE_GOLDEN (void)kGolden; // Silence warning. for (size_t i = 0; i < 2 * kNumGoldenOutputs; ++i) { printf("0x%08x, ", engine()); if (i % 6 == 5) { printf("\n"); } } printf("\n\n\n"); #else for (const auto& elem : kGolden) { EXPECT_EQ(elem, engine()); } engine.seed(); for (const auto& elem : kGolden) { EXPECT_EQ(elem, engine()); } #endif } TEST(RandenTest, VerifyGoldenRanden32Seeded) { constexpr uint64_t kGolden[2 * kNumGoldenOutputs] = { 0x94d3dcd5, 0x83a9e58f, 0xd97949fb, 0x70bbdff3, 0x7471c1b4, 0x0438481f, 0xe5fb5930, 0x34fdc58e, 0x2a937d17, 0xceee4f2d, 0xe432aea9, 0xb5a26a68, 0x3fb51740, 0x8b64774a, 0x74249c74, 0xd89ac1fc, 0x23fc3fdf, 0x03910d1d, 0x78aa897f, 0xd38f6308, 0x615f7e44, 0x0ee8f0f5, 0xf8279d52, 0x98f5a53d, 0x25938d0e, 0xb403f52c, 0x6ea6e838, 0x24007299, 0x6190fa61, 0xd3a79124, 0x7a7b4f80, 0xaaedd3df, 0x05deaf6e, 0xc6eacabe, 0x790edf4d, 0xb7967dd8, 0xe049d279, 0x9a0a8e67, 0xaebc23e7, 0x0494f606, 0x7bc3e0ee, 0x598dcd68, 0x02d452a1, 0x010ac818, 0x60aa2842, 0x6407c871, 0x486f93a0, 0x5a56e276, 0xd46a8f02, 0xc887a399, 0xfe93b740, 0x9e1e6100, 0x0f8901f6, 0x12d02e33, 0x47e790b7, 0xc39ca52b, 0x11e82e61, 0xb0b0a2fa, 0xa303806a, 0x1542d841, 0x7d6e9d86, 0x1fe659fd, 0x746541ac, 0xb8c90d80, 0x669ddc94, 0x239d56a5, 0x8123d13c, 0xd40db57c, 0x153a0db0, 0x3abc2414, 0x30cb8d61, 0x9bad6656, 0xee3f4bbc, 0x0bd1fb90, 0x079b4e42, 0x8f0b4d7e, 0xee59e793, 0xfa0fb0e0, 0x3e071100, 0x51080b28, 0x5081cc15, 0x2c4b9e71, 0xde4941df, 0xbe10ed49, 0x4b1b0d37, 0xf8eaac9d, 0x4605e139, 0x4bcce4b5, 0x6765dda6, 0xa64722b7, 0x8ca28ab5, 0xb9377d73, 0xa8ccc1af, 0x779fad81, 0x1ffd3ba7, 0x65cb3ee6, 0x7862836f, 0xd74e7908, 0x4c3f25bf, 0xd05b9c58, 0x93579827, 0x2ba93a46, 0xf05420ce, 0xd81530af, 0x15478621, 0xec06cea2, 0x796d65ad, 0x4b1798a6, 0x3a6f6fa6, 0xf142f3fb, 0xe237b560, 0x002b7bf7, 0xef65b4f8, 0xf47f2605, 0x17effc18, 0x9804ec55, 0xb7d481cd, 0xaed3d7f8, 0x1ce338d1, 0x5651c24c, 0x8bf0a3c6, 0x3e7a3820, 0x14534aed, 0x6796a7b6, 0x8358460f, 0x0d0f3b84, 0x00b19524, 0x0fa5fe76, 0x53faaedc, 0x2b0cf382, 0x233a9fd6, 0x10df9188, 0x80138b59, 0x3a100338, 0x3948e80f, 0x5fb0b0d2, 0x2fbf5350, 0x9e76f7b0, 0x04b1a985, 0x08160523, 0xb41fd218, 0x30c9880d, 0x65e20f28, 0x14aa399b, 0xace787b4, 0xe1454a8c, 0xb6c6f0f5, 0x325ac971, 0x784f3d36, 0x716b1aa2, 0xccfd144f, 0x3d5ce14a, 0x0f651792, 0x6c0c9771, 0xfb333532, 0xbc5b0f59, 0x140470bc, 0x2a90a7d2, 0x5c1e1c8d, 0x8da269f5, 0x895792ca, 0xcfc37143, 0xf30b238f, 0xbe21eab1, 0xee4d65fd, 0x8c47229d, 0xd1ed7d54, 0x5743614e, 0x9e9c476e, 0x351372a9, 0xe5db085f, 0x2bd5ea15, 0x6e0af4ca, 0x6925fde4, 0xdc1f45bd, 0xed3eda2b, 0xd460fa6e, 0xdef68c68, 0x6253e2b5, 0xe42a0de7, 0xbc29c305, 0x4e5176dc, 0x9f810f6e, 0xbfd85fba, 0xbeb815c6, 0x76a5a2a9, 0xceaf414c, 0x01edc4dd, 0xb4bb3b4b, 0xa4e98904, 0x7d2f1ddd, 0x00bd63ac, 0xe998ddbb, 0xb8491fe6, 0x3dda6800, 0xb386a346, 0x88871619, 0x00818876, 0x344e9a38, 0x33d394b3, 0xa3a8baf9, 0x815dba65, 0x02c2fd1a, 0x4232f6ec, 0xedd20834, 0xb5cff603, 0x3f687663, 0x58018924, 0xdc27fe99, 0xa8d5a2cb, 0x93fa0131, 0x725d8816, 0xdb2c7ac5, 0xa2be2c13, 0xb509fd78, 0x7b6a9614, 0x1e717636, 0xb6b136d7, 0xaff046ea, 0x660f1a71, 0x46c8ec9e, 0x0ba10ae3, 0xe3145b41, 0xe66dde53, 0x88c26be6, 0x3b18288c, 0xf02db933, 0x4d9d9d2f, 0x70f46e8a, 0x4167da8c, 0x8c6318b4, 0xf183beef, 0x71eeeef1, 0x4d889e1e, 0xd6689b6b, 0x7175c71a, 0xacd1b7dd, 0xfb9e42be, 0xb29b5e0d, 0xc33d0e91, 0x1ce47922, 0xd39b8329, 0x8493d12e, 0xc4d570fb, 0x4f424ae6, 0x23d5a572, 0x876b6616, 0x5245f161, 0x21ab578d, 0x38d77dbd, 0x1f4ecbfe, 0x9c342331, 0x9bacd9d5, 0x76fe3138, }; ExplicitSeedSeq seed_sequence{12, 34, 56}; randen_u32 engine(seed_sequence); #if UPDATE_GOLDEN (void)kGolden; // Silence warning. for (size_t i = 0; i < 2 * kNumGoldenOutputs; ++i) { printf("0x%08x, ", engine()); if (i % 6 == 5) { printf("\n"); } } printf("\n\n\n"); #else for (const auto& elem : kGolden) { EXPECT_EQ(elem, engine()); } engine.seed(seed_sequence); for (const auto& elem : kGolden) { EXPECT_EQ(elem, engine()); } #endif } TEST(RandenTest, VerifyGoldenFromDeserializedEngine) { constexpr uint64_t kGolden[kNumGoldenOutputs] = { 0x067f9f9ab919657a, 0x0534605912988583, 0x8a303f72feaa673f, 0x77b7fd747909185c, 0xd9af90403c56d891, 0xd939c6cb204d14b5, 0x7fbe6b954a47b483, 0x8b31a47cc34c768d, 0x3a9e546da2701a9c, 0x5246539046253e71, 0x417191ffb2a848a1, 0x7b1c7bf5a5001d09, 0x9489b15d194f2361, 0xfcebdeea3bcd2461, 0xd643027c854cec97, 0x5885397f91e0d21c, 0x53173b0efae30d58, 0x1c9c71168449fac1, 0xe358202b711ed8aa, 0x94e3918ed1d8227c, 0x5bb4e251450144cf, 0xb5c7a519b489af3b, 0x6f8b560b1f7b3469, 0xfde11dd4a1c74eef, 0x33383d2f76457dcf, 0x3060c0ec6db9fce1, 0x18f451fcddeec766, 0xe73c5d6b9f26da2a, 0x8d4cc566671b32a4, 0xb8189b73776bc9ff, 0x497a70f9caf0bc23, 0x23afcc509791dcea, 0x18af70dc4b27d306, 0xd3853f955a0ce5b9, 0x441db6c01a0afb17, 0xd0136c3fb8e1f13f, 0x5e4fd6fc2f33783c, 0xe0d24548adb5da51, 0x0f4d8362a7d3485a, 0x9f572d68270fa563, 0x6351fbc823024393, 0xa66dbfc61810e9ab, 0x0ff17fc14b651af8, 0xd74c55dafb99e623, 0x36303bc1ad85c6c2, 0x4920cd6a2af7e897, 0x0b8848addc30fecd, 0x9e1562eda6488e93, 0x197553807d607828, 0xbef5eaeda5e21235, 0x18d91d2616aca527, 0xb7821937f5c873cd, 0x2cd4ae5650dbeefc, 0xb35a64376f75ffdf, 0x9226d414d647fe07, 0x663f3db455bbb35e, 0xa829eead6ae93247, 0x7fd69c204dd0d25f, 0xbe1411f891c9acb1, 0xd476f34a506d5f11, 0xf423d2831649c5ca, 0x1e503962951abd75, 0xeccc9e8b1e34b537, 0xb11a147294044854, 0xc4cf27f0abf4929d, 0xe9193abf6fa24c8c, 0xa94a259e3aba8808, 0x21dc414197deffa3, 0xa2ae211d1ff622ae, 0xfe3995c46be5a4f4, 0xe9984c284bf11128, 0xcb1ce9d2f0851a80, 0x42fee17971d87cd8, 0xac76a98d177adc88, 0xa0973b3dedc4af6f, 0xdf56d6bbcb1b8e86, 0xf1e6485f407b11c9, 0x2c63de4deccb15c0, 0x6fe69db32ed4fad7, 0xaa51a65f84bca1f1, 0x242f2ee81d608afc, 0x8eb88b2b69fc153b, 0x22c20098baf73fd1, 0x57759466f576488c, 0x075ca562cea1be9d, 0x9a74814d73d28891, 0x73d1555fc02f4d3d, 0xc17f8f210ee89337, 0x46cca7999eaeafd4, 0x5db8d6a327a0d8ac, 0xb79b4f93c738d7a1, 0x9994512f0036ded1, 0xd3883026f38747f4, 0xf31f7458078d097c, 0x736ce4d480680669, 0x7a496f4c7e1033e3, 0xecf85bf297fbc68c, 0x9e37e1d0f24f3c4e, 0x15b6e067ca0746fc, 0xdd4a39905c5db81c, 0xb5dfafa7bcfdf7da, 0xca6646fb6f92a276, 0x1c6b35f363ef0efd, 0x6a33d06037ad9f76, 0x45544241afd8f80f, 0x83f8d83f859c90c5, 0x22aea9c5365e8c19, 0xfac35b11f20b6a6a, 0xd1acf49d1a27dd2f, 0xf281cd09c4fed405, 0x076000a42cd38e4f, 0x6ace300565070445, 0x463a62781bddc4db, 0x1477126b46b569ac, 0x127f2bb15035fbb8, 0xdfa30946049c04a8, 0x89072a586ba8dd3e, 0x62c809582bb7e74d, 0x22c0c3641406c28b, 0x9b66e36c47ff004d, 0xb9cd2c7519653330, 0x18608d79cd7a598d, 0x92c0bd1323e53e32, 0x887ff00de8524aa5, 0xa074410b787abd10, 0x18ab41b8057a2063, 0x1560abf26bc5f987}; #if UPDATE_GOLDEN (void)kGolden; // Silence warning. std::seed_seq seed_sequence{1, 2, 3, 4, 5}; randen_u64 engine(seed_sequence); std::ostringstream stream; stream << engine; auto str = stream.str(); printf("%s\n\n", str.c_str()); for (size_t i = 0; i < kNumGoldenOutputs; ++i) { printf("0x%016lx, ", engine()); if (i % 3 == 2) { printf("\n"); } } printf("\n\n\n"); #else randen_u64 engine; std::istringstream stream( "0 0 9824501439887287479 3242284395352394785 243836530774933777 " "4047941804708365596 17165468127298385802 949276103645889255 " "10659970394998657921 1657570836810929787 11697746266668051452 " "9967209969299905230 14140390331161524430 7383014124183271684 " "13146719127702337852 13983155220295807171 11121125587542359264 " "195757810993252695 17138580243103178492 11326030747260920501 " "8585097322474965590 18342582839328350995 15052982824209724634 " "7321861343874683609 1806786911778767826 10100850842665572955 " "9249328950653985078 13600624835326909759 11137960060943860251 " "10208781341792329629 9282723971471525577 16373271619486811032 32"); stream >> engine; for (const auto& elem : kGolden) { EXPECT_EQ(elem, engine()); } #endif } TEST(RandenTest, IsFastOrSlow) { // randen_engine typically costs ~5ns per value for the optimized code paths, // and the ~1000ns per value for slow code paths. However when running under // msan, asan, etc. it can take much longer. // // The estimated operation time is something like: // // linux, optimized ~5ns // ppc, optimized ~7ns // nacl (slow), ~1100ns // // `kCount` is chosen below so that, in debug builds and without hardware // acceleration, the test (assuming ~1us per call) should finish in ~0.1s static constexpr size_t kCount = 100000; randen_u64 engine; randen_u64::result_type sum = 0; auto start = absl::GetCurrentTimeNanos(); for (int i = 0; i < kCount; i++) { sum += engine(); } auto duration = absl::GetCurrentTimeNanos() - start; ABSL_INTERNAL_LOG(INFO, absl::StrCat(static_cast(duration) / static_cast(kCount), "ns")); EXPECT_GT(sum, 0); EXPECT_GE(duration, kCount); // Should be slower than 1ns per call. } } // namespace