1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "absl/random/internal/randen_engine.h"
16 
17 #include <algorithm>
18 #include <bitset>
19 #include <random>
20 #include <sstream>
21 
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "absl/base/internal/raw_logging.h"
25 #include "absl/random/internal/explicit_seed_seq.h"
26 #include "absl/strings/str_cat.h"
27 #include "absl/time/clock.h"
28 
29 #define UPDATE_GOLDEN 0
30 
31 using randen_u64 = absl::random_internal::randen_engine<uint64_t>;
32 using randen_u32 = absl::random_internal::randen_engine<uint32_t>;
33 using absl::random_internal::ExplicitSeedSeq;
34 
35 namespace {
36 
37 template <typename UIntType>
38 class RandenEngineTypedTest : public ::testing::Test {};
39 
40 using UIntTypes = ::testing::Types<uint8_t, uint16_t, uint32_t, uint64_t>;
41 
42 TYPED_TEST_SUITE(RandenEngineTypedTest, UIntTypes);
43 
TYPED_TEST(RandenEngineTypedTest,VerifyReseedChangesAllValues)44 TYPED_TEST(RandenEngineTypedTest, VerifyReseedChangesAllValues) {
45   using randen = typename absl::random_internal::randen_engine<TypeParam>;
46   using result_type = typename randen::result_type;
47 
48   const size_t kNumOutputs = (sizeof(randen) * 2 / sizeof(TypeParam)) + 1;
49   randen engine;
50 
51   // MSVC emits error 2719 without the use of std::ref below.
52   //  * formal parameter with __declspec(align('#')) won't be aligned
53 
54   {
55     std::seed_seq seq1{1, 2, 3, 4, 5, 6, 7};
56     engine.seed(seq1);
57   }
58   result_type a[kNumOutputs];
59   std::generate(std::begin(a), std::end(a), std::ref(engine));
60 
61   {
62     std::random_device rd;
63     std::seed_seq seq2{rd(), rd(), rd()};
64     engine.seed(seq2);
65   }
66   result_type b[kNumOutputs];
67   std::generate(std::begin(b), std::end(b), std::ref(engine));
68 
69   // Test that generated sequence changed as sequence of bits, i.e. if about
70   // half of the bites were flipped between two non-correlated values.
71   size_t changed_bits = 0;
72   size_t unchanged_bits = 0;
73   size_t total_set = 0;
74   size_t total_bits = 0;
75   size_t equal_count = 0;
76   for (size_t i = 0; i < kNumOutputs; ++i) {
77     equal_count += (a[i] == b[i]) ? 1 : 0;
78     std::bitset<sizeof(result_type) * 8> bitset(a[i] ^ b[i]);
79     changed_bits += bitset.count();
80     unchanged_bits += bitset.size() - bitset.count();
81 
82     std::bitset<sizeof(result_type) * 8> a_set(a[i]);
83     std::bitset<sizeof(result_type) * 8> b_set(b[i]);
84     total_set += a_set.count() + b_set.count();
85     total_bits += 2 * 8 * sizeof(result_type);
86   }
87   // On average, half the bits are changed between two calls.
88   EXPECT_LE(changed_bits, 0.60 * (changed_bits + unchanged_bits));
89   EXPECT_GE(changed_bits, 0.40 * (changed_bits + unchanged_bits));
90 
91   // Verify using a quick normal-approximation to the binomial.
92   EXPECT_NEAR(total_set, total_bits * 0.5, 4 * std::sqrt(total_bits))
93       << "@" << total_set / static_cast<double>(total_bits);
94 
95   // Also, A[i] == B[i] with probability (1/range) * N.
96   // Give this a pretty wide latitude, though.
97   const double kExpected = kNumOutputs / (1.0 * sizeof(result_type) * 8);
98   EXPECT_LE(equal_count, 1.0 + kExpected);
99 }
100 
101 // Number of values that needs to be consumed to clean two sizes of buffer
102 // and trigger third refresh. (slightly overestimates the actual state size).
103 constexpr size_t kTwoBufferValues = sizeof(randen_u64) / sizeof(uint16_t) + 1;
104 
TYPED_TEST(RandenEngineTypedTest,VerifyDiscard)105 TYPED_TEST(RandenEngineTypedTest, VerifyDiscard) {
106   using randen = typename absl::random_internal::randen_engine<TypeParam>;
107 
108   for (size_t num_used = 0; num_used < kTwoBufferValues; ++num_used) {
109     randen engine_used;
110     for (size_t i = 0; i < num_used; ++i) {
111       engine_used();
112     }
113 
114     for (size_t num_discard = 0; num_discard < kTwoBufferValues;
115          ++num_discard) {
116       randen engine1 = engine_used;
117       randen engine2 = engine_used;
118       for (size_t i = 0; i < num_discard; ++i) {
119         engine1();
120       }
121       engine2.discard(num_discard);
122       for (size_t i = 0; i < kTwoBufferValues; ++i) {
123         const auto r1 = engine1();
124         const auto r2 = engine2();
125         ASSERT_EQ(r1, r2) << "used=" << num_used << " discard=" << num_discard;
126       }
127     }
128   }
129 }
130 
TYPED_TEST(RandenEngineTypedTest,StreamOperatorsResult)131 TYPED_TEST(RandenEngineTypedTest, StreamOperatorsResult) {
132   using randen = typename absl::random_internal::randen_engine<TypeParam>;
133   std::wostringstream os;
134   std::wistringstream is;
135   randen engine;
136 
137   EXPECT_EQ(&(os << engine), &os);
138   EXPECT_EQ(&(is >> engine), &is);
139 }
140 
TYPED_TEST(RandenEngineTypedTest,StreamSerialization)141 TYPED_TEST(RandenEngineTypedTest, StreamSerialization) {
142   using randen = typename absl::random_internal::randen_engine<TypeParam>;
143 
144   for (size_t discard = 0; discard < kTwoBufferValues; ++discard) {
145     ExplicitSeedSeq seed_sequence{12, 34, 56};
146     randen engine(seed_sequence);
147     engine.discard(discard);
148 
149     std::stringstream stream;
150     stream << engine;
151 
152     randen new_engine;
153     stream >> new_engine;
154     for (size_t i = 0; i < 64; ++i) {
155       EXPECT_EQ(engine(), new_engine()) << " " << i;
156     }
157   }
158 }
159 
160 constexpr size_t kNumGoldenOutputs = 127;
161 
162 // This test is checking if randen_engine is meets interface requirements
163 // defined in [rand.req.urbg].
TYPED_TEST(RandenEngineTypedTest,RandomNumberEngineInterface)164 TYPED_TEST(RandenEngineTypedTest, RandomNumberEngineInterface) {
165   using randen = typename absl::random_internal::randen_engine<TypeParam>;
166 
167   using E = randen;
168   using T = typename E::result_type;
169 
170   static_assert(std::is_copy_constructible<E>::value,
171                 "randen_engine must be copy constructible");
172 
173   static_assert(absl::is_copy_assignable<E>::value,
174                 "randen_engine must be copy assignable");
175 
176   static_assert(std::is_move_constructible<E>::value,
177                 "randen_engine must be move constructible");
178 
179   static_assert(absl::is_move_assignable<E>::value,
180                 "randen_engine must be move assignable");
181 
182   static_assert(std::is_same<decltype(std::declval<E>()()), T>::value,
183                 "return type of operator() must be result_type");
184 
185   // Names after definition of [rand.req.urbg] in C++ standard.
186   // e us a value of E
187   // v is a lvalue of E
188   // x, y are possibly const values of E
189   // s is a value of T
190   // q is a value satisfying requirements of seed_sequence
191   // z is a value of type unsigned long long
192   // os is a some specialization of basic_ostream
193   // is is a some specialization of basic_istream
194 
195   E e, v;
196   const E x, y;
197   T s = 1;
198   std::seed_seq q{1, 2, 3};
199   unsigned long long z = 1;  // NOLINT(runtime/int)
200   std::wostringstream os;
201   std::wistringstream is;
202 
203   E{};
204   E{x};
205   E{s};
206   E{q};
207 
208   e.seed();
209 
210   // MSVC emits error 2718 when using EXPECT_EQ(e, x)
211   //  * actual parameter with __declspec(align('#')) won't be aligned
212   EXPECT_TRUE(e == x);
213 
214   e.seed(q);
215   {
216     E tmp(q);
217     EXPECT_TRUE(e == tmp);
218   }
219 
220   e();
221   {
222     E tmp(q);
223     EXPECT_TRUE(e != tmp);
224   }
225 
226   e.discard(z);
227 
228   static_assert(std::is_same<decltype(x == y), bool>::value,
229                 "return type of operator== must be bool");
230 
231   static_assert(std::is_same<decltype(x != y), bool>::value,
232                 "return type of operator== must be bool");
233 }
234 
TYPED_TEST(RandenEngineTypedTest,RandenEngineSFINAETest)235 TYPED_TEST(RandenEngineTypedTest, RandenEngineSFINAETest) {
236   using randen = typename absl::random_internal::randen_engine<TypeParam>;
237   using result_type = typename randen::result_type;
238 
239   {
240     randen engine(result_type(1));
241     engine.seed(result_type(1));
242   }
243 
244   {
245     result_type n = 1;
246     randen engine(n);
247     engine.seed(n);
248   }
249 
250   {
251     randen engine(1);
252     engine.seed(1);
253   }
254 
255   {
256     int n = 1;
257     randen engine(n);
258     engine.seed(n);
259   }
260 
261   {
262     std::seed_seq seed_seq;
263     randen engine(seed_seq);
264     engine.seed(seed_seq);
265   }
266 
267   {
268     randen engine{std::seed_seq()};
269     engine.seed(std::seed_seq());
270   }
271 }
272 
TEST(RandenTest,VerifyGoldenRanden64Default)273 TEST(RandenTest, VerifyGoldenRanden64Default) {
274   constexpr uint64_t kGolden[kNumGoldenOutputs] = {
275       0xc3c14f134e433977, 0xdda9f47cd90410ee, 0x887bf3087fd8ca10,
276       0xf0b780f545c72912, 0x15dbb1d37696599f, 0x30ec63baff3c6d59,
277       0xb29f73606f7f20a6, 0x02808a316f49a54c, 0x3b8feaf9d5c8e50e,
278       0x9cbf605e3fd9de8a, 0xc970ae1a78183bbb, 0xd8b2ffd356301ed5,
279       0xf4b327fe0fc73c37, 0xcdfd8d76eb8f9a19, 0xc3a506eb91420c9d,
280       0xd5af05dd3eff9556, 0x48db1bb78f83c4a1, 0x7023920e0d6bfe8c,
281       0x58d3575834956d42, 0xed1ef4c26b87b840, 0x8eef32a23e0b2df3,
282       0x497cabf3431154fc, 0x4e24370570029a8b, 0xd88b5749f090e5ea,
283       0xc651a582a970692f, 0x78fcec2cbb6342f5, 0x463cb745612f55db,
284       0x352ee4ad1816afe3, 0x026ff374c101da7e, 0x811ef0821c3de851,
285       0x6f7e616704c4fa59, 0xa0660379992d58fc, 0x04b0a374a3b795c7,
286       0x915f3445685da798, 0x26802a8ac76571ce, 0x4663352533ce1882,
287       0xb9fdefb4a24dc738, 0x5588ba3a4d6e6c51, 0xa2101a42d35f1956,
288       0x607195a5e200f5fd, 0x7e100308f3290764, 0xe1e5e03c759c0709,
289       0x082572cc5da6606f, 0xcbcf585399e432f1, 0xe8a2be4f8335d8f1,
290       0x0904469acbfee8f2, 0xf08bd31b6daecd51, 0x08e8a1f1a69da69a,
291       0x6542a20aad57bff5, 0x2e9705bb053d6b46, 0xda2fc9db0713c391,
292       0x78e3a810213b6ffb, 0xdc16a59cdd85f8a6, 0xc0932718cd55781f,
293       0xb9bfb29c2b20bfe5, 0xb97289c1be0f2f9c, 0xc0a2a0e403a892d4,
294       0x5524bb834771435b, 0x8265da3d39d1a750, 0xff4af3ab8d1b78c5,
295       0xf0ec5f424bcad77f, 0x66e455f627495189, 0xc82d3120b57e3270,
296       0x3424e47dc22596e3, 0xbc0c95129ccedcdd, 0xc191c595afc4dcbf,
297       0x120392bd2bb70939, 0x7f90650ea6cd6ab4, 0x7287491832695ad3,
298       0xa7c8fac5a7917eb0, 0xd088cb9418be0361, 0x7c1bf9839c7c1ce5,
299       0xe2e991fa58e1e79e, 0x78565cdefd28c4ad, 0x7351b9fef98bafad,
300       0x2a9eac28b08c96bf, 0x6c4f179696cb2225, 0x13a685861bab87e0,
301       0x64c6de5aa0501971, 0x30537425cac70991, 0x01590d9dc6c532b7,
302       0x7e05e3aa8ec720dc, 0x74a07d9c54e3e63f, 0x738184388f3bc1d2,
303       0x26ffdc5067be3acb, 0x6bcdf185561f255f, 0xa0eaf2e1cf99b1c6,
304       0x171df81934f68604, 0x7ea5a21665683e5a, 0x5d1cb02075ba1cea,
305       0x957f38cbd2123fdf, 0xba6364eff80de02f, 0x606e0a0e41d452ee,
306       0x892d8317de82f7a2, 0xe707b1db50f7b43e, 0x4eb28826766fcf5b,
307       0x5a362d56e80a0951, 0x6ee217df16527d78, 0xf6737962ba6b23dd,
308       0x443e63857d4076ca, 0x790d9a5f048adfeb, 0xd796b052151ee94d,
309       0x033ed95c12b04a03, 0x8b833ff84893da5d, 0x3d6724b1bb15eab9,
310       0x9877c4225061ca76, 0xd68d6810adf74fb3, 0x42e5352fe30ce989,
311       0x265b565a7431fde7, 0x3cdbf7e358df4b8b, 0x2922a47f6d3e8779,
312       0x52d2242f65b37f88, 0x5d836d6e2958d6b5, 0x29d40f00566d5e26,
313       0x288db0e1124b14a0, 0x6c056608b7d9c1b6, 0x0b9471bdb8f19d32,
314       0x8fb946504faa6c9d, 0x8943a9464540251c, 0xfd1fe27d144a09e0,
315       0xea6ac458da141bda, 0x8048f217633fce36, 0xfeda1384ade74d31,
316       0x4334b8b02ff7612f, 0xdbc8441f5227e216, 0x096d119a3605c85b,
317       0x2b72b31c21b7d7d0};
318 
319   randen_u64 engine;
320 #if UPDATE_GOLDEN
321   (void)kGolden;  // Silence warning.
322   for (size_t i = 0; i < kNumGoldenOutputs; ++i) {
323     printf("0x%016lx, ", engine());
324     if (i % 3 == 2) {
325       printf("\n");
326     }
327   }
328   printf("\n\n\n");
329 #else
330   for (const auto& elem : kGolden) {
331     EXPECT_EQ(elem, engine());
332   }
333   engine.seed();
334   for (const auto& elem : kGolden) {
335     EXPECT_EQ(elem, engine());
336   }
337 #endif
338 }
339 
TEST(RandenTest,VerifyGoldenRanden64Seeded)340 TEST(RandenTest, VerifyGoldenRanden64Seeded) {
341   constexpr uint64_t kGolden[kNumGoldenOutputs] = {
342       0x83a9e58f94d3dcd5, 0x70bbdff3d97949fb, 0x0438481f7471c1b4,
343       0x34fdc58ee5fb5930, 0xceee4f2d2a937d17, 0xb5a26a68e432aea9,
344       0x8b64774a3fb51740, 0xd89ac1fc74249c74, 0x03910d1d23fc3fdf,
345       0xd38f630878aa897f, 0x0ee8f0f5615f7e44, 0x98f5a53df8279d52,
346       0xb403f52c25938d0e, 0x240072996ea6e838, 0xd3a791246190fa61,
347       0xaaedd3df7a7b4f80, 0xc6eacabe05deaf6e, 0xb7967dd8790edf4d,
348       0x9a0a8e67e049d279, 0x0494f606aebc23e7, 0x598dcd687bc3e0ee,
349       0x010ac81802d452a1, 0x6407c87160aa2842, 0x5a56e276486f93a0,
350       0xc887a399d46a8f02, 0x9e1e6100fe93b740, 0x12d02e330f8901f6,
351       0xc39ca52b47e790b7, 0xb0b0a2fa11e82e61, 0x1542d841a303806a,
352       0x1fe659fd7d6e9d86, 0xb8c90d80746541ac, 0x239d56a5669ddc94,
353       0xd40db57c8123d13c, 0x3abc2414153a0db0, 0x9bad665630cb8d61,
354       0x0bd1fb90ee3f4bbc, 0x8f0b4d7e079b4e42, 0xfa0fb0e0ee59e793,
355       0x51080b283e071100, 0x2c4b9e715081cc15, 0xbe10ed49de4941df,
356       0xf8eaac9d4b1b0d37, 0x4bcce4b54605e139, 0xa64722b76765dda6,
357       0xb9377d738ca28ab5, 0x779fad81a8ccc1af, 0x65cb3ee61ffd3ba7,
358       0xd74e79087862836f, 0xd05b9c584c3f25bf, 0x2ba93a4693579827,
359       0xd81530aff05420ce, 0xec06cea215478621, 0x4b1798a6796d65ad,
360       0xf142f3fb3a6f6fa6, 0x002b7bf7e237b560, 0xf47f2605ef65b4f8,
361       0x9804ec5517effc18, 0xaed3d7f8b7d481cd, 0x5651c24c1ce338d1,
362       0x3e7a38208bf0a3c6, 0x6796a7b614534aed, 0x0d0f3b848358460f,
363       0x0fa5fe7600b19524, 0x2b0cf38253faaedc, 0x10df9188233a9fd6,
364       0x3a10033880138b59, 0x5fb0b0d23948e80f, 0x9e76f7b02fbf5350,
365       0x0816052304b1a985, 0x30c9880db41fd218, 0x14aa399b65e20f28,
366       0xe1454a8cace787b4, 0x325ac971b6c6f0f5, 0x716b1aa2784f3d36,
367       0x3d5ce14accfd144f, 0x6c0c97710f651792, 0xbc5b0f59fb333532,
368       0x2a90a7d2140470bc, 0x8da269f55c1e1c8d, 0xcfc37143895792ca,
369       0xbe21eab1f30b238f, 0x8c47229dee4d65fd, 0x5743614ed1ed7d54,
370       0x351372a99e9c476e, 0x2bd5ea15e5db085f, 0x6925fde46e0af4ca,
371       0xed3eda2bdc1f45bd, 0xdef68c68d460fa6e, 0xe42a0de76253e2b5,
372       0x4e5176dcbc29c305, 0xbfd85fba9f810f6e, 0x76a5a2a9beb815c6,
373       0x01edc4ddceaf414c, 0xa4e98904b4bb3b4b, 0x00bd63ac7d2f1ddd,
374       0xb8491fe6e998ddbb, 0xb386a3463dda6800, 0x0081887688871619,
375       0x33d394b3344e9a38, 0x815dba65a3a8baf9, 0x4232f6ec02c2fd1a,
376       0xb5cff603edd20834, 0x580189243f687663, 0xa8d5a2cbdc27fe99,
377       0x725d881693fa0131, 0xa2be2c13db2c7ac5, 0x7b6a9614b509fd78,
378       0xb6b136d71e717636, 0x660f1a71aff046ea, 0x0ba10ae346c8ec9e,
379       0xe66dde53e3145b41, 0x3b18288c88c26be6, 0x4d9d9d2ff02db933,
380       0x4167da8c70f46e8a, 0xf183beef8c6318b4, 0x4d889e1e71eeeef1,
381       0x7175c71ad6689b6b, 0xfb9e42beacd1b7dd, 0xc33d0e91b29b5e0d,
382       0xd39b83291ce47922, 0xc4d570fb8493d12e, 0x23d5a5724f424ae6,
383       0x5245f161876b6616, 0x38d77dbd21ab578d, 0x9c3423311f4ecbfe,
384       0x76fe31389bacd9d5,
385   };
386 
387   ExplicitSeedSeq seed_sequence{12, 34, 56};
388   randen_u64 engine(seed_sequence);
389 #if UPDATE_GOLDEN
390   (void)kGolden;  // Silence warning.
391   for (size_t i = 0; i < kNumGoldenOutputs; ++i) {
392     printf("0x%016lx, ", engine());
393     if (i % 3 == 2) {
394       printf("\n");
395     }
396   }
397   printf("\n\n\n");
398 #else
399   for (const auto& elem : kGolden) {
400     EXPECT_EQ(elem, engine());
401   }
402   engine.seed(seed_sequence);
403   for (const auto& elem : kGolden) {
404     EXPECT_EQ(elem, engine());
405   }
406 #endif
407 }
408 
TEST(RandenTest,VerifyGoldenRanden32Default)409 TEST(RandenTest, VerifyGoldenRanden32Default) {
410   constexpr uint64_t kGolden[2 * kNumGoldenOutputs] = {
411       0x4e433977, 0xc3c14f13, 0xd90410ee, 0xdda9f47c, 0x7fd8ca10, 0x887bf308,
412       0x45c72912, 0xf0b780f5, 0x7696599f, 0x15dbb1d3, 0xff3c6d59, 0x30ec63ba,
413       0x6f7f20a6, 0xb29f7360, 0x6f49a54c, 0x02808a31, 0xd5c8e50e, 0x3b8feaf9,
414       0x3fd9de8a, 0x9cbf605e, 0x78183bbb, 0xc970ae1a, 0x56301ed5, 0xd8b2ffd3,
415       0x0fc73c37, 0xf4b327fe, 0xeb8f9a19, 0xcdfd8d76, 0x91420c9d, 0xc3a506eb,
416       0x3eff9556, 0xd5af05dd, 0x8f83c4a1, 0x48db1bb7, 0x0d6bfe8c, 0x7023920e,
417       0x34956d42, 0x58d35758, 0x6b87b840, 0xed1ef4c2, 0x3e0b2df3, 0x8eef32a2,
418       0x431154fc, 0x497cabf3, 0x70029a8b, 0x4e243705, 0xf090e5ea, 0xd88b5749,
419       0xa970692f, 0xc651a582, 0xbb6342f5, 0x78fcec2c, 0x612f55db, 0x463cb745,
420       0x1816afe3, 0x352ee4ad, 0xc101da7e, 0x026ff374, 0x1c3de851, 0x811ef082,
421       0x04c4fa59, 0x6f7e6167, 0x992d58fc, 0xa0660379, 0xa3b795c7, 0x04b0a374,
422       0x685da798, 0x915f3445, 0xc76571ce, 0x26802a8a, 0x33ce1882, 0x46633525,
423       0xa24dc738, 0xb9fdefb4, 0x4d6e6c51, 0x5588ba3a, 0xd35f1956, 0xa2101a42,
424       0xe200f5fd, 0x607195a5, 0xf3290764, 0x7e100308, 0x759c0709, 0xe1e5e03c,
425       0x5da6606f, 0x082572cc, 0x99e432f1, 0xcbcf5853, 0x8335d8f1, 0xe8a2be4f,
426       0xcbfee8f2, 0x0904469a, 0x6daecd51, 0xf08bd31b, 0xa69da69a, 0x08e8a1f1,
427       0xad57bff5, 0x6542a20a, 0x053d6b46, 0x2e9705bb, 0x0713c391, 0xda2fc9db,
428       0x213b6ffb, 0x78e3a810, 0xdd85f8a6, 0xdc16a59c, 0xcd55781f, 0xc0932718,
429       0x2b20bfe5, 0xb9bfb29c, 0xbe0f2f9c, 0xb97289c1, 0x03a892d4, 0xc0a2a0e4,
430       0x4771435b, 0x5524bb83, 0x39d1a750, 0x8265da3d, 0x8d1b78c5, 0xff4af3ab,
431       0x4bcad77f, 0xf0ec5f42, 0x27495189, 0x66e455f6, 0xb57e3270, 0xc82d3120,
432       0xc22596e3, 0x3424e47d, 0x9ccedcdd, 0xbc0c9512, 0xafc4dcbf, 0xc191c595,
433       0x2bb70939, 0x120392bd, 0xa6cd6ab4, 0x7f90650e, 0x32695ad3, 0x72874918,
434       0xa7917eb0, 0xa7c8fac5, 0x18be0361, 0xd088cb94, 0x9c7c1ce5, 0x7c1bf983,
435       0x58e1e79e, 0xe2e991fa, 0xfd28c4ad, 0x78565cde, 0xf98bafad, 0x7351b9fe,
436       0xb08c96bf, 0x2a9eac28, 0x96cb2225, 0x6c4f1796, 0x1bab87e0, 0x13a68586,
437       0xa0501971, 0x64c6de5a, 0xcac70991, 0x30537425, 0xc6c532b7, 0x01590d9d,
438       0x8ec720dc, 0x7e05e3aa, 0x54e3e63f, 0x74a07d9c, 0x8f3bc1d2, 0x73818438,
439       0x67be3acb, 0x26ffdc50, 0x561f255f, 0x6bcdf185, 0xcf99b1c6, 0xa0eaf2e1,
440       0x34f68604, 0x171df819, 0x65683e5a, 0x7ea5a216, 0x75ba1cea, 0x5d1cb020,
441       0xd2123fdf, 0x957f38cb, 0xf80de02f, 0xba6364ef, 0x41d452ee, 0x606e0a0e,
442       0xde82f7a2, 0x892d8317, 0x50f7b43e, 0xe707b1db, 0x766fcf5b, 0x4eb28826,
443       0xe80a0951, 0x5a362d56, 0x16527d78, 0x6ee217df, 0xba6b23dd, 0xf6737962,
444       0x7d4076ca, 0x443e6385, 0x048adfeb, 0x790d9a5f, 0x151ee94d, 0xd796b052,
445       0x12b04a03, 0x033ed95c, 0x4893da5d, 0x8b833ff8, 0xbb15eab9, 0x3d6724b1,
446       0x5061ca76, 0x9877c422, 0xadf74fb3, 0xd68d6810, 0xe30ce989, 0x42e5352f,
447       0x7431fde7, 0x265b565a, 0x58df4b8b, 0x3cdbf7e3, 0x6d3e8779, 0x2922a47f,
448       0x65b37f88, 0x52d2242f, 0x2958d6b5, 0x5d836d6e, 0x566d5e26, 0x29d40f00,
449       0x124b14a0, 0x288db0e1, 0xb7d9c1b6, 0x6c056608, 0xb8f19d32, 0x0b9471bd,
450       0x4faa6c9d, 0x8fb94650, 0x4540251c, 0x8943a946, 0x144a09e0, 0xfd1fe27d,
451       0xda141bda, 0xea6ac458, 0x633fce36, 0x8048f217, 0xade74d31, 0xfeda1384,
452       0x2ff7612f, 0x4334b8b0, 0x5227e216, 0xdbc8441f, 0x3605c85b, 0x096d119a,
453       0x21b7d7d0, 0x2b72b31c};
454 
455   randen_u32 engine;
456 #if UPDATE_GOLDEN
457   (void)kGolden;  // Silence warning.
458   for (size_t i = 0; i < 2 * kNumGoldenOutputs; ++i) {
459     printf("0x%08x, ", engine());
460     if (i % 6 == 5) {
461       printf("\n");
462     }
463   }
464   printf("\n\n\n");
465 #else
466   for (const auto& elem : kGolden) {
467     EXPECT_EQ(elem, engine());
468   }
469   engine.seed();
470   for (const auto& elem : kGolden) {
471     EXPECT_EQ(elem, engine());
472   }
473 #endif
474 }
475 
TEST(RandenTest,VerifyGoldenRanden32Seeded)476 TEST(RandenTest, VerifyGoldenRanden32Seeded) {
477   constexpr uint64_t kGolden[2 * kNumGoldenOutputs] = {
478       0x94d3dcd5, 0x83a9e58f, 0xd97949fb, 0x70bbdff3, 0x7471c1b4, 0x0438481f,
479       0xe5fb5930, 0x34fdc58e, 0x2a937d17, 0xceee4f2d, 0xe432aea9, 0xb5a26a68,
480       0x3fb51740, 0x8b64774a, 0x74249c74, 0xd89ac1fc, 0x23fc3fdf, 0x03910d1d,
481       0x78aa897f, 0xd38f6308, 0x615f7e44, 0x0ee8f0f5, 0xf8279d52, 0x98f5a53d,
482       0x25938d0e, 0xb403f52c, 0x6ea6e838, 0x24007299, 0x6190fa61, 0xd3a79124,
483       0x7a7b4f80, 0xaaedd3df, 0x05deaf6e, 0xc6eacabe, 0x790edf4d, 0xb7967dd8,
484       0xe049d279, 0x9a0a8e67, 0xaebc23e7, 0x0494f606, 0x7bc3e0ee, 0x598dcd68,
485       0x02d452a1, 0x010ac818, 0x60aa2842, 0x6407c871, 0x486f93a0, 0x5a56e276,
486       0xd46a8f02, 0xc887a399, 0xfe93b740, 0x9e1e6100, 0x0f8901f6, 0x12d02e33,
487       0x47e790b7, 0xc39ca52b, 0x11e82e61, 0xb0b0a2fa, 0xa303806a, 0x1542d841,
488       0x7d6e9d86, 0x1fe659fd, 0x746541ac, 0xb8c90d80, 0x669ddc94, 0x239d56a5,
489       0x8123d13c, 0xd40db57c, 0x153a0db0, 0x3abc2414, 0x30cb8d61, 0x9bad6656,
490       0xee3f4bbc, 0x0bd1fb90, 0x079b4e42, 0x8f0b4d7e, 0xee59e793, 0xfa0fb0e0,
491       0x3e071100, 0x51080b28, 0x5081cc15, 0x2c4b9e71, 0xde4941df, 0xbe10ed49,
492       0x4b1b0d37, 0xf8eaac9d, 0x4605e139, 0x4bcce4b5, 0x6765dda6, 0xa64722b7,
493       0x8ca28ab5, 0xb9377d73, 0xa8ccc1af, 0x779fad81, 0x1ffd3ba7, 0x65cb3ee6,
494       0x7862836f, 0xd74e7908, 0x4c3f25bf, 0xd05b9c58, 0x93579827, 0x2ba93a46,
495       0xf05420ce, 0xd81530af, 0x15478621, 0xec06cea2, 0x796d65ad, 0x4b1798a6,
496       0x3a6f6fa6, 0xf142f3fb, 0xe237b560, 0x002b7bf7, 0xef65b4f8, 0xf47f2605,
497       0x17effc18, 0x9804ec55, 0xb7d481cd, 0xaed3d7f8, 0x1ce338d1, 0x5651c24c,
498       0x8bf0a3c6, 0x3e7a3820, 0x14534aed, 0x6796a7b6, 0x8358460f, 0x0d0f3b84,
499       0x00b19524, 0x0fa5fe76, 0x53faaedc, 0x2b0cf382, 0x233a9fd6, 0x10df9188,
500       0x80138b59, 0x3a100338, 0x3948e80f, 0x5fb0b0d2, 0x2fbf5350, 0x9e76f7b0,
501       0x04b1a985, 0x08160523, 0xb41fd218, 0x30c9880d, 0x65e20f28, 0x14aa399b,
502       0xace787b4, 0xe1454a8c, 0xb6c6f0f5, 0x325ac971, 0x784f3d36, 0x716b1aa2,
503       0xccfd144f, 0x3d5ce14a, 0x0f651792, 0x6c0c9771, 0xfb333532, 0xbc5b0f59,
504       0x140470bc, 0x2a90a7d2, 0x5c1e1c8d, 0x8da269f5, 0x895792ca, 0xcfc37143,
505       0xf30b238f, 0xbe21eab1, 0xee4d65fd, 0x8c47229d, 0xd1ed7d54, 0x5743614e,
506       0x9e9c476e, 0x351372a9, 0xe5db085f, 0x2bd5ea15, 0x6e0af4ca, 0x6925fde4,
507       0xdc1f45bd, 0xed3eda2b, 0xd460fa6e, 0xdef68c68, 0x6253e2b5, 0xe42a0de7,
508       0xbc29c305, 0x4e5176dc, 0x9f810f6e, 0xbfd85fba, 0xbeb815c6, 0x76a5a2a9,
509       0xceaf414c, 0x01edc4dd, 0xb4bb3b4b, 0xa4e98904, 0x7d2f1ddd, 0x00bd63ac,
510       0xe998ddbb, 0xb8491fe6, 0x3dda6800, 0xb386a346, 0x88871619, 0x00818876,
511       0x344e9a38, 0x33d394b3, 0xa3a8baf9, 0x815dba65, 0x02c2fd1a, 0x4232f6ec,
512       0xedd20834, 0xb5cff603, 0x3f687663, 0x58018924, 0xdc27fe99, 0xa8d5a2cb,
513       0x93fa0131, 0x725d8816, 0xdb2c7ac5, 0xa2be2c13, 0xb509fd78, 0x7b6a9614,
514       0x1e717636, 0xb6b136d7, 0xaff046ea, 0x660f1a71, 0x46c8ec9e, 0x0ba10ae3,
515       0xe3145b41, 0xe66dde53, 0x88c26be6, 0x3b18288c, 0xf02db933, 0x4d9d9d2f,
516       0x70f46e8a, 0x4167da8c, 0x8c6318b4, 0xf183beef, 0x71eeeef1, 0x4d889e1e,
517       0xd6689b6b, 0x7175c71a, 0xacd1b7dd, 0xfb9e42be, 0xb29b5e0d, 0xc33d0e91,
518       0x1ce47922, 0xd39b8329, 0x8493d12e, 0xc4d570fb, 0x4f424ae6, 0x23d5a572,
519       0x876b6616, 0x5245f161, 0x21ab578d, 0x38d77dbd, 0x1f4ecbfe, 0x9c342331,
520       0x9bacd9d5, 0x76fe3138,
521   };
522 
523   ExplicitSeedSeq seed_sequence{12, 34, 56};
524   randen_u32 engine(seed_sequence);
525 #if UPDATE_GOLDEN
526   (void)kGolden;  // Silence warning.
527   for (size_t i = 0; i < 2 * kNumGoldenOutputs; ++i) {
528     printf("0x%08x, ", engine());
529     if (i % 6 == 5) {
530       printf("\n");
531     }
532   }
533   printf("\n\n\n");
534 #else
535   for (const auto& elem : kGolden) {
536     EXPECT_EQ(elem, engine());
537   }
538   engine.seed(seed_sequence);
539   for (const auto& elem : kGolden) {
540     EXPECT_EQ(elem, engine());
541   }
542 #endif
543 }
544 
TEST(RandenTest,VerifyGoldenFromDeserializedEngine)545 TEST(RandenTest, VerifyGoldenFromDeserializedEngine) {
546   constexpr uint64_t kGolden[kNumGoldenOutputs] = {
547       0x067f9f9ab919657a, 0x0534605912988583, 0x8a303f72feaa673f,
548       0x77b7fd747909185c, 0xd9af90403c56d891, 0xd939c6cb204d14b5,
549       0x7fbe6b954a47b483, 0x8b31a47cc34c768d, 0x3a9e546da2701a9c,
550       0x5246539046253e71, 0x417191ffb2a848a1, 0x7b1c7bf5a5001d09,
551       0x9489b15d194f2361, 0xfcebdeea3bcd2461, 0xd643027c854cec97,
552       0x5885397f91e0d21c, 0x53173b0efae30d58, 0x1c9c71168449fac1,
553       0xe358202b711ed8aa, 0x94e3918ed1d8227c, 0x5bb4e251450144cf,
554       0xb5c7a519b489af3b, 0x6f8b560b1f7b3469, 0xfde11dd4a1c74eef,
555       0x33383d2f76457dcf, 0x3060c0ec6db9fce1, 0x18f451fcddeec766,
556       0xe73c5d6b9f26da2a, 0x8d4cc566671b32a4, 0xb8189b73776bc9ff,
557       0x497a70f9caf0bc23, 0x23afcc509791dcea, 0x18af70dc4b27d306,
558       0xd3853f955a0ce5b9, 0x441db6c01a0afb17, 0xd0136c3fb8e1f13f,
559       0x5e4fd6fc2f33783c, 0xe0d24548adb5da51, 0x0f4d8362a7d3485a,
560       0x9f572d68270fa563, 0x6351fbc823024393, 0xa66dbfc61810e9ab,
561       0x0ff17fc14b651af8, 0xd74c55dafb99e623, 0x36303bc1ad85c6c2,
562       0x4920cd6a2af7e897, 0x0b8848addc30fecd, 0x9e1562eda6488e93,
563       0x197553807d607828, 0xbef5eaeda5e21235, 0x18d91d2616aca527,
564       0xb7821937f5c873cd, 0x2cd4ae5650dbeefc, 0xb35a64376f75ffdf,
565       0x9226d414d647fe07, 0x663f3db455bbb35e, 0xa829eead6ae93247,
566       0x7fd69c204dd0d25f, 0xbe1411f891c9acb1, 0xd476f34a506d5f11,
567       0xf423d2831649c5ca, 0x1e503962951abd75, 0xeccc9e8b1e34b537,
568       0xb11a147294044854, 0xc4cf27f0abf4929d, 0xe9193abf6fa24c8c,
569       0xa94a259e3aba8808, 0x21dc414197deffa3, 0xa2ae211d1ff622ae,
570       0xfe3995c46be5a4f4, 0xe9984c284bf11128, 0xcb1ce9d2f0851a80,
571       0x42fee17971d87cd8, 0xac76a98d177adc88, 0xa0973b3dedc4af6f,
572       0xdf56d6bbcb1b8e86, 0xf1e6485f407b11c9, 0x2c63de4deccb15c0,
573       0x6fe69db32ed4fad7, 0xaa51a65f84bca1f1, 0x242f2ee81d608afc,
574       0x8eb88b2b69fc153b, 0x22c20098baf73fd1, 0x57759466f576488c,
575       0x075ca562cea1be9d, 0x9a74814d73d28891, 0x73d1555fc02f4d3d,
576       0xc17f8f210ee89337, 0x46cca7999eaeafd4, 0x5db8d6a327a0d8ac,
577       0xb79b4f93c738d7a1, 0x9994512f0036ded1, 0xd3883026f38747f4,
578       0xf31f7458078d097c, 0x736ce4d480680669, 0x7a496f4c7e1033e3,
579       0xecf85bf297fbc68c, 0x9e37e1d0f24f3c4e, 0x15b6e067ca0746fc,
580       0xdd4a39905c5db81c, 0xb5dfafa7bcfdf7da, 0xca6646fb6f92a276,
581       0x1c6b35f363ef0efd, 0x6a33d06037ad9f76, 0x45544241afd8f80f,
582       0x83f8d83f859c90c5, 0x22aea9c5365e8c19, 0xfac35b11f20b6a6a,
583       0xd1acf49d1a27dd2f, 0xf281cd09c4fed405, 0x076000a42cd38e4f,
584       0x6ace300565070445, 0x463a62781bddc4db, 0x1477126b46b569ac,
585       0x127f2bb15035fbb8, 0xdfa30946049c04a8, 0x89072a586ba8dd3e,
586       0x62c809582bb7e74d, 0x22c0c3641406c28b, 0x9b66e36c47ff004d,
587       0xb9cd2c7519653330, 0x18608d79cd7a598d, 0x92c0bd1323e53e32,
588       0x887ff00de8524aa5, 0xa074410b787abd10, 0x18ab41b8057a2063,
589       0x1560abf26bc5f987};
590 
591 #if UPDATE_GOLDEN
592   (void)kGolden;  // Silence warning.
593   std::seed_seq seed_sequence{1, 2, 3, 4, 5};
594   randen_u64 engine(seed_sequence);
595   std::ostringstream stream;
596   stream << engine;
597   auto str = stream.str();
598   printf("%s\n\n", str.c_str());
599   for (size_t i = 0; i < kNumGoldenOutputs; ++i) {
600     printf("0x%016lx, ", engine());
601     if (i % 3 == 2) {
602       printf("\n");
603     }
604   }
605   printf("\n\n\n");
606 #else
607   randen_u64 engine;
608   std::istringstream stream(
609       "0 0 9824501439887287479 3242284395352394785 243836530774933777 "
610       "4047941804708365596 17165468127298385802 949276103645889255 "
611       "10659970394998657921 1657570836810929787 11697746266668051452 "
612       "9967209969299905230 14140390331161524430 7383014124183271684 "
613       "13146719127702337852 13983155220295807171 11121125587542359264 "
614       "195757810993252695 17138580243103178492 11326030747260920501 "
615       "8585097322474965590 18342582839328350995 15052982824209724634 "
616       "7321861343874683609 1806786911778767826 10100850842665572955 "
617       "9249328950653985078 13600624835326909759 11137960060943860251 "
618       "10208781341792329629 9282723971471525577 16373271619486811032 32");
619   stream >> engine;
620   for (const auto& elem : kGolden) {
621     EXPECT_EQ(elem, engine());
622   }
623 #endif
624 }
625 
TEST(RandenTest,IsFastOrSlow)626 TEST(RandenTest, IsFastOrSlow) {
627   // randen_engine typically costs ~5ns per value for the optimized code paths,
628   // and the ~1000ns per value for slow code paths.  However when running under
629   // msan, asan, etc. it can take much longer.
630   //
631   // The estimated operation time is something like:
632   //
633   // linux, optimized ~5ns
634   // ppc, optimized ~7ns
635   // nacl (slow), ~1100ns
636   //
637   // `kCount` is chosen below so that, in debug builds and without hardware
638   // acceleration, the test (assuming ~1us per call) should finish in ~0.1s
639   static constexpr size_t kCount = 100000;
640   randen_u64 engine;
641   randen_u64::result_type sum = 0;
642   auto start = absl::GetCurrentTimeNanos();
643   for (int i = 0; i < kCount; i++) {
644     sum += engine();
645   }
646   auto duration = absl::GetCurrentTimeNanos() - start;
647 
648   ABSL_INTERNAL_LOG(INFO, absl::StrCat(static_cast<double>(duration) /
649                                            static_cast<double>(kCount),
650                                        "ns"));
651 
652   EXPECT_GT(sum, 0);
653   EXPECT_GE(duration, kCount);  // Should be slower than 1ns per call.
654 }
655 
656 }  // namespace
657