This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/wwlib/random.cpp

416 lines
No EOL
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;
}