random.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Command & Conquer *
  23. * *
  24. * $Archive:: /VSS_Sync/wwlib/random.cpp $*
  25. * *
  26. * $Author:: Vss_sync $*
  27. * *
  28. * $Modtime:: 8/29/01 10:24p $*
  29. * *
  30. * $Revision:: 2 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * RandomClass::RandomClass -- Constructor for the random number class. *
  35. * RandomClass::operator() -- Fetches the next random number in the sequence. *
  36. * RandomClass::operator() -- Ranged random number generator. *
  37. * Random2Class::Random2Class -- Constructor for the random class. *
  38. * Random2Class::operator -- Generates a random number between two values. *
  39. * Random2Class::operator -- Randomizer function that returns value. *
  40. * Random3Class::Random3Class -- Initializer for the random number generator. *
  41. * Random3Class::operator -- Generates a random number between two values. *
  42. * Random3Class::operator -- Random number generator function. *
  43. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  44. #include "always.h"
  45. #include "random.h"
  46. // Timing tests for random these random number generators in seconds for
  47. // 10000000 iterations. Testing done by Hector Yee, 6/20/01
  48. // using DIEHARD and multidimensional Monte-Carlo Integration
  49. /*
  50. Time for Random=0.156000
  51. Time for Random2=0.250000
  52. Time for Random3=1.281000
  53. Time for Random4=0.375000
  54. Time for Built in Rand()=0.813000
  55. Results from DIEHARD battery of tests
  56. A p-value of 0.0 or 1.0 means it fails. Anything inbetween is ok.
  57. R0 - FAILED almost all tests, didn't complete squeeze test
  58. R2 - Passed all tests, p-value 0.6
  59. R3 - Failed 11 of 253 tests, p-value 1.0
  60. R4 - Passed all tests, p-value 0.2588
  61. Rand() - FAILED almost all tests, didn't complete squeeze test
  62. Results from Montecarlo Integration 2-96 dimensions
  63. R0 - starts breaking in 24 dimensions
  64. R2 - Ok, but will repeat with short period. Huge spike at 300000 samples in 64 dimensions
  65. R3 - Strong bias from 2 dimensions up
  66. R4 - Ok
  67. Rand() - starts breaking in 24 dimensions
  68. */
  69. /***********************************************************************************************
  70. * RandomClass::RandomClass -- Constructor for the random number class. *
  71. * *
  72. * This constructor can take an integer as a parameter. This allows the class to be *
  73. * constructed by assigning an integer to an existing object. The compiler creates a *
  74. * temporary with the constructor and then performs a copy constructor operation. *
  75. * *
  76. * INPUT: seed -- The optional starting seed value to use. *
  77. * *
  78. * OUTPUT: none *
  79. * *
  80. * WARNINGS: none *
  81. * *
  82. * HISTORY: *
  83. * 02/27/1996 JLB : Created. *
  84. *=============================================================================================*/
  85. RandomClass::RandomClass(unsigned seed) :
  86. Seed(seed)
  87. {
  88. }
  89. /***********************************************************************************************
  90. * RandomClass::operator() -- Fetches the next random number in the sequence. *
  91. * *
  92. * This routine will fetch the next random number in the sequence. *
  93. * *
  94. * INPUT: none *
  95. * *
  96. * OUTPUT: Returns with the next random number. *
  97. * *
  98. * WARNINGS: This routine modifies the seed value so that subsequent calls will not return *
  99. * the same value. Take note that this routine only returns 15 bits of *
  100. * random number. *
  101. * *
  102. * HISTORY: *
  103. * 02/27/1996 JLB : Created. *
  104. *=============================================================================================*/
  105. int RandomClass::operator ()(void)
  106. {
  107. /*
  108. ** Transform the seed value into the next number in the sequence.
  109. */
  110. Seed = (Seed * MULT_CONSTANT) + ADD_CONSTANT;
  111. /*
  112. ** Extract the 'random' bits from the seed and return that value as the
  113. ** random number result.
  114. */
  115. return((Seed >> THROW_AWAY_BITS) & (~((~0) << SIGNIFICANT_BITS)));
  116. }
  117. /***********************************************************************************************
  118. * RandomClass::operator() -- Ranged random number generator. *
  119. * *
  120. * This function will return with a random number within the range specified. This replaces *
  121. * the functionality of IRandom() in the old library. *
  122. * *
  123. * INPUT: minval -- The minimum value to return from the function. *
  124. * *
  125. * maxval -- The maximum value to return from the function. *
  126. * *
  127. * OUTPUT: Returns with a random number that falls between the minval and maxval (inclusive). *
  128. * *
  129. * WARNINGS: The range specified must fall within the maximum bit significance of the *
  130. * random number algorithm (15 bits), otherwise the value returned will be *
  131. * decidedly non-random. *
  132. * *
  133. * HISTORY: *
  134. * 02/27/1996 JLB : Created. *
  135. *=============================================================================================*/
  136. int RandomClass::operator() (int minval, int maxval)
  137. {
  138. return(Pick_Random_Number(*this, minval, maxval));
  139. }
  140. /***********************************************************************************************
  141. * Random2Class::Random2Class -- Constructor for the random class. *
  142. * *
  143. * This will initialize the random class object with the seed value specified. *
  144. * *
  145. * INPUT: seed -- The seed value used to scramble the random number generator. *
  146. * *
  147. * OUTPUT: none *
  148. * *
  149. * WARNINGS: none *
  150. * *
  151. * HISTORY: *
  152. * 05/14/1997 JLB : Created. *
  153. *=============================================================================================*/
  154. Random2Class::Random2Class(unsigned seed) :
  155. Index1(0),
  156. Index2(103)
  157. {
  158. Random3Class random(seed);
  159. for (int index = 0; index < ARRAY_SIZE(Table); index++) {
  160. Table[index] = random;
  161. }
  162. }
  163. /***********************************************************************************************
  164. * Random2Class::operator -- Randomizer function that returns value. *
  165. * *
  166. * This is the random number generator function. It will generate a random number and *
  167. * return the value. *
  168. * *
  169. * INPUT: none *
  170. * *
  171. * OUTPUT: Returns with a random number. *
  172. * *
  173. * WARNINGS: none *
  174. * *
  175. * HISTORY: *
  176. * 05/20/1997 JLB : Created. *
  177. *=============================================================================================*/
  178. int Random2Class::operator() (void)
  179. {
  180. Table[Index1] ^= Table[Index2];
  181. int val = Table[Index1];
  182. Index1++;
  183. Index2++;
  184. if (Index1 >= ARRAY_SIZE(Table)) Index1 = 0;
  185. if (Index2 >= ARRAY_SIZE(Table)) Index2 = 0;
  186. return(val);
  187. }
  188. /***********************************************************************************************
  189. * Random2Class::operator -- Generates a random number between two values. *
  190. * *
  191. * This routine will generate a random number between the two values specified. It uses *
  192. * a method that will not bias the values in any way. *
  193. * *
  194. * INPUT: minval -- The minium return value (inclusive). *
  195. * *
  196. * maxval -- The maximum return value (inclusive). *
  197. * *
  198. * OUTPUT: Returns with a random number that falls between the two values (inclusive). *
  199. * *
  200. * WARNINGS: none *
  201. * *
  202. * HISTORY: *
  203. * 05/20/1997 JLB : Created. *
  204. *=============================================================================================*/
  205. int Random2Class::operator() (int minval, int maxval)
  206. {
  207. return(Pick_Random_Number(*this, minval, maxval));
  208. }
  209. /*
  210. ** This is the seed table for the Random3Class generator. These ensure
  211. ** that the algorithm is not vulnerable to being primed with a weak seed
  212. ** and thus prevents the algorithm from breaking down as a result.
  213. */
  214. int Random3Class::Mix1[20] = {
  215. 0x0baa96887, 0x01e17d32c, 0x003bcdc3c, 0x00f33d1b2,
  216. 0x076a6491d, 0x0c570d85d, 0x0e382b1e3, 0x078db4362,
  217. 0x07439a9d4, 0x09cea8ac5, 0x089537c5c, 0x02588f55d,
  218. 0x0415b5e1d, 0x0216e3d95, 0x085c662e7, 0x05e8ab368,
  219. 0x03ea5cc8c, 0x0d26a0f74, 0x0f3a9222b, 0x048aad7e4
  220. };
  221. int Random3Class::Mix2[20] = {
  222. 0x04b0f3b58, 0x0e874f0c3, 0x06955c5a6, 0x055a7ca46,
  223. 0x04d9a9d86, 0x0fe28a195, 0x0b1ca7865, 0x06b235751,
  224. 0x09a997a61, 0x0aa6e95c8, 0x0aaa98ee1, 0x05af9154c,
  225. 0x0fc8e2263, 0x0390f5e8c, 0x058ffd802, 0x0ac0a5eba,
  226. 0x0ac4874f6, 0x0a9df0913, 0x086be4c74, 0x0ed2c123b
  227. };
  228. /***********************************************************************************************
  229. * Random3Class::Random3Class -- Initializer for the random number generator. *
  230. * *
  231. * This initializes the random number generator with the seed values specified. Due to a *
  232. * peculiarity of the random number design, the second seed value can be used to find the *
  233. * Nth random number generated by this algorithm. The second seed is used as the Nth index *
  234. * value. *
  235. * *
  236. * INPUT: seed1 -- The seed value to inialize the generator with. It is suggest that some *
  237. * random value based on user input seed this value. *
  238. * *
  239. * seed2 -- The auxiliary seed value. This adds randomness and thus allows this *
  240. * algorithm to use a 64 bit seed. This second seed also serves as an index *
  241. * into the algorithm such that the value passed as 'seed2' is will prime *
  242. * the generator to return that Nth random number when it is called. *
  243. * *
  244. * OUTPUT: none *
  245. * *
  246. * WARNINGS: As with all random number generators. Randomness is only as strong as the *
  247. * initial seed value. *
  248. * *
  249. * HISTORY: *
  250. * 05/20/1997 JLB : Created. *
  251. *=============================================================================================*/
  252. Random3Class::Random3Class(unsigned seed1, unsigned seed2) :
  253. Seed(seed1),
  254. Index(seed2)
  255. {
  256. }
  257. /***********************************************************************************************
  258. * Random3Class::operator -- Random number generator function. *
  259. * *
  260. * This routine generates a random number. The number returned is strongly random and is *
  261. * nearly good enough for cryptography. *
  262. * *
  263. * INPUT: none *
  264. * *
  265. * OUTPUT: Returns with a 32bit random number. *
  266. * *
  267. * WARNINGS: none *
  268. * *
  269. * HISTORY: *
  270. * 05/20/1997 JLB : Created. *
  271. *=============================================================================================*/
  272. int Random3Class::operator() (void)
  273. {
  274. int loword = Seed;
  275. int hiword = Index++;
  276. for (int i = 0; i < 4; i++) {
  277. int hihold = hiword;
  278. int temp = hihold ^ Mix1[i];
  279. int itmpl = temp & 0xffff;
  280. int itmph = temp >> 16;
  281. temp = itmpl * itmpl + ~(itmph * itmph);
  282. temp = (temp >> 16) | (temp << 16);
  283. hiword = loword ^ ((temp ^ Mix2[i]) + itmpl * itmph);
  284. loword = hihold;
  285. }
  286. return(hiword);
  287. }
  288. /***********************************************************************************************
  289. * Random3Class::operator -- Generates a random number between two values. *
  290. * *
  291. * This routine will generate a random number between the two values specified. It uses *
  292. * a method that will not bias the values in any way. *
  293. * *
  294. * INPUT: minval -- The minium return value (inclusive). *
  295. * *
  296. * maxval -- The maximum return value (inclusive). *
  297. * *
  298. * OUTPUT: Returns with a random number that falls between the two values (inclusive). *
  299. * *
  300. * WARNINGS: none *
  301. * *
  302. * HISTORY: *
  303. * 05/20/1997 JLB : Created. *
  304. *=============================================================================================*/
  305. int Random3Class::operator() (int minval, int maxval)
  306. {
  307. return(Pick_Random_Number(*this, minval, maxval));
  308. }
  309. // Random4
  310. // Hector Yee 6/11/01
  311. /* Period parameters */
  312. #define N 624
  313. #define M 397
  314. #define MATRIX_A 0x9908b0df /* constant vector a */
  315. #define UPPER_MASK 0x80000000 /* most significant w-r bits */
  316. #define LOWER_MASK 0x7fffffff /* least significant r bits */
  317. /* Tempering parameters */
  318. #define TEMPERING_MASK_B 0x9d2c5680
  319. #define TEMPERING_MASK_C 0xefc60000
  320. #define TEMPERING_SHIFT_U(y) (y >> 11)
  321. #define TEMPERING_SHIFT_S(y) (y << 7)
  322. #define TEMPERING_SHIFT_T(y) (y << 15)
  323. #define TEMPERING_SHIFT_L(y) (y >> 18)
  324. Random4Class::Random4Class(unsigned int seed)
  325. {
  326. /* setting initial seeds to mt[N] using */
  327. /* the generator Line 25 of Table 1 in */
  328. /* [KNUTH 1981, The Art of Computer Programming */
  329. /* Vol. 2 (2nd Ed.), pp102] */
  330. if (!seed) seed=4375;
  331. mt[0]= seed & 0xffffffff;
  332. for (mti=1; mti<N; mti++)
  333. mt[mti] = (69069 * mt[mti-1]) & 0xffffffff;
  334. // mti is N+1 after this
  335. }
  336. int Random4Class::operator() (void)
  337. {
  338. unsigned int y;
  339. static unsigned int mag01[2]={0x0, MATRIX_A};
  340. /* mag01[x] = x * MATRIX_A for x=0,1 */
  341. if (mti >= N) { /* generate N words at one time */
  342. int kk;
  343. for (kk=0;kk<N-M;kk++) {
  344. y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
  345. mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1];
  346. }
  347. for (;kk<N-1;kk++) {
  348. y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
  349. mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1];
  350. }
  351. y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
  352. mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1];
  353. mti = 0;
  354. }
  355. y = mt[mti++];
  356. y ^= TEMPERING_SHIFT_U(y);
  357. y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B;
  358. y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C;
  359. y ^= TEMPERING_SHIFT_L(y);
  360. int *x=(int *)&y;
  361. return *x;
  362. }
  363. int Random4Class::operator() (int minval, int maxval)
  364. {
  365. return(Pick_Random_Number(*this, minval, maxval));
  366. }
  367. float Random4Class::Get_Float()
  368. {
  369. int x=(*this)();
  370. unsigned int *y=(unsigned int *) &x;
  371. return (*y)*2.3283064370807973754314699618685e-10f;
  372. }