Files
GTASource/rage/scaleform/Src/GFxPlayer/GFxRandom.cpp

158 lines
3.9 KiB
C++
Raw Normal View History

2025-02-23 17:40:52 +08:00
/**********************************************************************
Filename : GFxRandom.h
Content : Pseudo-random number generator
Created : June 27, 2005
Authors :
Notes :
History :
Copyright : (c) 1998-2006 Scaleform Corp. All Rights Reserved.
Licensees may use this file in accordance with the valid Scaleform
Commercial License Agreement provided with the software.
This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR ANY PURPOSE.
**********************************************************************/
#include "GFxRandom.h"
#include "GTimer.h"
// Global generator.
static GFxRandom::Generator Generator_1;
UInt32 GFxRandom::NextRandom()
{
return Generator_1.NextRandom();
}
void GFxRandom::SeedRandom(UInt32 seed)
{
Generator_1.SeedRandom(seed);
}
Float GFxRandom::GetUnitFloat()
{
return Generator_1.GetUnitFloat();
}
// PRNG code adapted from the complimentary-multiply-with-carry
// code in the article: George Marsaglia, "Seeds for Random Number
// Generators", Communications of the ACM, May 2003, Vol 46 No 5,
// pp90-93.
//
// The article says:
//
// "Any one of the choices for seed table size and multiplier will
// provide a RNG that has passed extensive tests of randomness,
// particularly those in [3], yet is simple and fast --
// approximately 30 million random 32-bit integers per second on a
// 850MHz PC. The period is a*b^n, where a is the multiplier, n
// the size of the seed table and b=2^32-1. (a is chosen so that
// b is a primitive root of the prime a*b^n + 1.)"
//
// [3] Marsaglia, G., Zaman, A., and Tsang, W. Toward a universal
// random number generator. _Statistics and Probability Letters
// 8 (1990), 35-39.
// const UInt64 a = 123471786; // for SEED_COUNT=1024
// const UInt64 a = 123554632; // for SEED_COUNT=512
// const UInt64 a = 8001634; // for SEED_COUNT=255
// const UInt64 a = 8007626; // for SEED_COUNT=128
// const UInt64 a = 647535442; // for SEED_COUNT=64
// const UInt64 a = 547416522; // for SEED_COUNT=32
// const UInt64 a = 487198574; // for SEED_COUNT=16
const UInt64 a = 716514398; // for SEED_COUNT=8
GFxRandom::Generator::Generator()
:
C(362436),
I(GFxRandom::Random_SeedCount - 1)
{
//SeedRandom(987654321);
// we set the seed to the current tick count
SeedRandom(static_cast<UInt32>(GTimer::GetTicks()));
}
// Simple pseudo-random to reseed the seeds.
// Suggested by the above article.
void GFxRandom::Generator::SeedRandom(UInt32 seed)
{
UInt32 j = seed;
for (int i = 0; i < Random_SeedCount; i++)
{
j = j ^ (j << 13);
j = j ^ (j >> 17);
j = j ^ (j << 5);
Q[i] = j;
}
C = 362436;
I = Random_SeedCount - 1;
}
// Return the next pseudo-random number in the sequence.
UInt32 GFxRandom::Generator::NextRandom()
{
UInt64 t;
UInt32 x;
//static UInt32 c = 362436;
//static UInt32 i = SEED_COUNT - 1;
const UInt32 r = 0xFFFFFFFE;
I = (I+1) & (Random_SeedCount - 1);
t = a * Q[I] + C;
C = (UInt32) (t >> 32);
x = (UInt32) (t + C);
if (x < C)
{
x++;
C++;
}
UInt32 val = r - x;
Q[I] = val;
return val;
}
Float GFxRandom::Generator::GetUnitFloat()
{
UInt32 r = NextRandom();
// 24 bits of precision.
return Float(r >> 8) / (16777216.0f - 1.0f);
}
#ifdef TEST_RANDOM
// Compile with e.G.:
//
// gcc -o TuRandomTest TuRandom.Cpp -I.. -g -DTEST_TU_RANDOM -lstdc++
//
// Generate a test file of random numbers for DIEHARD.
int main()
{
const int COUNT = 15000000 / 4; // number of 4-byte words; DIEHARD needs ~80M bits
for (int i = 0; i < COUNT; i++)
{
UInt32 val = GFxRandom::NextRandom();
fwrite(&val, sizeof(val), 1, stdout);
}
}
#endif // TEST_RANDOM