1 // Copyright 2018 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/pcg_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/random/internal/explicit_seed_seq.h"
25 #include "absl/time/clock.h"
26
27 #define UPDATE_GOLDEN 0
28
29 namespace {
30
31 using absl::random_internal::ExplicitSeedSeq;
32 using absl::random_internal::pcg32_2018_engine;
33 using absl::random_internal::pcg64_2018_engine;
34
35 template <typename EngineType>
36 class PCGEngineTest : public ::testing::Test {};
37
38 using EngineTypes = ::testing::Types<pcg64_2018_engine, pcg32_2018_engine>;
39
40 TYPED_TEST_SUITE(PCGEngineTest, EngineTypes);
41
TYPED_TEST(PCGEngineTest,VerifyReseedChangesAllValues)42 TYPED_TEST(PCGEngineTest, VerifyReseedChangesAllValues) {
43 using engine_type = TypeParam;
44 using result_type = typename engine_type::result_type;
45
46 const size_t kNumOutputs = 16;
47 engine_type engine;
48
49 // MSVC emits error 2719 without the use of std::ref below.
50 // * formal parameter with __declspec(align('#')) won't be aligned
51
52 {
53 std::seed_seq seq1{1, 2, 3, 4, 5, 6, 7};
54 engine.seed(seq1);
55 }
56 result_type a[kNumOutputs];
57 std::generate(std::begin(a), std::end(a), std::ref(engine));
58
59 {
60 std::random_device rd;
61 std::seed_seq seq2{rd(), rd(), rd()};
62 engine.seed(seq2);
63 }
64 result_type b[kNumOutputs];
65 std::generate(std::begin(b), std::end(b), std::ref(engine));
66
67 // Verify that two uncorrelated values have ~50% of there bits in common. Use
68 // a 10% margin-of-error to reduce flakiness.
69 size_t changed_bits = 0;
70 size_t unchanged_bits = 0;
71 size_t total_set = 0;
72 size_t total_bits = 0;
73 size_t equal_count = 0;
74 for (size_t i = 0; i < kNumOutputs; ++i) {
75 equal_count += (a[i] == b[i]) ? 1 : 0;
76 std::bitset<sizeof(result_type) * 8> bitset(a[i] ^ b[i]);
77 changed_bits += bitset.count();
78 unchanged_bits += bitset.size() - bitset.count();
79
80 std::bitset<sizeof(result_type) * 8> a_set(a[i]);
81 std::bitset<sizeof(result_type) * 8> b_set(b[i]);
82 total_set += a_set.count() + b_set.count();
83 total_bits += 2 * 8 * sizeof(result_type);
84 }
85 // On average, half the bits are changed between two calls.
86 EXPECT_LE(changed_bits, 0.60 * (changed_bits + unchanged_bits));
87 EXPECT_GE(changed_bits, 0.40 * (changed_bits + unchanged_bits));
88
89 // verify using a quick normal-approximation to the binomial.
90 EXPECT_NEAR(total_set, total_bits * 0.5, 4 * std::sqrt(total_bits))
91 << "@" << total_set / static_cast<double>(total_bits);
92
93 // Also, A[i] == B[i] with probability (1/range) * N.
94 // Give this a pretty wide latitude, though.
95 const double kExpected = kNumOutputs / (1.0 * sizeof(result_type) * 8);
96 EXPECT_LE(equal_count, 1.0 + kExpected);
97 }
98
99 // Number of values that needs to be consumed to clean two sizes of buffer
100 // and trigger third refresh. (slightly overestimates the actual state size).
101 constexpr size_t kTwoBufferValues = 16;
102
TYPED_TEST(PCGEngineTest,VerifyDiscard)103 TYPED_TEST(PCGEngineTest, VerifyDiscard) {
104 using engine_type = TypeParam;
105
106 for (size_t num_used = 0; num_used < kTwoBufferValues; ++num_used) {
107 engine_type engine_used;
108 for (size_t i = 0; i < num_used; ++i) {
109 engine_used();
110 }
111
112 for (size_t num_discard = 0; num_discard < kTwoBufferValues;
113 ++num_discard) {
114 engine_type engine1 = engine_used;
115 engine_type engine2 = engine_used;
116 for (size_t i = 0; i < num_discard; ++i) {
117 engine1();
118 }
119 engine2.discard(num_discard);
120 for (size_t i = 0; i < kTwoBufferValues; ++i) {
121 const auto r1 = engine1();
122 const auto r2 = engine2();
123 ASSERT_EQ(r1, r2) << "used=" << num_used << " discard=" << num_discard;
124 }
125 }
126 }
127 }
128
TYPED_TEST(PCGEngineTest,StreamOperatorsResult)129 TYPED_TEST(PCGEngineTest, StreamOperatorsResult) {
130 using engine_type = TypeParam;
131
132 std::wostringstream os;
133 std::wistringstream is;
134 engine_type engine;
135
136 EXPECT_EQ(&(os << engine), &os);
137 EXPECT_EQ(&(is >> engine), &is);
138 }
139
TYPED_TEST(PCGEngineTest,StreamSerialization)140 TYPED_TEST(PCGEngineTest, StreamSerialization) {
141 using engine_type = TypeParam;
142
143 for (size_t discard = 0; discard < kTwoBufferValues; ++discard) {
144 ExplicitSeedSeq seed_sequence{12, 34, 56};
145 engine_type engine(seed_sequence);
146 engine.discard(discard);
147
148 std::stringstream stream;
149 stream << engine;
150
151 engine_type new_engine;
152 stream >> new_engine;
153 for (size_t i = 0; i < 64; ++i) {
154 EXPECT_EQ(engine(), new_engine()) << " " << i;
155 }
156 }
157 }
158
159 constexpr size_t kNumGoldenOutputs = 127;
160
161 // This test is checking if randen_engine is meets interface requirements
162 // defined in [rand.req.urbg].
TYPED_TEST(PCGEngineTest,RandomNumberEngineInterface)163 TYPED_TEST(PCGEngineTest, RandomNumberEngineInterface) {
164 using engine_type = TypeParam;
165
166 using E = engine_type;
167 using T = typename E::result_type;
168
169 static_assert(std::is_copy_constructible<E>::value,
170 "engine_type must be copy constructible");
171
172 static_assert(absl::is_copy_assignable<E>::value,
173 "engine_type must be copy assignable");
174
175 static_assert(std::is_move_constructible<E>::value,
176 "engine_type must be move constructible");
177
178 static_assert(absl::is_move_assignable<E>::value,
179 "engine_type must be move assignable");
180
181 static_assert(std::is_same<decltype(std::declval<E>()()), T>::value,
182 "return type of operator() must be result_type");
183
184 // Names after definition of [rand.req.urbg] in C++ standard.
185 // e us a value of E
186 // v is a lvalue of E
187 // x, y are possibly const values of E
188 // s is a value of T
189 // q is a value satisfying requirements of seed_sequence
190 // z is a value of type unsigned long long
191 // os is a some specialization of basic_ostream
192 // is is a some specialization of basic_istream
193
194 E e, v;
195 const E x, y;
196 T s = 1;
197 std::seed_seq q{1, 2, 3};
198 unsigned long long z = 1; // NOLINT(runtime/int)
199 std::wostringstream os;
200 std::wistringstream is;
201
202 E{};
203 E{x};
204 E{s};
205 E{q};
206
207 e.seed();
208
209 // MSVC emits error 2718 when using EXPECT_EQ(e, x)
210 // * actual parameter with __declspec(align('#')) won't be aligned
211 EXPECT_TRUE(e == x);
212
213 e.seed(q);
214 {
215 E tmp(q);
216 EXPECT_TRUE(e == tmp);
217 }
218
219 e();
220 {
221 E tmp(q);
222 EXPECT_TRUE(e != tmp);
223 }
224
225 e.discard(z);
226
227 static_assert(std::is_same<decltype(x == y), bool>::value,
228 "return type of operator== must be bool");
229
230 static_assert(std::is_same<decltype(x != y), bool>::value,
231 "return type of operator== must be bool");
232 }
233
TYPED_TEST(PCGEngineTest,RandenEngineSFINAETest)234 TYPED_TEST(PCGEngineTest, RandenEngineSFINAETest) {
235 using engine_type = TypeParam;
236 using result_type = typename engine_type::result_type;
237
238 {
239 engine_type engine(result_type(1));
240 engine.seed(result_type(1));
241 }
242
243 {
244 result_type n = 1;
245 engine_type engine(n);
246 engine.seed(n);
247 }
248
249 {
250 engine_type engine(1);
251 engine.seed(1);
252 }
253
254 {
255 int n = 1;
256 engine_type engine(n);
257 engine.seed(n);
258 }
259
260 {
261 std::seed_seq seed_seq;
262 engine_type engine(seed_seq);
263 engine.seed(seed_seq);
264 }
265
266 {
267 engine_type engine{std::seed_seq()};
268 engine.seed(std::seed_seq());
269 }
270 }
271
272 // ------------------------------------------------------------------
273 // Stability tests for pcg64_2018_engine
274 // ------------------------------------------------------------------
TEST(PCG642018EngineTest,VerifyGolden)275 TEST(PCG642018EngineTest, VerifyGolden) {
276 constexpr uint64_t kGolden[kNumGoldenOutputs] = {
277 0x01070196e695f8f1, 0x703ec840c59f4493, 0xe54954914b3a44fa,
278 0x96130ff204b9285e, 0x7d9fdef535ceb21a, 0x666feed42e1219a0,
279 0x981f685721c8326f, 0xad80710d6eab4dda, 0xe202c480b037a029,
280 0x5d3390eaedd907e2, 0x0756befb39c6b8aa, 0x1fb44ba6634d62a3,
281 0x8d20423662426642, 0x34ea910167a39fb4, 0x93010b43a80d0ab6,
282 0x663db08a98fc568a, 0x720b0a1335956fae, 0x2c35483e31e1d3ba,
283 0x429f39776337409d, 0xb46d99e638687344, 0x105370b96aedcaee,
284 0x3999e92f811cff71, 0xd230f8bcb591cfc9, 0x0dce3db2ba7bdea5,
285 0xcf2f52c91eec99af, 0x2bc7c24a8b998a39, 0xbd8af1b0d599a19c,
286 0x56bc45abc66059f5, 0x170a46dc170f7f1e, 0xc25daf5277b85fad,
287 0xe629c2e0c948eadb, 0x1720a796915542ed, 0x22fb0caa4f909951,
288 0x7e0c0f4175acd83d, 0xd9fcab37ff2a860c, 0xab2280fb2054bad1,
289 0x58e8a06f37fa9e99, 0xc3a52a30b06528c7, 0x0175f773a13fc1bd,
290 0x731cfc584b00e840, 0x404cc7b2648069cb, 0x5bc29153b0b7f783,
291 0x771310a38cc999d1, 0x766a572f0a71a916, 0x90f450fb4fc48348,
292 0xf080ea3e1c7b1a0d, 0x15471a4507d66a44, 0x7d58e55a78f3df69,
293 0x0130a094576ac99c, 0x46669cb2d04b1d87, 0x17ab5bed20191840,
294 0x95b177d260adff3e, 0x025fb624b6ee4c07, 0xb35de4330154a95f,
295 0xe8510fff67e24c79, 0x132c3cbcd76ed2d3, 0x35e7cc145a093904,
296 0x9f5b5b5f81583b79, 0x3ee749a533966233, 0x4af85886cdeda8cd,
297 0x0ca5380ecb3ef3aa, 0x4f674eb7661d3192, 0x88a29aad00cd7733,
298 0x70b627ca045ffac6, 0x5912b43ea887623d, 0x95dc9fc6f62cf221,
299 0x926081a12a5c905b, 0x9c57d4cd7dfce651, 0x85ab2cbf23e3bb5d,
300 0xc5cd669f63023152, 0x3067be0fad5d898e, 0x12b56f444cb53d05,
301 0xbc2e5a640c3434fc, 0x9280bff0e4613fe1, 0x98819094c528743e,
302 0x999d1c98d829df33, 0x9ff82a012dc89242, 0xf99183ed39c8be94,
303 0xf0f59161cd421c55, 0x3c705730c2f6c48d, 0x66ad85c6e9278a61,
304 0x2a3428e4a428d5d0, 0x79207d68fd04940d, 0xea7f2b402edc8430,
305 0xa06b419ac857f63b, 0xcb1dd0e6fbc47e1c, 0x4f55229200ada6a4,
306 0x9647b5e6359c927f, 0x30bf8f9197c7efe5, 0xa79519529cc384d0,
307 0xbb22c4f339ad6497, 0xd7b9782f59d14175, 0x0dff12fff2ec0118,
308 0xa331ad8305343a7c, 0x48dad7e3f17e0862, 0x324c6fb3fd3c9665,
309 0xf0e4350e7933dfc4, 0x7ccda2f30b8b03b6, 0xa0afc6179005de40,
310 0xee65da6d063b3a30, 0xb9506f42f2bfe87a, 0xc9a2e26b0ef5baa0,
311 0x39fa9d4f495011d6, 0xbecc21a45d023948, 0x6bf484c6593f737f,
312 0x8065e0070cadc3b7, 0x9ef617ed8d419799, 0xac692cf8c233dd15,
313 0xd2ed87583c4ebb98, 0xad95ba1bebfedc62, 0x9b60b160a8264e43,
314 0x0bc8c45f71fcf25b, 0x4a78035cdf1c9931, 0x4602dc106667e029,
315 0xb335a3c250498ac8, 0x0256ebc4df20cab8, 0x0c61efd153f0c8d9,
316 0xe5d0150a4f806f88, 0x99d6521d351e7d87, 0x8d4888c9f80f4325,
317 0x106c5735c1ba868d, 0x73414881b880a878, 0x808a9a58a3064751,
318 0x339a29f3746de3d5, 0x5410d7fa4f873896, 0xd84623c81d7b8a03,
319 0x1f7c7e7a7f47f462,
320 };
321
322 pcg64_2018_engine engine(0);
323 #if UPDATE_GOLDEN
324 (void)kGolden; // Silence warning.
325 for (size_t i = 0; i < kNumGoldenOutputs; ++i) {
326 printf("0x%016lx, ", engine());
327 if (i % 3 == 2) {
328 printf("\n");
329 }
330 }
331 printf("\n\n\n");
332 #else
333 for (const auto& elem : kGolden) {
334 EXPECT_EQ(elem, engine());
335 }
336 engine.seed();
337 for (const auto& elem : kGolden) {
338 EXPECT_EQ(elem, engine());
339 }
340 #endif
341 }
342
TEST(PCG642018EngineTest,VerifyGoldenSeeded)343 TEST(PCG642018EngineTest, VerifyGoldenSeeded) {
344 constexpr uint64_t kGolden[kNumGoldenOutputs] = {
345 0xb03988f1e39691ee, 0xbd2a1eb5ac31e97a, 0x8f00d6d433634d02,
346 0x1823c28d483d5776, 0x000c3ee3e1aeb74a, 0xfa82ef27a4f3df9c,
347 0xc6f382308654e454, 0x414afb1a238996c2, 0x4703a4bc252eb411,
348 0x99d64f62c8f7f654, 0xbb07ebe11a34fa44, 0x79eb06a363c06131,
349 0xf66ad3756f1c6b21, 0x130c01d5e869f457, 0x5ca2b9963aecbc81,
350 0xfef7bebc1de27e6c, 0x1d174faa5ed2cdbf, 0xd75b7a773f2bb889,
351 0xc35c872327a170a5, 0x46da6d88646a42fe, 0x4622985e0442dae2,
352 0xbe3cbd67297f1f9b, 0xe7c37b4a4798bfd1, 0x173d5dfad15a25c3,
353 0x0eb6849ba2961522, 0xb0ff7246e6700d73, 0x88cb9c42d3afa577,
354 0xb609731dbd94d917, 0xd3941cda04b40081, 0x28d140f7409bea3a,
355 0x3c96699a920a124a, 0xdb28be521958b2fd, 0x0a3f44db3d4c5124,
356 0x7ac8e60ba13b70d2, 0x75f03a41ded5195a, 0xaed10ac7c4e4825d,
357 0xb92a3b18aadb7adc, 0xda45e0081f2bca46, 0x74d39ab3753143fc,
358 0xb686038018fac9ca, 0x4cc309fe99542dbb, 0xf3e1a4fcb311097c,
359 0x58763d6fa698d69d, 0xd11c365dbecd8d60, 0x2c15d55725b1dee7,
360 0x89805f254d85658c, 0x2374c44dfc62158b, 0x9a8350fa7995328d,
361 0x198f838970cf91da, 0x96aff569562c0e53, 0xd76c8c52b7ec6e3f,
362 0x23a01cd9ae4baa81, 0x3adb366b6d02a893, 0xb3313e2a4c5b333f,
363 0x04c11230b96a5425, 0x1f7f7af04787d571, 0xaddb019365275ec7,
364 0x5c960468ccb09f42, 0x8438db698c69a44a, 0x492be1e46111637e,
365 0x9c6c01e18100c610, 0xbfe48e75b7d0aceb, 0xb5e0b89ec1ce6a00,
366 0x9d280ecbc2fe8997, 0x290d9e991ba5fcab, 0xeec5bec7d9d2a4f0,
367 0x726e81488f19150e, 0x1a6df7955a7e462c, 0x37a12d174ba46bb5,
368 0x3cdcdffd96b1b5c5, 0x2c5d5ac10661a26e, 0xa742ed18f22e50c4,
369 0x00e0ed88ff0d8a35, 0x3d3c1718cb1efc0b, 0x1d70c51ffbccbf11,
370 0xfbbb895132a4092f, 0x619d27f2fb095f24, 0x69af68200985e5c4,
371 0xbee4885f57373f8d, 0x10b7a6bfe0587e40, 0xa885e6cf2f7e5f0a,
372 0x59f879464f767550, 0x24e805d69056990d, 0x860970b911095891,
373 0xca3189954f84170d, 0x6652a5edd4590134, 0x5e1008cef76174bf,
374 0xcbd417881f2bcfe5, 0xfd49fc9d706ecd17, 0xeebf540221ebd066,
375 0x46af7679464504cb, 0xd4028486946956f1, 0xd4f41864b86c2103,
376 0x7af090e751583372, 0x98cdaa09278cb642, 0xffd42b921215602f,
377 0x1d05bec8466b1740, 0xf036fa78a0132044, 0x787880589d1ecc78,
378 0x5644552cfef33230, 0x0a97e275fe06884b, 0x96d1b13333d470b5,
379 0xc8b3cdad52d3b034, 0x091357b9db7376fd, 0xa5fe4232555edf8c,
380 0x3371bc3b6ada76b5, 0x7deeb2300477c995, 0x6fc6d4244f2849c1,
381 0x750e8cc797ca340a, 0x81728613cd79899f, 0x3467f4ee6f9aeb93,
382 0x5ef0a905f58c640f, 0x432db85e5101c98a, 0x6488e96f46ac80c2,
383 0x22fddb282625048c, 0x15b287a0bc2d4c5d, 0xa7e2343ef1f28bce,
384 0xc87ee1aa89bed09e, 0x220610107812c5e9, 0xcbdab6fcd640f586,
385 0x8d41047970928784, 0x1aa431509ec1ade0, 0xac3f0be53f518ddc,
386 0x16f4428ad81d0cbb, 0x675b13c2736fc4bb, 0x6db073afdd87e32d,
387 0x572f3ca2f1a078c6,
388 };
389
390 ExplicitSeedSeq seed_sequence{12, 34, 56};
391 pcg64_2018_engine engine(seed_sequence);
392 #if UPDATE_GOLDEN
393 (void)kGolden; // Silence warning.
394 for (size_t i = 0; i < kNumGoldenOutputs; ++i) {
395 printf("0x%016lx, ", engine());
396 if (i % 3 == 2) {
397 printf("\n");
398 }
399 }
400 printf("\n\n\n");
401 #else
402 for (const auto& elem : kGolden) {
403 EXPECT_EQ(elem, engine());
404 }
405 engine.seed(seed_sequence);
406 for (const auto& elem : kGolden) {
407 EXPECT_EQ(elem, engine());
408 }
409 #endif
410 }
411
TEST(PCG642018EngineTest,VerifyGoldenFromDeserializedEngine)412 TEST(PCG642018EngineTest, VerifyGoldenFromDeserializedEngine) {
413 constexpr uint64_t kGolden[kNumGoldenOutputs] = {
414 0xdd425b47b4113dea, 0x1b07176479d444b0, 0x6b391027586f2e42,
415 0xa166f2b15f4a2143, 0xffb6dbd7a179ee97, 0xb2c00035365bf0b1,
416 0x8fbb518b45855521, 0xfc789a55ddf87c3b, 0x429531f0f17ff355,
417 0xbe708560d603d283, 0x5bff415175c5cb6b, 0xe813491f4ad45394,
418 0xa853f4506d55880d, 0x7e538453e568172e, 0xe101f1e098ddd0ec,
419 0x6ee31266ee4c766d, 0xa8786d92d66b39d7, 0xfee622a2acf5e5b0,
420 0x5fe8e82c102fa7b3, 0x01f10be4cdb53c9d, 0xbe0545366f857022,
421 0x12e74f010a339bca, 0xb10d85ca40d5ce34, 0xe80d6feba5054875,
422 0x2b7c1ee6d567d4ee, 0x2a9cd043bfd03b66, 0x5cfc531bd239f3f1,
423 0x1c4734e4647d70f5, 0x85a8f60f006b5760, 0x6a4239ce76dca387,
424 0x8da0f86d7339335c, 0xf055b0468551374d, 0x486e8567e9bea9a0,
425 0x4cb531b8405192dd, 0xf813b1ee3157110b, 0x214c2a664a875d8e,
426 0x74531237b29b35f7, 0xa6f0267bb77a771e, 0x64b552bff54184a4,
427 0xa2d6f7af2d75b6fc, 0x460a10018e03b5ab, 0x76fd1fdcb81d0800,
428 0x76f5f81805070d9d, 0x1fb75cb1a70b289a, 0x9dfd25a022c4b27f,
429 0x9a31a14a80528e9e, 0x910dc565ddc25820, 0xd6aef8e2b0936c10,
430 0xe1773c507fe70225, 0xe027fd7aadd632bc, 0xc1fecb427089c8b8,
431 0xb5c74c69fa9dbf26, 0x71bf9b0e4670227d, 0x25f48fad205dcfdd,
432 0x905248ec4d689c56, 0x5c2b7631b0de5c9d, 0x9f2ee0f8f485036c,
433 0xfd6ce4ebb90bf7ea, 0xd435d20046085574, 0x6b7eadcb0625f986,
434 0x679d7d44b48be89e, 0x49683b8e1cdc49de, 0x4366cf76e9a2f4ca,
435 0x54026ec1cdad7bed, 0xa9a04385207f28d3, 0xc8e66de4eba074b2,
436 0x40b08c42de0f4cc0, 0x1d4c5e0e93c5bbc0, 0x19b80792e470ae2d,
437 0x6fcaaeaa4c2a5bd9, 0xa92cb07c4238438e, 0x8bb5c918a007e298,
438 0x7cd671e944874cf4, 0x88166470b1ba3cac, 0xd013d476eaeeade6,
439 0xcee416947189b3c3, 0x5d7c16ab0dce6088, 0xd3578a5c32b13d27,
440 0x3875db5adc9cc973, 0xfbdaba01c5b5dc56, 0xffc4fdd391b231c3,
441 0x2334520ecb164fec, 0x361c115e7b6de1fa, 0xeee58106cc3563d7,
442 0x8b7f35a8db25ebb8, 0xb29d00211e2cafa6, 0x22a39fe4614b646b,
443 0x92ca6de8b998506d, 0x40922fe3d388d1db, 0x9da47f1e540f802a,
444 0x811dceebf16a25db, 0xf6524ae22e0e53a9, 0x52d9e780a16eb99d,
445 0x4f504286bb830207, 0xf6654d4786bd5cc3, 0x00bd98316003a7e1,
446 0xefda054a6ab8f5f3, 0x46cfb0f4c1872827, 0xc22b316965c0f3b2,
447 0xd1a28087c7e7562a, 0xaa4f6a094b7f5cff, 0xfe2bc853a041f7da,
448 0xe9d531402a83c3ba, 0xe545d8663d3ce4dd, 0xfa2dcd7d91a13fa8,
449 0xda1a080e52a127b8, 0x19c98f1f809c3d84, 0x2cef109af4678c88,
450 0x53462accab3b9132, 0x176b13a80415394e, 0xea70047ef6bc178b,
451 0x57bca80506d6dcdf, 0xd853ba09ff09f5c4, 0x75f4df3a7ddd4775,
452 0x209c367ade62f4fe, 0xa9a0bbc74d5f4682, 0x5dfe34bada86c21a,
453 0xc2c05bbcd38566d1, 0x6de8088e348c916a, 0x6a7001c6000c2196,
454 0xd9fb51865fc4a367, 0x12f320e444ece8ff, 0x6d56f7f793d65035,
455 0x138f31b7a865f8aa, 0x58fc68b4026b9adf, 0xcd48954b79fb6436,
456 0x27dfce4a0232af87,
457 };
458
459 #if UPDATE_GOLDEN
460 (void)kGolden; // Silence warning.
461 std::seed_seq seed_sequence{1, 2, 3};
462 pcg64_2018_engine engine(seed_sequence);
463 std::ostringstream stream;
464 stream << engine;
465 auto str = stream.str();
466 printf("%s\n\n", str.c_str());
467 for (size_t i = 0; i < kNumGoldenOutputs; ++i) {
468 printf("0x%016lx, ", engine());
469 if (i % 3 == 2) {
470 printf("\n");
471 }
472 }
473 printf("\n\n\n");
474 #else
475 pcg64_2018_engine engine;
476 std::istringstream stream(
477 "2549297995355413924 4865540595714422341 6364136223846793005 "
478 "1442695040888963407 18088519957565336995 4845369368158826708");
479 stream >> engine;
480 for (const auto& elem : kGolden) {
481 EXPECT_EQ(elem, engine());
482 }
483 #endif
484 }
485
486 // ------------------------------------------------------------------
487 // Stability tests for pcg32_2018_engine
488 // ------------------------------------------------------------------
TEST(PCG322018EngineTest,VerifyGolden)489 TEST(PCG322018EngineTest, VerifyGolden) {
490 constexpr uint32_t kGolden[kNumGoldenOutputs] = {
491 0x7a7ecbd9, 0x89fd6c06, 0xae646aa8, 0xcd3cf945, 0x6204b303, 0x198c8585,
492 0x49fce611, 0xd1e9297a, 0x142d9440, 0xee75f56b, 0x473a9117, 0xe3a45903,
493 0xbce807a1, 0xe54e5f4d, 0x497d6c51, 0x61829166, 0xa740474b, 0x031912a8,
494 0x9de3defa, 0xd266dbf1, 0x0f38bebb, 0xec3c4f65, 0x07c5057d, 0xbbce03c8,
495 0xfd2ac7a8, 0xffcf4773, 0x5b10affb, 0xede1c842, 0xe22b01b7, 0xda133c8c,
496 0xaf89b0f4, 0x25d1b8bc, 0x9f625482, 0x7bfd6882, 0x2e2210c0, 0x2c8fb9a6,
497 0x42cb3b83, 0x40ce0dab, 0x644a3510, 0x36230ef2, 0xe2cb6d43, 0x1012b343,
498 0x746c6c9f, 0x36714cf8, 0xed1f5026, 0x8bbbf83e, 0xe98710f4, 0x8a2afa36,
499 0x09035349, 0x6dc1a487, 0x682b634b, 0xc106794f, 0x7dd78beb, 0x628c262b,
500 0x852fb232, 0xb153ac4c, 0x4f169d1b, 0xa69ab774, 0x4bd4b6f2, 0xdc351dd3,
501 0x93ff3c8c, 0xa30819ab, 0xff07758c, 0x5ab13c62, 0xd16d7fb5, 0xc4950ffa,
502 0xd309ae49, 0xb9677a87, 0x4464e317, 0x90dc44f1, 0xc694c1d4, 0x1d5e1168,
503 0xadf37a2d, 0xda38990d, 0x1ec4bd33, 0x36ca25ce, 0xfa0dc76a, 0x968a9d43,
504 0x6950ac39, 0xdd3276bc, 0x06d5a71e, 0x1f6f282d, 0x5c626c62, 0xdde3fc31,
505 0x152194ce, 0xc35ed14c, 0xb1f7224e, 0x47f76bb8, 0xb34fdd08, 0x7011395e,
506 0x162d2a49, 0x0d1bf09f, 0x9428a952, 0x03c5c344, 0xd3525616, 0x7816fff3,
507 0x6bceb8a8, 0x8345a081, 0x366420fd, 0x182abeda, 0x70f82745, 0xaf15ded8,
508 0xc7f52ca2, 0xa98db9c5, 0x919d99ba, 0x9c376c1c, 0xed8d34c2, 0x716ae9f5,
509 0xef062fa5, 0xee3b6c56, 0x52325658, 0x61afa9c3, 0xfdaf02f0, 0x961cf3ab,
510 0x9f291565, 0x4fbf3045, 0x0590c899, 0xde901385, 0x45005ffb, 0x509db162,
511 0x262fa941, 0x4c421653, 0x4b17c21e, 0xea0d1530, 0xde803845, 0x61bfd515,
512 0x438523ef,
513 };
514
515 pcg32_2018_engine engine(0);
516 #if UPDATE_GOLDEN
517 (void)kGolden; // Silence warning.
518 for (size_t i = 0; i < kNumGoldenOutputs; ++i) {
519 printf("0x%08x, ", engine());
520 if (i % 6 == 5) {
521 printf("\n");
522 }
523 }
524 printf("\n\n\n");
525 #else
526 for (const auto& elem : kGolden) {
527 EXPECT_EQ(elem, engine());
528 }
529 engine.seed();
530 for (const auto& elem : kGolden) {
531 EXPECT_EQ(elem, engine());
532 }
533 #endif
534 }
535
TEST(PCG322018EngineTest,VerifyGoldenSeeded)536 TEST(PCG322018EngineTest, VerifyGoldenSeeded) {
537 constexpr uint32_t kGolden[kNumGoldenOutputs] = {
538 0x60b5a64c, 0x978502f9, 0x80a75f60, 0x241f1158, 0xa4cd1dbb, 0xe7284017,
539 0x3b678da5, 0x5223ec99, 0xe4bdd5d9, 0x72190e6d, 0xe6e702c9, 0xff80c768,
540 0xcf126ed3, 0x1fbd20ab, 0x60980489, 0xbc72bf89, 0x407ac6c0, 0x00bf3c51,
541 0xf9087897, 0x172e4eb6, 0xe9e4f443, 0x1a6098bf, 0xbf44f8c2, 0xdd84a0e5,
542 0xd9a52364, 0xc0e2e786, 0x061ae2ba, 0x9facb8e3, 0x6109432d, 0xd4e0a013,
543 0xbd8eb9a6, 0x7e86c3b6, 0x629c0e68, 0x05337430, 0xb495b9f4, 0x11ccd65d,
544 0xb578db25, 0x66f1246d, 0x6ef20a7f, 0x5e429812, 0x11772130, 0xb944b5c2,
545 0x01624128, 0xa2385ab7, 0xd3e10d35, 0xbe570ec3, 0xc951656f, 0xbe8944a0,
546 0x7be41062, 0x5709f919, 0xd745feda, 0x9870b9ae, 0xb44b8168, 0x19e7683b,
547 0xded8017f, 0xc6e4d544, 0x91ae4225, 0xd6745fba, 0xb992f284, 0x65b12b33,
548 0xa9d5fdb4, 0xf105ce1a, 0x35ca1a6e, 0x2ff70dd0, 0xd8335e49, 0xfb71ddf2,
549 0xcaeabb89, 0x5c6f5f84, 0x9a811a7d, 0xbcecbbd1, 0x0f661ba0, 0x9ad93b9d,
550 0xedd23e0b, 0x42062f48, 0xd38dd7e4, 0x6cd63c9c, 0x640b98ae, 0x4bff5653,
551 0x12626371, 0x13266017, 0xe7a698d8, 0x39c74667, 0xe8fdf2e3, 0x52803bf8,
552 0x2af6895b, 0x91335b7b, 0x699e4961, 0x00a40fff, 0x253ff2b6, 0x4a6cf672,
553 0x9584e85f, 0xf2a5000c, 0x4d58aba8, 0xb8513e6a, 0x767fad65, 0x8e326f9e,
554 0x182f15a1, 0x163dab52, 0xdf99c780, 0x047282a1, 0xee4f90dd, 0xd50394ae,
555 0x6c9fd5f0, 0xb06a9194, 0x387e3840, 0x04a9487b, 0xf678a4c2, 0xd0a78810,
556 0xd502c97e, 0xd6a9b12a, 0x4accc5dc, 0x416ed53e, 0x50411536, 0xeeb89c24,
557 0x813a7902, 0x034ebca6, 0xffa52e7c, 0x7ecd3d0e, 0xfa37a0d2, 0xb1fbe2c1,
558 0xb7efc6d1, 0xefa4ccee, 0xf6f80424, 0x2283f3d9, 0x68732284, 0x94f3b5c8,
559 0xbbdeceb9,
560 };
561
562 ExplicitSeedSeq seed_sequence{12, 34, 56};
563 pcg32_2018_engine engine(seed_sequence);
564 #if UPDATE_GOLDEN
565 (void)kGolden; // Silence warning.
566 for (size_t i = 0; i < kNumGoldenOutputs; ++i) {
567 printf("0x%08x, ", engine());
568 if (i % 6 == 5) {
569 printf("\n");
570 }
571 }
572 printf("\n\n\n");
573 #else
574 for (const auto& elem : kGolden) {
575 EXPECT_EQ(elem, engine());
576 }
577 engine.seed(seed_sequence);
578 for (const auto& elem : kGolden) {
579 EXPECT_EQ(elem, engine());
580 }
581 #endif
582 }
583
TEST(PCG322018EngineTest,VerifyGoldenFromDeserializedEngine)584 TEST(PCG322018EngineTest, VerifyGoldenFromDeserializedEngine) {
585 constexpr uint64_t kGolden[kNumGoldenOutputs] = {
586 0x780f7042, 0xba137215, 0x43ab6f22, 0x0cb55f46, 0x44b2627d, 0x835597af,
587 0xea973ea1, 0x0d2abd35, 0x4fdd601c, 0xac4342fe, 0x7db7e93c, 0xe56ebcaf,
588 0x3596470a, 0x7770a9ad, 0x9b893320, 0x57db3415, 0xb432de54, 0xa02baf71,
589 0xa256aadb, 0x88921fc7, 0xa35fa6b3, 0xde3eca46, 0x605739a7, 0xa890b82b,
590 0xe457b7ad, 0x335fb903, 0xeb06790c, 0xb3c54bf6, 0x6141e442, 0xa599a482,
591 0xb78987cc, 0xc61dfe9d, 0x0f1d6ace, 0x17460594, 0x8f6a5061, 0x083dc354,
592 0xe9c337fb, 0xcfd105f7, 0x926764b6, 0x638d24dc, 0xeaac650a, 0x67d2cb9c,
593 0xd807733c, 0x205fc52e, 0xf5399e2e, 0x6c46ddcc, 0xb603e875, 0xce113a25,
594 0x3c8d4813, 0xfb584db8, 0xf6d255ff, 0xea80954f, 0x42e8be85, 0xb2feee72,
595 0x62bd8d16, 0x1be4a142, 0x97dca1a4, 0xdd6e7333, 0xb2caa20e, 0xa12b1588,
596 0xeb3a5a1a, 0x6fa5ba89, 0x077ea931, 0x8ddb1713, 0x0dd03079, 0x2c2ba965,
597 0xa77fac17, 0xc8325742, 0x8bb893bf, 0xc2315741, 0xeaceee92, 0x81dd2ee2,
598 0xe5214216, 0x1b9b8fb2, 0x01646d03, 0x24facc25, 0xd8c0e0bb, 0xa33fe106,
599 0xf34fe976, 0xb3b4b44e, 0x65618fed, 0x032c6192, 0xa9dd72ce, 0xf391887b,
600 0xf41c6a6e, 0x05c4bd6d, 0x37fa260e, 0x46b05659, 0xb5f6348a, 0x62d26d89,
601 0x39f6452d, 0xb17b30a2, 0xbdd82743, 0x38ecae3b, 0xfe90f0a2, 0xcb2d226d,
602 0xcf8a0b1c, 0x0eed3d4d, 0xa1f69cfc, 0xd7ac3ba5, 0xce9d9a6b, 0x121deb4c,
603 0x4a0d03f3, 0xc1821ed1, 0x59c249ac, 0xc0abb474, 0x28149985, 0xfd9a82ba,
604 0x5960c3b2, 0xeff00cba, 0x6073aa17, 0x25dc0919, 0x9976626e, 0xdd2ccc33,
605 0x39ecb6ec, 0xc6e15d13, 0xfac94cfd, 0x28cfd34f, 0xf2d2c32d, 0x51c23d08,
606 0x4fdb2f48, 0x97baa807, 0xf2c1004c, 0xc4ae8136, 0x71f31c94, 0x8c92d601,
607 0x36caf5cd,
608 };
609
610 #if UPDATE_GOLDEN
611 (void)kGolden; // Silence warning.
612 std::seed_seq seed_sequence{1, 2, 3};
613 pcg32_2018_engine engine(seed_sequence);
614 std::ostringstream stream;
615 stream << engine;
616 auto str = stream.str();
617 printf("%s\n\n", str.c_str());
618 for (size_t i = 0; i < kNumGoldenOutputs; ++i) {
619 printf("0x%08x, ", engine());
620 if (i % 6 == 5) {
621 printf("\n");
622 }
623 }
624 printf("\n\n\n");
625
626 EXPECT_FALSE(true);
627 #else
628 pcg32_2018_engine engine;
629 std::istringstream stream(
630 "6364136223846793005 1442695040888963407 6537028157270659894");
631 stream >> engine;
632 for (const auto& elem : kGolden) {
633 EXPECT_EQ(elem, engine());
634 }
635 #endif
636 }
637
638 } // namespace
639