TestRandom.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) Electronic Arts Inc. All rights reserved.
  3. ///////////////////////////////////////////////////////////////////////////////
  4. #ifdef _MSC_VER
  5. #pragma warning(disable: 4244) // This warning is being generated due to a bug in VC++.
  6. #endif
  7. #include <EABase/eabase.h>
  8. #include <EAStdC/EARandom.h>
  9. #include <EAStdC/EARandomDistribution.h>
  10. #include <EAStdCTest/EAStdCTest.h>
  11. #include <EATest/EATest.h>
  12. #include <EASTL/bitset.h>
  13. #ifdef _MSC_VER
  14. #pragma warning(push, 0)
  15. #pragma warning(disable: 4275) // non dll-interface class 'stdext::exception' used as base for dll-interface class 'std::bad_cast'
  16. #endif
  17. #ifndef EA_PLATFORM_ANDROID
  18. #include <algorithm>
  19. #endif
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <math.h>
  23. #if defined(_MSC_VER) && defined(EA_PLATFORM_MICROSOFT)
  24. #include <crtdbg.h>
  25. #endif
  26. #if defined(EA_PLATFORM_WINDOWS)
  27. #include <Windows.h>
  28. #endif
  29. #if EASTDC_TIME_H_AVAILABLE
  30. #include <time.h>
  31. #endif
  32. #ifdef _MSC_VER
  33. #pragma warning(pop)
  34. #pragma warning(push)
  35. #pragma warning(disable: 4365) // 'argument' : conversion from 'int' to 'uint32_t', signed/unsigned mismatch
  36. #endif
  37. using namespace EA::StdC;
  38. // Forward declarations
  39. void rt_init(int binmode);
  40. void rt_add(void* buf, int bufl);
  41. void rt_end(double* r_ent, double* r_chisq, double* r_mean, double* r_montepicalc, double* r_scc);
  42. static int TestDieHard()
  43. {
  44. int nErrorCount(0);
  45. // Write out 9MB file for DieHard tests.
  46. #if defined(EA_PLATFORM_WINDOWS) && EA_WINAPI_FAMILY_PARTITION(EA_WINAPI_PARTITION_DESKTOP)
  47. if(GetAsyncKeyState(VK_SCROLL)) // If the Scroll Lock key is alive.
  48. {
  49. // Ideally we would port the DieHard code to here, but it is not well
  50. // written for modularity. For the time being, we write out the 9MB
  51. // data file that DieHard.exe can analyze. As of this writing, DieHard.exe
  52. // is part of the EAOS UTF Research repository.
  53. {
  54. RandomLinearCongruential randomLC;
  55. FILE* pFile = fopen("RandomLinearCongruentialData.txt", "w");
  56. if(pFile)
  57. {
  58. for(uint32_t i = 0; i < 12000000; i += 4)
  59. {
  60. const uint32_t value = randomLC.RandomUint32Uniform();
  61. fwrite(&value, 1, 4, pFile);
  62. }
  63. fclose(pFile);
  64. }
  65. }
  66. {
  67. RandomMersenneTwister randomMT;
  68. FILE* pFile = fopen("RandomMersenneTwisterData.txt", "w");
  69. if(pFile)
  70. {
  71. for(uint32_t i = 0; i < 12000000; i += 4)
  72. {
  73. const uint32_t value = randomMT.RandomUint32Uniform();
  74. fwrite(&value, 1, 4, pFile);
  75. }
  76. fclose(pFile);
  77. }
  78. }
  79. }
  80. #endif
  81. return nErrorCount;
  82. }
  83. namespace
  84. {
  85. #if defined(EA_PLATFORM_DESKTOP) && !defined(EA_DEBUG)
  86. // This exists for the purpose of testing distributions. It implements a seed that is continuously
  87. // increasting and thus over the course of 0x100000000 (2^32) calls to RandomUint32Uniform returns a statistically
  88. // even distribution of bits. Note that truly random data won't behave this way and formal tests for
  89. // randomness would identify this as being not random. But that's not the purpose of this class;
  90. // the purpose is to help test if there are distribution problems in the range and distribution adapters.
  91. // Note that it's important that you do 0x100000000 calls with this or else the results of it won't
  92. // be evenly distributed as designed.
  93. class FakeIncrementingRandom
  94. {
  95. public:
  96. FakeIncrementingRandom()
  97. : mnSeed(0) {}
  98. //FakeIncrementingRandom(const FakeIncrementingRandom& x)
  99. // : mnSeed(x.mnSeed) {}
  100. //FakeIncrementingRandom& operator=(const FakeIncrementingRandom& x)
  101. // { mnSeed = x.mnSeed; return *this; }
  102. //uint32_t GetSeed() const
  103. // { return mnSeed; }
  104. //void SetSeed(uint32_t nSeed)
  105. // { mnSeed = nSeed; }
  106. //uint32_t operator()(uint32_t nLimit)
  107. // { return EA::StdC::RandomLimit(*this, nLimit); }
  108. uint32_t RandomUint32Uniform()
  109. { return mnSeed++; }
  110. protected:
  111. uint32_t mnSeed;
  112. };
  113. #endif
  114. }
  115. // TestRandom
  116. // Note that thus function itself is not meant as a comprehensive
  117. // test for randomness. Instead this function does a basic test
  118. // for randomness and then optionally writes out files to disk
  119. // for analysis by a comprehensive tool like DieHard.
  120. //
  121. int TestRandom()
  122. {
  123. int nErrorCount(0);
  124. { // Bug report regression.
  125. // User Fei Jiang reports that RandomLinearCongruential::RandomUnit32Uniform(uint32_t nLimit) returns
  126. // different values on PS3 in debug vs. debug-opt builds with SN compiler.
  127. RandomLinearCongruential rlc(UINT32_C(2474210934));
  128. uint32_t seed = rlc.GetSeed();
  129. //EA::UnitTest::Report("seed: %u\n", (unsigned)seed);
  130. EATEST_VERIFY(seed == UINT32_C(2474210934));
  131. uint32_t result = rlc.RandomUint32Uniform(57);
  132. //EA::UnitTest::Report("result: %u\n", (unsigned)result);
  133. EATEST_VERIFY(result == 23); // 743483
  134. }
  135. // Load priming
  136. // We call a function from each generator used below to minimize
  137. // an loading effects on benchmarking.
  138. int rTemp = rand();
  139. EATEST_VERIFY(rTemp >= 0); // "Returns a pseudo-random integral number in the range 0 to RAND_MAX."
  140. RandomLinearCongruential randomLCPrimer;
  141. randomLCPrimer.RandomUint32Uniform();
  142. RandomMersenneTwister randomMTPrimer;
  143. randomMTPrimer.RandomUint32Uniform();
  144. TestDieHard();
  145. //#define SPEED_TESTS_ENABLED
  146. #ifdef SPEED_TESTS_ENABLED
  147. // Speed tests.
  148. // Results on a Pentium 4 PC were:
  149. // rand(): 8172 clocks.
  150. // RandomLinearCongruential: 4687 clocks.
  151. // RandomMersenneTwister: 6157 clocks.
  152. {
  153. clock_t timeStart;
  154. clock_t timeTotal;
  155. const int kIterationCount(5000000);
  156. timeStart = clock();
  157. for(int i(0); i < kIterationCount; i++)
  158. EA::UnitTest::WriteToEnsureFunctionCalled() = (int)rand();
  159. timeTotal = clock() - timeStart;
  160. EA::UnitTest::Report("rand(): %d clocks.\n", (int)timeTotal);
  161. timeStart = clock();
  162. for(int i(0); i < kIterationCount; i++)
  163. EA::UnitTest::WriteToEnsureFunctionCalled() = (int)(rand() % 37997);
  164. timeTotal = clock() - timeStart;
  165. EA::UnitTest::Report("rand() w/limit: %d clocks.\n", (int)timeTotal);
  166. RandomLinearCongruential randomLC;
  167. timeStart = clock();
  168. for(int i(0); i < kIterationCount; i++)
  169. EA::UnitTest::WriteToEnsureFunctionCalled() = (int)randomLC.RandomUint32Uniform();
  170. timeTotal = clock() - timeStart;
  171. EA::UnitTest::Report("RandomLinearCongruential: %d clocks.\n", (int)timeTotal);
  172. timeStart = clock();
  173. for(int i(0); i < kIterationCount; i++)
  174. EA::UnitTest::WriteToEnsureFunctionCalled() = (int)randomLC.RandomUint32Uniform(37997);
  175. timeTotal = clock() - timeStart;
  176. EA::UnitTest::Report("RandomLinearCongruential w/limit: %d clocks.\n", (int)timeTotal);
  177. RandomMersenneTwister randomMT;
  178. timeStart = clock();
  179. for(int i(0); i < kIterationCount; i++)
  180. EA::UnitTest::WriteToEnsureFunctionCalled() = (int)randomMT.RandomUint32Uniform();
  181. timeTotal = clock() - timeStart;
  182. EA::UnitTest::Report("RandomMersenneTwister: %d clocks.\n", (int)timeTotal);
  183. timeStart = clock();
  184. for(int i(0); i < kIterationCount; i++)
  185. EA::UnitTest::WriteToEnsureFunctionCalled() = (int)randomMT.RandomUint32Uniform(32997);
  186. timeTotal = clock() - timeStart;
  187. EA::UnitTest::Report("RandomMersenneTwister w/limit: %d clocks.\n", (int)timeTotal);
  188. }
  189. #endif
  190. // Test output ranges
  191. { // RandomLinearCongruential test
  192. RandomLinearCongruential random;
  193. int32_t nRandom;
  194. double dRandom;
  195. for(unsigned i(0); i < 100; i++)
  196. {
  197. for(uint32_t j(5); j < (UINT32_MAX / 2); j *= 5)
  198. {
  199. uint32_t nU32 = random.RandomUint32Uniform(j);
  200. EATEST_VERIFY(nU32 < j);
  201. dRandom = random.RandomDoubleUniform((double)j);
  202. EATEST_VERIFY(0.0 <= dRandom && dRandom < j);
  203. dRandom = random.RandomDoubleUniform();
  204. EATEST_VERIFY(0.0 <= dRandom && dRandom < 1.0);
  205. }
  206. nRandom = Random2(random);
  207. EATEST_VERIFY(nRandom < 2);
  208. nRandom = Random4(random);
  209. EATEST_VERIFY(nRandom < 4);
  210. nRandom = Random8(random);
  211. EATEST_VERIFY(nRandom < 8);
  212. nRandom = Random16(random);
  213. EATEST_VERIFY(nRandom < 16);
  214. nRandom = Random32(random);
  215. EATEST_VERIFY(nRandom < 32);
  216. nRandom = Random64(random);
  217. EATEST_VERIFY(nRandom < 642);
  218. nRandom = Random128(random);
  219. EATEST_VERIFY(nRandom < 128);
  220. nRandom = Random256(random);
  221. EATEST_VERIFY(nRandom < 256);
  222. // RandomPowerOfTwo
  223. for(uint32_t k(1); k < 31; k++)
  224. {
  225. nRandom = RandomPowerOfTwo(random, k);
  226. EATEST_VERIFY((uint32_t)nRandom < (uint32_t)(2 << k));
  227. }
  228. // RandomInt32UniformRange
  229. for(int32_t nBegin(-10000); nBegin < 10000; nBegin += Random256(random))
  230. {
  231. int32_t nEnd = nBegin + 1 + Random256(random);
  232. int32_t iRandom = RandomInt32UniformRange(random, nBegin, nEnd);
  233. EATEST_VERIFY_F((iRandom >= nBegin) && (iRandom < nEnd), "RandomInt32UniformRange failure: iRandom: %I32d, nBegin: %I32d, nEnd: %I32d", iRandom, nBegin, nEnd);
  234. }
  235. // RandomDoubleUniformRange
  236. for(int32_t dBegin(-10000); dBegin < 10000; dBegin += Random256(random))
  237. {
  238. int32_t dEnd = dBegin + 1 + Random256(random);
  239. dRandom = RandomDoubleUniformRange(random, (double)dBegin, (double)dEnd);
  240. EATEST_VERIFY_F((dRandom >= dBegin) && (dRandom < dEnd), "RandomDoubleUniformRange failure: dRandom: %f, dBegin: %f, dEnd: %f", dRandom, (double)dBegin, (double)dEnd);
  241. }
  242. // RandomUint32WeightedChoice
  243. const uint32_t kLimit = 37;
  244. float weights[kLimit];
  245. for(uint32_t q(0); q < kLimit; q++)
  246. weights[q] = (float)RandomDoubleUniformRange(random, 0.5, 30.0);
  247. for(uint32_t r(0); r < 1000; r++)
  248. {
  249. uint32_t nU32 = RandomUint32WeightedChoice(random, kLimit, weights);
  250. EATEST_VERIFY_F(nU32 < kLimit, "RandomUint32WeightedChoice failure: nU32: %I32u, kLimit: %I32u", nU32, kLimit);
  251. }
  252. // RandomInt32GaussianRange
  253. for(int r(0); r < 1000; r++)
  254. {
  255. const int32_t nBegin = (int32_t)random.RandomUint32Uniform(1000);
  256. const int32_t nEnd = nBegin + (int32_t)random.RandomUint32Uniform(1000) + 1;
  257. const int32_t iRandom = RandomInt32GaussianRange(random, nBegin, nEnd);
  258. EATEST_VERIFY((iRandom >= nBegin) && (iRandom < nEnd));
  259. }
  260. // RandomFloatGaussianRange
  261. for(int r(0); r < 1000; r++)
  262. {
  263. const float fBegin = (float)random.RandomDoubleUniform(1000);
  264. const float fEnd = fBegin + (float)random.RandomDoubleUniform(1000) + 1.0f;
  265. const float fRandom = RandomFloatGaussianRange(random, fBegin, fEnd);
  266. EATEST_VERIFY((fRandom >= fBegin) && (fRandom < fEnd));
  267. }
  268. // RandomInt32TriangleRange
  269. for(int r(0); r < 1000; r++)
  270. {
  271. const int32_t nBegin = (int32_t)random.RandomUint32Uniform(1000);
  272. const int32_t nEnd = nBegin + (int32_t)random.RandomUint32Uniform(1000) + 1;
  273. const int32_t iRandom = RandomInt32TriangleRange(random, nBegin, nEnd);
  274. EATEST_VERIFY((iRandom >= nBegin) && (iRandom < nEnd));
  275. }
  276. // RandomFloatTriangleRange
  277. for(int r(0); r < 1000; r++)
  278. {
  279. const float fBegin = (float)random.RandomDoubleUniform(1000);
  280. const float fEnd = fBegin + (float)random.RandomDoubleUniform(1000) + 1.0f;
  281. const float fRandom = RandomFloatTriangleRange(random, fBegin, fEnd);
  282. EATEST_VERIFY((fRandom >= fBegin) && (fRandom < fEnd));
  283. }
  284. }
  285. }
  286. { // RandomInt32Poisson
  287. const float fMean = 5.f;
  288. const size_t maxK = 30;
  289. RandomMersenneTwister random;
  290. for(int i = 0; i < 1000; i++)
  291. {
  292. int32_t rn = RandomInt32Poisson(random.RandomDoubleUniform(), fMean);
  293. EATEST_VERIFY(rn < maxK);
  294. }
  295. }
  296. { // RandomLinearCongruential test
  297. RandomMersenneTwister random;
  298. int32_t nRandom;
  299. double dRandom;
  300. for(unsigned i(0); i < 1000; i++)
  301. {
  302. for(uint32_t j(5); j < UINT32_MAX / 2; j *= 5)
  303. {
  304. uint32_t nU32 = random.RandomUint32Uniform(j);
  305. EATEST_VERIFY(nU32 < j);
  306. dRandom = random.RandomDoubleUniform((double)j);
  307. EATEST_VERIFY(0.0 <= dRandom && dRandom < j);
  308. dRandom = random.RandomDoubleUniform();
  309. EATEST_VERIFY(0.0 <= dRandom && dRandom < 1.0);
  310. }
  311. nRandom = Random2(random);
  312. EATEST_VERIFY(nRandom < 2);
  313. nRandom = Random4(random);
  314. EATEST_VERIFY(nRandom < 4);
  315. nRandom = Random8(random);
  316. EATEST_VERIFY(nRandom < 8);
  317. nRandom = Random16(random);
  318. EATEST_VERIFY(nRandom < 16);
  319. nRandom = Random32(random);
  320. EATEST_VERIFY(nRandom < 32);
  321. nRandom = Random64(random);
  322. EATEST_VERIFY(nRandom < 64);
  323. nRandom = Random128(random);
  324. EATEST_VERIFY(nRandom < 128);
  325. nRandom = Random256(random);
  326. EATEST_VERIFY(nRandom < 256);
  327. for(uint32_t k(1); k < 31; k++)
  328. {
  329. nRandom = RandomPowerOfTwo(random, k);
  330. EATEST_VERIFY((uint32_t)nRandom < (uint32_t)(2 << k));
  331. }
  332. for(int nBegin(-10000); nBegin < 10000; nBegin += Random256(random))
  333. {
  334. int32_t nEnd = nBegin + 1 + Random256(random);
  335. int32_t iRandom = RandomInt32UniformRange(random, nBegin, nEnd);
  336. EATEST_VERIFY((iRandom >= nBegin) && (iRandom < nEnd));
  337. }
  338. for(int dBegin(-10000); dBegin < 10000; dBegin += Random256(random))
  339. {
  340. int32_t dEnd = dBegin + 1 + Random256(random);
  341. dRandom = RandomDoubleUniformRange(random, (double)dBegin, (double)dEnd);
  342. EATEST_VERIFY((dRandom >= dBegin) && (dRandom < dEnd));
  343. }
  344. const unsigned int kLimit = 37;
  345. float weights[kLimit];
  346. for(unsigned int q(0); q < kLimit; q++)
  347. weights[q] = (float)RandomDoubleUniformRange(random, 0.5, 30.0);
  348. for(unsigned int r(0); r < 100; r++)
  349. {
  350. uint32_t nU32 = RandomUint32WeightedChoice(random, kLimit, weights);
  351. EATEST_VERIFY(nU32 < kLimit);
  352. }
  353. }
  354. }
  355. //NOTICE:
  356. //Need Paul to look at this.
  357. //At times, getting values outside of the assertion range.
  358. #if !defined(EA_PLATFORM_IPHONE)
  359. // Do basic randomness testing.
  360. // Just because a random number generator passes known basic tests
  361. // doesn't mean it doesn't have a major flaw.
  362. { // C runtime rand() test, provided for comparison.
  363. int nErrorCountCRand(0); //We don't want to report these as part of our test.
  364. rt_init(false);
  365. for(int i(0); i < 100000; i++)
  366. {
  367. uint8_t nRandom = (uint8_t)(rand() & UINT8_MAX);
  368. rt_add(&nRandom, sizeof(nRandom));
  369. }
  370. // See the rt_end documentation for detailed explanations
  371. // of what each of these metrics mean.
  372. double r_ent, r_chisq, r_mean, r_montepicalc, r_scc;
  373. rt_end(&r_ent, &r_chisq, &r_mean, &r_montepicalc, &r_scc);
  374. if(r_ent < 7.8)
  375. nErrorCountCRand++;
  376. else if(r_chisq < 200)
  377. nErrorCountCRand++;
  378. else if(r_mean < 127.2 || r_mean > 127.9)
  379. nErrorCountCRand++;
  380. else if(r_montepicalc < 3.11 || r_montepicalc > 3.17)
  381. nErrorCountCRand++;
  382. else if(r_scc > 0.01)
  383. nErrorCountCRand++;
  384. }
  385. { // RandomLinearCongruential test
  386. RandomLinearCongruential random;
  387. rt_init(false);
  388. for(int i(0); i < 100000; i++)
  389. {
  390. uint32_t nRandom = random.RandomUint32Uniform();
  391. rt_add(&nRandom, sizeof(nRandom));
  392. }
  393. // See the rt_end documentation for detailed explanations
  394. // of what each of these metrics mean.
  395. double r_ent, r_chisq, r_mean, r_montepicalc, r_scc;
  396. rt_end(&r_ent, &r_chisq, &r_mean, &r_montepicalc, &r_scc);
  397. EATEST_VERIFY(r_ent >= 7.8);
  398. //EATEST_VERIFY(r_chisq >= 200); Disabled until we can figure out why it occasionally fails.
  399. //EATEST_VERIFY(r_mean >= 127.2 && r_mean < 127.9); Disabled until we can figure out why it occasionally fails.
  400. EATEST_VERIFY(r_montepicalc >= 3.11 && r_montepicalc < 3.17);
  401. EATEST_VERIFY(r_scc <= 0.01);
  402. }
  403. { // RandomMersenneTwister test
  404. RandomMersenneTwister random;
  405. rt_init(false);
  406. for(int i(0); i < 100000; i++)
  407. {
  408. uint32_t nRandom = random.RandomUint32Uniform();
  409. rt_add(&nRandom, sizeof(nRandom));
  410. }
  411. // See the rt_end documentation for detailed explanations
  412. // of what each of these metrics mean.
  413. double r_ent, r_chisq, r_mean, r_montepicalc, r_scc;
  414. rt_end(&r_ent, &r_chisq, &r_mean, &r_montepicalc, &r_scc);
  415. EATEST_VERIFY(r_ent >= 7.8);
  416. //EATEST_VERIFY(r_chisq >= 200); Disabled until we can figure out why it occasionally fails.
  417. //EATEST_VERIFY(r_mean >= 127.2 && r_mean < 127.9); Disabled until we can figure out why it occasionally fails.
  418. EATEST_VERIFY(r_montepicalc >= 3.11 && r_montepicalc < 3.17);
  419. EATEST_VERIFY(r_scc <= 0.01);
  420. }
  421. #endif
  422. { // RandomMersenneTwister seed serialization test.
  423. RandomMersenneTwister rmt;
  424. uint32_t seedArray[RandomMersenneTwister::kSeedArrayCount * 2];
  425. uint32_t rand1, rand2;
  426. unsigned size;
  427. size = rmt.GetSeed(seedArray, RandomMersenneTwister::kSeedArrayCount);
  428. EATEST_VERIFY(size == RandomMersenneTwister::kSeedArrayCount);
  429. rand1 = rmt.RandomUint32Uniform();
  430. rmt.RandomUint32Uniform();
  431. rmt.SetSeed(seedArray, size);
  432. rand2 = rmt.RandomUint32Uniform();
  433. EATEST_VERIFY(rand1 == rand2);
  434. size = rmt.GetSeed(seedArray, RandomMersenneTwister::kSeedArrayCount * 2);
  435. EATEST_VERIFY(size == RandomMersenneTwister::kSeedArrayCount);
  436. rand1 = rmt.RandomUint32Uniform();
  437. rmt.RandomUint32Uniform();
  438. rmt.SetSeed(seedArray, size);
  439. rand2 = rmt.RandomUint32Uniform();
  440. EATEST_VERIFY(rand1 == rand2);
  441. size = rmt.GetSeed(seedArray, RandomMersenneTwister::kSeedArrayCount / 2);
  442. EATEST_VERIFY(size == RandomMersenneTwister::kSeedArrayCount / 2);
  443. rand1 = rmt.RandomUint32Uniform();
  444. rmt.RandomUint32Uniform();
  445. rmt.SetSeed(seedArray, size);
  446. // We can't test for equality or inequality of rand1 and rand2
  447. // This is just a pathological test.
  448. size = rmt.GetSeed(seedArray, 0);
  449. EATEST_VERIFY(size == 0);
  450. rand1 = rmt.RandomUint32Uniform();
  451. rmt.RandomUint32Uniform();
  452. rmt.SetSeed(seedArray, size);
  453. rand2 = rmt.RandomUint32Uniform();
  454. EATEST_VERIFY(rand1 != rand2); // They should be different (actually one out of 4 billion times they shouldn't be) because we didn't read the entire state, but only half of it.
  455. }
  456. {
  457. #if defined(EA_PLATFORM_DESKTOP) && !defined(EA_DEBUG) // Do this test only on fast machines, as it's compute-intensive.
  458. // Range tests with FakeIncrementingRandom
  459. const size_t sizes[] = { 2, 5, 10 };
  460. eastl::vector<uint32_t> countBuckets(sizes[EAArrayCount(sizes) - 1], 0);
  461. for(size_t a = 0; a < EAArrayCount(sizes); a++)
  462. {
  463. size_t s = sizes[a];
  464. FakeIncrementingRandom fir;
  465. eastl::fill(countBuckets.begin(), countBuckets.end(), 0);
  466. for(uint64_t i = 0, iEnd = UINT64_C(0x100000000) / s * s; i < iEnd; i++)
  467. {
  468. if((i % 0x10000000) == 0)
  469. EA::UnitTest::Report("."); // Keepalive output.
  470. uint32_t b = EA::StdC::RandomLimit(fir, static_cast<uint32_t>(s));
  471. countBuckets[b]++;
  472. }
  473. for(eastl_size_t b = 1, c = countBuckets[0]; b < s; b++)
  474. {
  475. if(countBuckets[b] != c)
  476. {
  477. EATEST_VERIFY(countBuckets[b] == c);
  478. EA::UnitTest::Report("Random distribution result buckets for limit of %I32u:\n ", (uint32_t)s);
  479. for(eastl_size_t bb = 0, bbEnd = s; bb < bbEnd; bb++)
  480. EA::UnitTest::Report("%I32u%s", (uint32_t)countBuckets[bb], ((bb % 16) == 15) ? "\n" : " ");
  481. EA::UnitTest::Report("\n");
  482. break;
  483. }
  484. }
  485. EA::UnitTest::Report(".\n"); // Keep alive output.
  486. }
  487. #endif
  488. }
  489. // Write out files suitable for the DieHard test suite.
  490. // The version of DieHard that this author most recently
  491. // worked with requires 8404992 bytes of data in a file.
  492. // A copy of DieHard.exe should accompany this test.
  493. // Currently, you drag a file onto it to get the results
  494. // of the test. In the future we can implement the entire
  495. // test within this file. It is about 3500 lines of code
  496. // and would require some massaging to make it work
  497. // smoothly with a unit testing system.
  498. return nErrorCount;
  499. }
  500. ///////////////////////////////////////////////////////////////////////////////
  501. // Ent Chi-Squared functions
  502. //
  503. // Home:
  504. // http://www.fourmilab.ch/random/
  505. // License:
  506. // This software is in the public domain. Permission to use, copy, modify,
  507. // and distribute this software and its documentation for any purpose and
  508. // without fee is hereby granted, without any conditions or restrictions.
  509. // This software is provided "as is" without express or implied warranty.
  510. ///////////////////////////////////////////////////////////////////////////////
  511. //
  512. // Entropy
  513. // The information density of the contents of the file, expressed as a
  514. // number of bits per character. The results above, which resulted from
  515. // processing an image file compressed with JPEG, indicate that the
  516. // file is extremely dense in information--essentially random.
  517. // Hence, compression of the file is unlikely to reduce its size.
  518. // By contrast, the C source code of the program has entropy of about
  519. // 4.9 bits per character, indicating that optimal compression of the
  520. // file would reduce its size by 38%. [Hamming, pp. 104-108]
  521. //
  522. // Chi-square Test
  523. // The chi-square test is the most commonly used test for the randomness
  524. // of data, and is extremely sensitive to errors in pseudorandom sequence
  525. // generators. The chi-square distribution is calculated for the stream
  526. // of bytes in the file and expressed as an absolute number and a
  527. // percentage which indicates how frequently a truly random sequence
  528. // would exceed the value calculated. We interpret the percentage as the
  529. // degree to which the sequence tested is suspected of being non-random.
  530. // If the percentage is greater than 99% or less than 1%, the sequence is
  531. // almost certainly not random. If the percentage is between 99% and 95%
  532. // or between 1% and 5%, the sequence is suspect. Percentages between 90%
  533. // and 95% and 5% and 10% indicate the sequence is "almost suspect".
  534. // Note that our JPEG file, while very dense in information, is far from
  535. // random as revealed by the chi-square test.
  536. //
  537. // Applying this test to the output of various pseudorandom sequence
  538. // generators is interesting. The low-order 8 bits returned by the
  539. // standard Unix rand() function, for example, yields:
  540. // Chi square distribution for 500000 samples is 0.01, and randomly
  541. // would exceed this value 99.99 percent of the times.
  542. //
  543. // While an improved generator [Park & Miller] reports:
  544. // Chi square distribution for 500000 samples is 212.53, and randomly
  545. // would exceed this value 95.00 percent of the times.
  546. //
  547. // Thus, the standard Unix generator (or at least the low-order bytes
  548. // it returns) is unacceptably non-random, while the improved generator
  549. // is much better but still sufficiently non-random to cause concern for
  550. // demanding applications. Contrast both of these software generators
  551. // with the chi-square result of a genuine random sequence created by
  552. // timing radioactive decay events.
  553. // Chi square distribution for 32768 samples is 237.05, and randomly
  554. // would exceed this value 75.00 percent of the times.
  555. //
  556. // See [Knuth, pp. 35-40] for more information on the chi-square test.
  557. // An interactive chi-square calculator is available at this site.
  558. //
  559. // Arithmetic Mean
  560. // This is simply the result of summing the all the bytes (bits if the -b
  561. // option is specified) in the file and dividing by the file length.
  562. // If the data are close to random, this should be about 127.5 (0.5 for -b
  563. // option output). If the mean departs from this value, the values are
  564. // consistently high or low.
  565. //
  566. // Monte Carlo Value for Pi
  567. // Each successive sequence of six bytes is used as 24 bit X and Y
  568. // co-ordinates within a square. If the distance of the randomly-generated
  569. // point is less than the radius of a circle inscribed within the square,
  570. // the six-byte sequence is considered a "hit". The percentage of hits can
  571. // be used to calculate the value of Pi. For very large streams
  572. // (this approximation converges very slowly), the value will approach the
  573. // correct value of Pi if the sequence is close to random. A 32768 byte
  574. // file created by radioactive decay yielded:
  575. // Monte Carlo value for Pi is 3.139648438 (error 0.06 percent).
  576. //
  577. // Serial Correlation Coefficient
  578. // This quantity measures the extent to which each byte in the file
  579. // depends upon the previous byte. For random sequences, this value
  580. // (which can be positive or negative) will, of course, be close to zero.
  581. // A non-random byte stream such as a C program will yield a serial
  582. // correlation coefficient on the order of 0.5. Wildly predictable data
  583. // such as uncompressed bitmaps will exhibit serial correlation coefficients
  584. // approaching 1. See [Knuth, pp. 64-65] for more details.
  585. ///////////////////////////////////////////////////////////////////////////////
  586. #define RFALSE 0
  587. #define RTRUE 1
  588. #define BINARY_MODE RTRUE
  589. #define BYTE_MODE RFALSE
  590. #define MONTEN 6 /* Bytes used as Monte Carlo co-ordinates. This should be no more bits than the mantissa of your "double" floating point type. */
  591. #define log2of10 3.32192809488736234787
  592. static int binary = RFALSE; /* Treat input as a bitstream */
  593. static long ccount[256]; /* Bins to count occurrences of values */
  594. static long totalc = 0; /* Total bytes counted */
  595. static double prob[256]; /* Probabilities per bin for entropy */
  596. static int mp, sccfirst;
  597. static unsigned int monte[MONTEN];
  598. static long inmont, mcount;
  599. static double cexp, incirc, montex, montey, montepi, scc, sccun, sccu0, scclast, scct1, scct2, scct3, ent, chisq, datasum;
  600. /* LOG2 -- Calculate log to the base 2 */
  601. static double Local_log2(double x)
  602. {
  603. return log2of10 * log10(x);
  604. }
  605. /* RT_INIT -- Initialise random test counters. Call with BINARY_MODE or BYTE_MODE */
  606. void rt_init(int binmode)
  607. {
  608. int i;
  609. binary = binmode; /* Set binary / byte mode */
  610. /* Initialise for calculations */
  611. ent = 0.0; /* Clear entropy accumulator */
  612. chisq = 0.0; /* Clear Chi-Square */
  613. datasum = 0.0; /* Clear sum of bytes for arithmetic mean */
  614. mp = 0; /* Reset Monte Carlo accumulator pointer */
  615. mcount = 0; /* Clear Monte Carlo tries */
  616. inmont = 0; /* Clear Monte Carlo inside count */
  617. incirc = 65535.0 * 65535.0; /* In-circle distance for Monte Carlo */
  618. sccfirst = RTRUE; /* Mark first time for serial correlation */
  619. scct1 = scct2 = scct3 = 0.0; /* Clear serial correlation terms */
  620. incirc = pow(pow(256.0, (double) (MONTEN / 2)) - 1, 2.0);
  621. for (i = 0; i < 256; i++) {
  622. ccount[i] = 0;
  623. }
  624. totalc = 0;
  625. }
  626. /* RT_ADD -- Add one or more bytes to accumulation. */
  627. void rt_add(void* buf, int bufl)
  628. {
  629. unsigned char* bp =(unsigned char*)buf;
  630. int oc, c, bean;
  631. while (bean = 0, (bufl-- > 0))
  632. {
  633. oc = *bp++;
  634. do {
  635. if (binary) {
  636. c = !!(oc & 0x80);
  637. }
  638. else {
  639. c = oc;
  640. }
  641. ccount[c]++; /* Update counter for this bin */
  642. totalc++;
  643. /* Update inside / outside circle counts for Monte Carlo computation of PI */
  644. if (bean == 0) {
  645. monte[mp++] = (unsigned int)oc; /* Save character for Monte Carlo */
  646. if (mp >= MONTEN) { /* Calculate every MONTEN character */
  647. int mj;
  648. mp = 0;
  649. mcount++;
  650. montex = montey = 0;
  651. for (mj = 0; mj < MONTEN / 2; mj++) {
  652. montex = (montex * 256.0) + monte[mj];
  653. montey = (montey * 256.0) + monte[(MONTEN / 2) + mj];
  654. }
  655. if ((montex * montex + montey * montey) <= incirc) {
  656. inmont++;
  657. }
  658. }
  659. }
  660. /* Update calculation of serial correlation coefficient */
  661. sccun = (double)c;
  662. if (sccfirst) {
  663. sccfirst = RFALSE;
  664. scclast = 0;
  665. sccu0 = sccun;
  666. }
  667. else {
  668. scct1 = scct1 + scclast * sccun;
  669. }
  670. scct2 = scct2 + sccun;
  671. scct3 = scct3 + (sccun * sccun);
  672. scclast = sccun;
  673. oc <<= 1;
  674. } while (binary && (++bean < 8));
  675. }
  676. }
  677. /* RT_END -- Complete calculation and return results. */
  678. void rt_end(double* r_ent, double* r_chisq, double* r_mean,
  679. double* r_montepicalc, double* r_scc)
  680. {
  681. int i;
  682. double a;
  683. /* Complete calculation of serial correlation coefficient */
  684. scct1 = scct1 + scclast * sccu0;
  685. scct2 = scct2 * scct2;
  686. scc = totalc * scct3 - scct2;
  687. if (scc == 0.0) {
  688. scc = -100000;
  689. }
  690. else {
  691. scc = (totalc * scct1 - scct2) / scc;
  692. }
  693. /* Scan bins and calculate probability for each bin and Chi-Square distribution */
  694. cexp = totalc / (binary ? 2.0 : 256.0); /* Expected count per bin */
  695. for (i = 0; i < (binary ? 2 : 256); i++) {
  696. prob[i] = (double) ccount[i] / totalc;
  697. a = ccount[i] - cexp;
  698. chisq = chisq + (a * a) / cexp;
  699. datasum += ((double) i) * ccount[i];
  700. }
  701. /* Calculate entropy */
  702. for (i = 0; i < (binary ? 2 : 256); i++) {
  703. if (prob[i] > 0.0) {
  704. ent += prob[i] * Local_log2(1 / prob[i]);
  705. }
  706. }
  707. /* Calculate Monte Carlo value for PI from percentage of hits within the circle */
  708. montepi = 4.0 * (((double) inmont) / mcount);
  709. /* Return results through arguments */
  710. *r_ent = ent;
  711. *r_chisq = chisq;
  712. *r_mean = datasum / totalc;
  713. *r_montepicalc = montepi;
  714. *r_scc = scc;
  715. }
  716. ///////////////////////////////////////////////////////////////////////////////
  717. #if 0
  718. static double get_double()
  719. {
  720. return 1.0;
  721. }
  722. static double CalculateSqrm(double a, double b)
  723. {
  724. return ((a - b) * (a - b)) / b;
  725. }
  726. static double CalculatePhi(double x)
  727. {
  728. static const double v[15] =
  729. {
  730. 1.2533141373155, .6556795424187985, .4213692292880545,
  731. .3045902987101033, .2366523829135607, .1928081047153158,
  732. .1623776608968675, .1401041834530502, .1231319632579329,
  733. .1097872825783083, .09902859647173193, .09017567550106468,
  734. .08276628650136917, .0764757610162485, .07106958053885211
  735. };
  736. // Local variables
  737. double cphi, a, b, h;
  738. double z, sum, pwr;
  739. int i, j;
  740. if (fabs(x) > 7.0)
  741. {
  742. if (x >= 0.0)
  743. return 1.0;
  744. return 0.0;
  745. }
  746. if (x>=0.0)
  747. cphi = 0.0;
  748. else
  749. cphi = 1.0;
  750. j = (int) (fabs(x) + 0.5);
  751. j = std::min<int>(j, 14);
  752. z = (double) j;
  753. h = fabs(x) - z;
  754. a = v[j];
  755. b = z * a - 1.0;
  756. pwr = 1.0;
  757. sum = a + h * b;
  758. for (i = 2; i <= (24-j); i += 2)
  759. {
  760. a = (a + z * b) / i;
  761. b = (b + z * a) / (i + 1);
  762. pwr *= h * h;
  763. sum += pwr * (a + h * b);
  764. }
  765. cphi = sum * exp(x * -0.5 * x - 0.918938533204672);
  766. if (x < 0.0)
  767. return cphi;
  768. return 1.0 - cphi;
  769. }
  770. static double CalculateChisq(double x, int n)
  771. {
  772. // System generated locals
  773. double ret_val;
  774. // Local variables
  775. double d;
  776. long i, l;
  777. double s, t;
  778. double xmin;
  779. if (x <= 0.0)
  780. return 0.0;
  781. if (n > 20)
  782. {
  783. t = (pow( x / n, 0.33333) - 1.0 + 0.22222 / n) / sqrt(0.22222 / n);
  784. return CalculatePhi(std::min(t, 8.0));
  785. }
  786. l = 4 - n % 2;
  787. d = (double) std::min(1, n / 3);
  788. ret_val = 0.0;
  789. for (i = l; i <= n; i += 2)
  790. {
  791. d = d * x / (i - 2);
  792. ret_val += d;
  793. }
  794. xmin = std::min(x * 0.5, 50.0);
  795. if (l == 3)
  796. {
  797. s = sqrt( xmin );
  798. return CalculatePhi(s/0.7071068) - exp(-xmin) * 0.564189 * ret_val / s;
  799. }
  800. return 1.0 - exp(-xmin) * (ret_val + 1.0);
  801. }
  802. ///////////////////////////////////////////////////////////////////////////////
  803. // TestCraps
  804. //
  805. // This is the Craps test. It plays 200,000 games of craps, finds
  806. // the number of wins and the number of throws necessary to end
  807. // each game. The number of wins should be (very close to) a
  808. // normal with mean 200000p and variance 200000p(1 - p), with
  809. // p = 244 / 495. Throws necessary to complete the game can vary
  810. // from 1 to infinity, but counts for all > 21 are lumped with 21.
  811. // A chi-square test is made on the #-of-throws cell counts.
  812. // Each 32-bit integer from the test file provides the value for
  813. // the throw of a die, by floating to [0, 1), multiplying by 6
  814. // and taking 1 plus the integer part of the result.
  815. //
  816. static void TestCraps(double& pvalueWins, double& pvalueThrows)
  817. {
  818. static long nt[22];
  819. static double e[22];
  820. double t;
  821. double pwins;
  822. double av; // Expected win count.
  823. double sd;
  824. double ex;
  825. double sum;
  826. long ng;
  827. long gc;
  828. long nwins; // Actual win count.
  829. double pthrows;
  830. int nthrows;
  831. int point;
  832. int i, m, k;
  833. e[1] = 1.0 / 3.0;
  834. sum = e[1];
  835. for (k = 2; k <= 20; ++k)
  836. {
  837. e[k] = ( pow(27.0/36.0, (double) k-2) * 27.0 +
  838. pow(26.0/36.0, (double) k-2) * 40.0 +
  839. pow(25.0/36.0, (double) k-2) * 55.0 ) / 648.0;
  840. sum += e[k];
  841. }
  842. e[21] = 1.0 - sum;
  843. ng = 200000;
  844. nwins = 0;
  845. for (i = 1; i <= 21; ++i)
  846. nt[i] = 0;
  847. for (gc = 1; gc <= ng; ++gc)
  848. {
  849. point = (int)(get_double() * 6.0) + (int)(get_double() * 6.0) + 2;
  850. nthrows = 1;
  851. if ((point == 7) || (point == 11))
  852. ++nwins;
  853. else if ((point != 2) && (point != 3) && (point != 12))
  854. {
  855. for(;;)
  856. {
  857. ++nthrows;
  858. k = (int)(get_double() * 6.0) + (int)(get_double() * 6.0) + 2;
  859. if (k == 7)
  860. break;
  861. if (k == point)
  862. {
  863. ++nwins;
  864. break;
  865. }
  866. }
  867. }
  868. m = std::min<int>(21, nthrows);
  869. ++nt[m];
  870. }
  871. av = ng * 244.0 / 495.0;
  872. sd = sqrt(av * 251.0 / 495.0);
  873. t = (nwins - av) / sd;
  874. //dprintf(" Results of craps test for %s\n", filename);
  875. //dprintf(" No. of wins: Observed Expected\n");
  876. //dprintf(" %9ld %11.2f\n", nwins, av);
  877. pwins = CalculatePhi(t);
  878. //dprintf(" %8ld= No. of wins, z-score=%6.3f pvalue=%7.5f\n", nwins, t, pwins);
  879. //dprintf(" Analysis of Throws-per-Game:\n");
  880. sum = 0.0;
  881. for (i = 1; i <= 21; ++i)
  882. {
  883. ex = ng * e[i];
  884. sum += CalculateSqrm((double)nt[i], ex);
  885. }
  886. pthrows = CalculateChisq(sum, 20);
  887. //dprintf(" Chisq=%7.2f for 20 degrees of freedom, p=%8.5f\n", sum, pthrows);
  888. //dprintf(" Throws Observed Expected Chisq Sum\n");
  889. //sum = 0.0;
  890. //for (i = 1; i <= 21; ++i)
  891. //{
  892. // ex = ng * e[i];
  893. // t = sqrm((double)nt[i], ex);
  894. // sum += t;
  895. //
  896. // dprintf("%19d %8ld %10.1f %7.3f %8.3f\n", i, nt[i], ex, t, sum);
  897. //}
  898. //save_pvalue(pwins);
  899. //save_pvalue(pthrows);
  900. //dprintf(" SUMMARY FOR %s\n", filename);
  901. //dprintf(" p-value for no. of wins:%8.6f\n", pwins);
  902. //dprintf(" p-value for throws/game:%8.6f\n", pthrows);
  903. pvalueWins = pwins;
  904. pvalueThrows = pthrows;
  905. }
  906. #endif
  907. #ifdef _MSC_VER
  908. #pragma warning(pop)
  909. #endif