Skip to content

Instantly share code, notes, and snippets.

@mrchnk
Created July 16, 2015 17:27
Show Gist options
  • Save mrchnk/b24c31d3a615a412374e to your computer and use it in GitHub Desktop.
Save mrchnk/b24c31d3a615a412374e to your computer and use it in GitHub Desktop.
//
// Random number generator
//
/*-------------------------------------------------------------------------*/
/* Coefficients used in the pure random number generator. */
#define c3 15731L
#define c2 789221L
#define c1 1376312589L
/* Read-only, XOR masks for random # generation. */
static const uint32_t Random_Xor_Masks[31] =
{
/* First mask is for generating sequences of 3 (2^2 - 1) random numbers,
/ Second mask is for generating sequences of 7 (2^3 - 1) random numbers,
/ etc. Numbers to the right are number of bits of random number sequence.
/ It generates 2^n - 1 numbers. */
0x00000003L, 0x00000006L, 0x0000000CL, 0x00000014L, /* 2,3,4,5 */
0x00000030L, 0x00000060L, 0x000000B8L, 0x00000110L, /* 6,7,8,9 */
0x00000240L, 0x00000500L, 0x00000CA0L, 0x00001B00L, /* 10,11,12,13 */
0x00003500L, 0x00006000L, 0x0000B400L, 0x00012000L, /* 14,15,16,17 */
0x00020400L, 0x00072000L, 0x00090000L, 0x00140000L, /* 18,19,20,21 */
0x00300000L, 0x00400000L, 0x00D80000L, 0x01200000L, /* 22,23,24,25 */
0x03880000L, 0x07200000L, 0x09000000L, 0x14000000L, /* 26,27,28,29 */
0x32800000L, 0x48000000L, 0xA3000000L /* 30,31,32 */
}; /* Randomizer Xor mask values CRK 10-29-90 */
/*-------------------------------------------------------------------------*/
//TRandomFast gRandomFast = { 0, 0, 0}; Initialized in global.cpp
/*-*-------------------------------------------------------------------------
/ Function
/ RandomFastInit
/
/ Purpose
/ This initializes the fast random number generator.
/
/ Notes
/ The fast random number generator has some unique qualities:
/
/ 1) The same sequence repeats every 2^n-1 generations.
/ 2) Each number can be generated extremely rapidly.
/
/ Entry
/ pRandomFast = Pointer to data structure for current state of a fast
/ pseudorandom number generator.
/--------------------------------------------*/
void MathUtils::RandomFastInit(pTRandomFast pRandomFast)
{
int32_t n = 31; // Changed from 32 to 31 per Prince (you mean "The Artist"?)
pRandomFast->uValue = (uint32_t)(VMPI_getPerformanceCounter());
/* Figure out the sequence length (2^n - 1). */
pRandomFast->uSequenceLength = (1L << n) - 1L;
/* Gather the XOR mask value. */
pRandomFast->uXorMask = Random_Xor_Masks[n - 2];
}
/*-------------------------------------------------------------------------*/
/*-*-------------------------------------------------------------------------
/ Function
/ imRandomFastNext
/
/ Purpose
/ This generates a new pseudorandom number using the fast random number
/ generator.
/
/ Notes
/ The fast random number generator must be initialized before use.
/
/ This is implemented as a macro for the best possible performance.
/
/ Entry
/ pRandomFast = Pointer to data structure for current state of a fast
/ pseudorandom number generator.
/
/ Exit
/ Returns the next pseudorandom number in the sequence.
/--------------------------------------------*/
#define RandomFastNext(_pRandomFast) \
( \
((_pRandomFast)->uValue & 1L) \
? ((_pRandomFast)->uValue = ((_pRandomFast)->uValue >> 1) ^ (_pRandomFast)->uXorMask) \
: ((_pRandomFast)->uValue = ((_pRandomFast)->uValue >> 1)) \
)
/*-------------------------------------------------------------------------*/
/*-*-------------------------------------------------------------------------
/ Function
/ RandomPureHasher
/
/ Purpose
/ This generates a pseudorandom number from a given seed using the high
/ quality random number generator.
/
/ Notes
/ The caller must pass in a seed value. This value is typically the
/ output of the fast random number generator multiplied by a prime
/ number, but can be any seed which was not derived from the output of
/ this function.
/
/ Please note that this random number generator is really as hasher.
/ It will not work well if you pass its own output in as the next input.
/
/ A given input seed always generates the same pseudorandom output result.
/
/ The feature of this hasher is that the value returned from one seed
/ to the next is highly uncorrelated to the seed value. High quality
/ multidimensional random numbers can be generated by using a sum of
/ prime multiples of the seed values.
/
/ For example, to generate a vector given three seed values sx, sy and sz,
/ use something like the following:
/ result = imRandomPureHasher(59*sx + 67*sy + 71*sz);
/
/ Entry
/ iSeed = Starting seed value.
/
/ Exit
/ Returns the next pseudorandom value in the sequence.
/--------------------------------------------*/
int32_t MathUtils::RandomPureHasher(int32_t iSeed)
{
int32_t iResult;
/* Adapted from "A Recursive Implementation of the Perlin Noise Function,"
/ by Greg Ward, Graphics Gems II, p. 396. */
/* First, hash s as a preventive measure. This helps ensure the first
/ few numbers are more random when used in conjunction with the fast
/ random number generator, which starts off with the first 10 or so
/ numbers all zero in the lowe bits. */
iSeed = ((iSeed << 13) ^ iSeed) - (iSeed >> 21);
/* Next, use a third order odd polynomial, better than linear. */
iResult = (iSeed*(iSeed*iSeed*c3 + c2) + c1) & kRandomPureMax;
/* DJ14dec94 -- The above wonderful expression always returns odd
/ numbers, and this is easy to prove. So we add the seed back to
/ the result which again randomizes bit zero. */
iResult += iSeed;
/* DJ17nov95 -- The above always returns values that are NEVER divisible
/ evenly by four, so do additional hashing. */
iResult = ((iResult << 13) ^ iResult) - (iResult >> 21);
return iResult;
}
/* ------------------------------------------------------------------------------ */
int32_t MathUtils::GenerateRandomNumber(pTRandomFast pRandomFast)
{
// Fill out gRandomFast if it is uninitialized.
if (pRandomFast->uValue == 0) {
RandomFastInit(pRandomFast);
}
long aNum = RandomFastNext(pRandomFast);
/* Use the pure random number generator to hash the result. */
aNum = RandomPureHasher(aNum * 71L);
return aNum & kRandomPureMax;
}
int32_t MathUtils::Random(int32_t range, pTRandomFast pRandomFast)
{
if (range > 0) {
return GenerateRandomNumber(pRandomFast) % range;
} else {
return 0;
}
}
void MathUtils::initRandom(TRandomFast *seed)
{
RandomFastInit(seed);
}
double MathUtils::random(TRandomFast *seed)
{
return (double)GenerateRandomNumber(seed) / ((double)kRandomPureMax+1.0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment