416 lines
23 KiB
C++
416 lines
23 KiB
C++
|
/*
|
||
|
** Command & Conquer Renegade(tm)
|
||
|
** Copyright 2025 Electronic Arts Inc.
|
||
|
**
|
||
|
** This program is free software: you can redistribute it and/or modify
|
||
|
** it under the terms of the GNU General Public License as published by
|
||
|
** the Free Software Foundation, either version 3 of the License, or
|
||
|
** (at your option) any later version.
|
||
|
**
|
||
|
** This program is distributed in the hope that it will be useful,
|
||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
** GNU General Public License for more details.
|
||
|
**
|
||
|
** You should have received a copy of the GNU General Public License
|
||
|
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
/***********************************************************************************************
|
||
|
*** 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 ***
|
||
|
***********************************************************************************************
|
||
|
* *
|
||
|
* Project Name : Command & Conquer *
|
||
|
* *
|
||
|
* $Archive:: /VSS_Sync/wwlib/random.cpp $*
|
||
|
* *
|
||
|
* $Author:: Vss_sync $*
|
||
|
* *
|
||
|
* $Modtime:: 8/29/01 10:24p $*
|
||
|
* *
|
||
|
* $Revision:: 2 $*
|
||
|
* *
|
||
|
*---------------------------------------------------------------------------------------------*
|
||
|
* Functions: *
|
||
|
* RandomClass::RandomClass -- Constructor for the random number class. *
|
||
|
* RandomClass::operator() -- Fetches the next random number in the sequence. *
|
||
|
* RandomClass::operator() -- Ranged random number generator. *
|
||
|
* Random2Class::Random2Class -- Constructor for the random class. *
|
||
|
* Random2Class::operator -- Generates a random number between two values. *
|
||
|
* Random2Class::operator -- Randomizer function that returns value. *
|
||
|
* Random3Class::Random3Class -- Initializer for the random number generator. *
|
||
|
* Random3Class::operator -- Generates a random number between two values. *
|
||
|
* Random3Class::operator -- Random number generator function. *
|
||
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||
|
|
||
|
#include "always.h"
|
||
|
#include "random.h"
|
||
|
|
||
|
// Timing tests for random these random number generators in seconds for
|
||
|
// 10000000 iterations. Testing done by Hector Yee, 6/20/01
|
||
|
// using DIEHARD and multidimensional Monte-Carlo Integration
|
||
|
/*
|
||
|
Time for Random=0.156000
|
||
|
Time for Random2=0.250000
|
||
|
Time for Random3=1.281000
|
||
|
Time for Random4=0.375000
|
||
|
Time for Built in Rand()=0.813000
|
||
|
Results from DIEHARD battery of tests
|
||
|
A p-value of 0.0 or 1.0 means it fails. Anything inbetween is ok.
|
||
|
R0 - FAILED almost all tests, didn't complete squeeze test
|
||
|
R2 - Passed all tests, p-value 0.6
|
||
|
R3 - Failed 11 of 253 tests, p-value 1.0
|
||
|
R4 - Passed all tests, p-value 0.2588
|
||
|
Rand() - FAILED almost all tests, didn't complete squeeze test
|
||
|
Results from Montecarlo Integration 2-96 dimensions
|
||
|
R0 - starts breaking in 24 dimensions
|
||
|
R2 - Ok, but will repeat with short period. Huge spike at 300000 samples in 64 dimensions
|
||
|
R3 - Strong bias from 2 dimensions up
|
||
|
R4 - Ok
|
||
|
Rand() - starts breaking in 24 dimensions
|
||
|
*/
|
||
|
|
||
|
|
||
|
/***********************************************************************************************
|
||
|
* RandomClass::RandomClass -- Constructor for the random number class. *
|
||
|
* *
|
||
|
* This constructor can take an integer as a parameter. This allows the class to be *
|
||
|
* constructed by assigning an integer to an existing object. The compiler creates a *
|
||
|
* temporary with the constructor and then performs a copy constructor operation. *
|
||
|
* *
|
||
|
* INPUT: seed -- The optional starting seed value to use. *
|
||
|
* *
|
||
|
* OUTPUT: none *
|
||
|
* *
|
||
|
* WARNINGS: none *
|
||
|
* *
|
||
|
* HISTORY: *
|
||
|
* 02/27/1996 JLB : Created. *
|
||
|
*=============================================================================================*/
|
||
|
RandomClass::RandomClass(unsigned seed) :
|
||
|
Seed(seed)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
/***********************************************************************************************
|
||
|
* RandomClass::operator() -- Fetches the next random number in the sequence. *
|
||
|
* *
|
||
|
* This routine will fetch the next random number in the sequence. *
|
||
|
* *
|
||
|
* INPUT: none *
|
||
|
* *
|
||
|
* OUTPUT: Returns with the next random number. *
|
||
|
* *
|
||
|
* WARNINGS: This routine modifies the seed value so that subsequent calls will not return *
|
||
|
* the same value. Take note that this routine only returns 15 bits of *
|
||
|
* random number. *
|
||
|
* *
|
||
|
* HISTORY: *
|
||
|
* 02/27/1996 JLB : Created. *
|
||
|
*=============================================================================================*/
|
||
|
int RandomClass::operator ()(void)
|
||
|
{
|
||
|
/*
|
||
|
** Transform the seed value into the next number in the sequence.
|
||
|
*/
|
||
|
Seed = (Seed * MULT_CONSTANT) + ADD_CONSTANT;
|
||
|
|
||
|
/*
|
||
|
** Extract the 'random' bits from the seed and return that value as the
|
||
|
** random number result.
|
||
|
*/
|
||
|
return((Seed >> THROW_AWAY_BITS) & (~((~0) << SIGNIFICANT_BITS)));
|
||
|
}
|
||
|
|
||
|
|
||
|
/***********************************************************************************************
|
||
|
* RandomClass::operator() -- Ranged random number generator. *
|
||
|
* *
|
||
|
* This function will return with a random number within the range specified. This replaces *
|
||
|
* the functionality of IRandom() in the old library. *
|
||
|
* *
|
||
|
* INPUT: minval -- The minimum value to return from the function. *
|
||
|
* *
|
||
|
* maxval -- The maximum value to return from the function. *
|
||
|
* *
|
||
|
* OUTPUT: Returns with a random number that falls between the minval and maxval (inclusive). *
|
||
|
* *
|
||
|
* WARNINGS: The range specified must fall within the maximum bit significance of the *
|
||
|
* random number algorithm (15 bits), otherwise the value returned will be *
|
||
|
* decidedly non-random. *
|
||
|
* *
|
||
|
* HISTORY: *
|
||
|
* 02/27/1996 JLB : Created. *
|
||
|
*=============================================================================================*/
|
||
|
int RandomClass::operator() (int minval, int maxval)
|
||
|
{
|
||
|
return(Pick_Random_Number(*this, minval, maxval));
|
||
|
}
|
||
|
|
||
|
|
||
|
/***********************************************************************************************
|
||
|
* Random2Class::Random2Class -- Constructor for the random class. *
|
||
|
* *
|
||
|
* This will initialize the random class object with the seed value specified. *
|
||
|
* *
|
||
|
* INPUT: seed -- The seed value used to scramble the random number generator. *
|
||
|
* *
|
||
|
* OUTPUT: none *
|
||
|
* *
|
||
|
* WARNINGS: none *
|
||
|
* *
|
||
|
* HISTORY: *
|
||
|
* 05/14/1997 JLB : Created. *
|
||
|
*=============================================================================================*/
|
||
|
Random2Class::Random2Class(unsigned seed) :
|
||
|
Index1(0),
|
||
|
Index2(103)
|
||
|
{
|
||
|
Random3Class random(seed);
|
||
|
|
||
|
for (int index = 0; index < ARRAY_SIZE(Table); index++) {
|
||
|
Table[index] = random;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/***********************************************************************************************
|
||
|
* Random2Class::operator -- Randomizer function that returns value. *
|
||
|
* *
|
||
|
* This is the random number generator function. It will generate a random number and *
|
||
|
* return the value. *
|
||
|
* *
|
||
|
* INPUT: none *
|
||
|
* *
|
||
|
* OUTPUT: Returns with a random number. *
|
||
|
* *
|
||
|
* WARNINGS: none *
|
||
|
* *
|
||
|
* HISTORY: *
|
||
|
* 05/20/1997 JLB : Created. *
|
||
|
*=============================================================================================*/
|
||
|
int Random2Class::operator() (void)
|
||
|
{
|
||
|
Table[Index1] ^= Table[Index2];
|
||
|
int val = Table[Index1];
|
||
|
|
||
|
Index1++;
|
||
|
Index2++;
|
||
|
|
||
|
if (Index1 >= ARRAY_SIZE(Table)) Index1 = 0;
|
||
|
if (Index2 >= ARRAY_SIZE(Table)) Index2 = 0;
|
||
|
|
||
|
return(val);
|
||
|
}
|
||
|
|
||
|
|
||
|
/***********************************************************************************************
|
||
|
* Random2Class::operator -- Generates a random number between two values. *
|
||
|
* *
|
||
|
* This routine will generate a random number between the two values specified. It uses *
|
||
|
* a method that will not bias the values in any way. *
|
||
|
* *
|
||
|
* INPUT: minval -- The minium return value (inclusive). *
|
||
|
* *
|
||
|
* maxval -- The maximum return value (inclusive). *
|
||
|
* *
|
||
|
* OUTPUT: Returns with a random number that falls between the two values (inclusive). *
|
||
|
* *
|
||
|
* WARNINGS: none *
|
||
|
* *
|
||
|
* HISTORY: *
|
||
|
* 05/20/1997 JLB : Created. *
|
||
|
*=============================================================================================*/
|
||
|
int Random2Class::operator() (int minval, int maxval)
|
||
|
{
|
||
|
return(Pick_Random_Number(*this, minval, maxval));
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
** This is the seed table for the Random3Class generator. These ensure
|
||
|
** that the algorithm is not vulnerable to being primed with a weak seed
|
||
|
** and thus prevents the algorithm from breaking down as a result.
|
||
|
*/
|
||
|
int Random3Class::Mix1[20] = {
|
||
|
0x0baa96887, 0x01e17d32c, 0x003bcdc3c, 0x00f33d1b2,
|
||
|
0x076a6491d, 0x0c570d85d, 0x0e382b1e3, 0x078db4362,
|
||
|
0x07439a9d4, 0x09cea8ac5, 0x089537c5c, 0x02588f55d,
|
||
|
0x0415b5e1d, 0x0216e3d95, 0x085c662e7, 0x05e8ab368,
|
||
|
0x03ea5cc8c, 0x0d26a0f74, 0x0f3a9222b, 0x048aad7e4
|
||
|
};
|
||
|
|
||
|
int Random3Class::Mix2[20] = {
|
||
|
0x04b0f3b58, 0x0e874f0c3, 0x06955c5a6, 0x055a7ca46,
|
||
|
0x04d9a9d86, 0x0fe28a195, 0x0b1ca7865, 0x06b235751,
|
||
|
0x09a997a61, 0x0aa6e95c8, 0x0aaa98ee1, 0x05af9154c,
|
||
|
0x0fc8e2263, 0x0390f5e8c, 0x058ffd802, 0x0ac0a5eba,
|
||
|
0x0ac4874f6, 0x0a9df0913, 0x086be4c74, 0x0ed2c123b
|
||
|
};
|
||
|
|
||
|
|
||
|
/***********************************************************************************************
|
||
|
* Random3Class::Random3Class -- Initializer for the random number generator. *
|
||
|
* *
|
||
|
* This initializes the random number generator with the seed values specified. Due to a *
|
||
|
* peculiarity of the random number design, the second seed value can be used to find the *
|
||
|
* Nth random number generated by this algorithm. The second seed is used as the Nth index *
|
||
|
* value. *
|
||
|
* *
|
||
|
* INPUT: seed1 -- The seed value to inialize the generator with. It is suggest that some *
|
||
|
* random value based on user input seed this value. *
|
||
|
* *
|
||
|
* seed2 -- The auxiliary seed value. This adds randomness and thus allows this *
|
||
|
* algorithm to use a 64 bit seed. This second seed also serves as an index *
|
||
|
* into the algorithm such that the value passed as 'seed2' is will prime *
|
||
|
* the generator to return that Nth random number when it is called. *
|
||
|
* *
|
||
|
* OUTPUT: none *
|
||
|
* *
|
||
|
* WARNINGS: As with all random number generators. Randomness is only as strong as the *
|
||
|
* initial seed value. *
|
||
|
* *
|
||
|
* HISTORY: *
|
||
|
* 05/20/1997 JLB : Created. *
|
||
|
*=============================================================================================*/
|
||
|
Random3Class::Random3Class(unsigned seed1, unsigned seed2) :
|
||
|
Seed(seed1),
|
||
|
Index(seed2)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
/***********************************************************************************************
|
||
|
* Random3Class::operator -- Random number generator function. *
|
||
|
* *
|
||
|
* This routine generates a random number. The number returned is strongly random and is *
|
||
|
* nearly good enough for cryptography. *
|
||
|
* *
|
||
|
* INPUT: none *
|
||
|
* *
|
||
|
* OUTPUT: Returns with a 32bit random number. *
|
||
|
* *
|
||
|
* WARNINGS: none *
|
||
|
* *
|
||
|
* HISTORY: *
|
||
|
* 05/20/1997 JLB : Created. *
|
||
|
*=============================================================================================*/
|
||
|
int Random3Class::operator() (void)
|
||
|
{
|
||
|
int loword = Seed;
|
||
|
int hiword = Index++;
|
||
|
for (int i = 0; i < 4; i++) {
|
||
|
int hihold = hiword;
|
||
|
int temp = hihold ^ Mix1[i];
|
||
|
int itmpl = temp & 0xffff;
|
||
|
int itmph = temp >> 16;
|
||
|
temp = itmpl * itmpl + ~(itmph * itmph);
|
||
|
temp = (temp >> 16) | (temp << 16);
|
||
|
hiword = loword ^ ((temp ^ Mix2[i]) + itmpl * itmph);
|
||
|
loword = hihold;
|
||
|
}
|
||
|
return(hiword);
|
||
|
}
|
||
|
|
||
|
|
||
|
/***********************************************************************************************
|
||
|
* Random3Class::operator -- Generates a random number between two values. *
|
||
|
* *
|
||
|
* This routine will generate a random number between the two values specified. It uses *
|
||
|
* a method that will not bias the values in any way. *
|
||
|
* *
|
||
|
* INPUT: minval -- The minium return value (inclusive). *
|
||
|
* *
|
||
|
* maxval -- The maximum return value (inclusive). *
|
||
|
* *
|
||
|
* OUTPUT: Returns with a random number that falls between the two values (inclusive). *
|
||
|
* *
|
||
|
* WARNINGS: none *
|
||
|
* *
|
||
|
* HISTORY: *
|
||
|
* 05/20/1997 JLB : Created. *
|
||
|
*=============================================================================================*/
|
||
|
int Random3Class::operator() (int minval, int maxval)
|
||
|
{
|
||
|
return(Pick_Random_Number(*this, minval, maxval));
|
||
|
}
|
||
|
|
||
|
// Random4
|
||
|
// Hector Yee 6/11/01
|
||
|
|
||
|
/* Period parameters */
|
||
|
#define N 624
|
||
|
#define M 397
|
||
|
#define MATRIX_A 0x9908b0df /* constant vector a */
|
||
|
#define UPPER_MASK 0x80000000 /* most significant w-r bits */
|
||
|
#define LOWER_MASK 0x7fffffff /* least significant r bits */
|
||
|
|
||
|
/* Tempering parameters */
|
||
|
#define TEMPERING_MASK_B 0x9d2c5680
|
||
|
#define TEMPERING_MASK_C 0xefc60000
|
||
|
#define TEMPERING_SHIFT_U(y) (y >> 11)
|
||
|
#define TEMPERING_SHIFT_S(y) (y << 7)
|
||
|
#define TEMPERING_SHIFT_T(y) (y << 15)
|
||
|
#define TEMPERING_SHIFT_L(y) (y >> 18)
|
||
|
|
||
|
Random4Class::Random4Class(unsigned int seed)
|
||
|
{
|
||
|
/* setting initial seeds to mt[N] using */
|
||
|
/* the generator Line 25 of Table 1 in */
|
||
|
/* [KNUTH 1981, The Art of Computer Programming */
|
||
|
/* Vol. 2 (2nd Ed.), pp102] */
|
||
|
if (!seed) seed=4375;
|
||
|
|
||
|
mt[0]= seed & 0xffffffff;
|
||
|
for (mti=1; mti<N; mti++)
|
||
|
mt[mti] = (69069 * mt[mti-1]) & 0xffffffff;
|
||
|
// mti is N+1 after this
|
||
|
}
|
||
|
|
||
|
int Random4Class::operator() (void)
|
||
|
{
|
||
|
unsigned int y;
|
||
|
static unsigned int mag01[2]={0x0, MATRIX_A};
|
||
|
/* mag01[x] = x * MATRIX_A for x=0,1 */
|
||
|
|
||
|
if (mti >= N) { /* generate N words at one time */
|
||
|
int kk;
|
||
|
|
||
|
for (kk=0;kk<N-M;kk++) {
|
||
|
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
|
||
|
mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1];
|
||
|
}
|
||
|
for (;kk<N-1;kk++) {
|
||
|
y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK);
|
||
|
mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1];
|
||
|
}
|
||
|
y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
|
||
|
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1];
|
||
|
|
||
|
mti = 0;
|
||
|
}
|
||
|
|
||
|
y = mt[mti++];
|
||
|
y ^= TEMPERING_SHIFT_U(y);
|
||
|
y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B;
|
||
|
y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C;
|
||
|
y ^= TEMPERING_SHIFT_L(y);
|
||
|
|
||
|
int *x=(int *)&y;
|
||
|
|
||
|
return *x;
|
||
|
}
|
||
|
|
||
|
int Random4Class::operator() (int minval, int maxval)
|
||
|
{
|
||
|
return(Pick_Random_Number(*this, minval, maxval));
|
||
|
}
|
||
|
|
||
|
float Random4Class::Get_Float()
|
||
|
{
|
||
|
int x=(*this)();
|
||
|
unsigned int *y=(unsigned int *) &x;
|
||
|
|
||
|
return (*y)*2.3283064370807973754314699618685e-10f;
|
||
|
}
|