Initial source commit
This commit is contained in:
commit
f1384c11ee
335 changed files with 52715 additions and 0 deletions
244
minorGems/util/random/CustomRandomSource.h
Normal file
244
minorGems/util/random/CustomRandomSource.h
Normal file
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
* Modification History
|
||||
*
|
||||
* 2009-January-14 Jason Rohrer
|
||||
* Created.
|
||||
*
|
||||
* 2009-February-5 Jason Rohrer
|
||||
* Added support for restoring from saved state.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef CUSTOM_RANDOM_SOURCE_INCLUDED
|
||||
#define CUSTOM_RANDOM_SOURCE_INCLUDED
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include "RandomSource.h"
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of RandomSource that does not depend on platform or library.
|
||||
*
|
||||
* Maintains its own internal state.
|
||||
*/
|
||||
class CustomRandomSource : public RandomSource {
|
||||
|
||||
public:
|
||||
|
||||
// seeds itself with current time
|
||||
CustomRandomSource();
|
||||
|
||||
// specify the seed
|
||||
CustomRandomSource( unsigned int inSeed );
|
||||
|
||||
// save for rewind later
|
||||
void saveState();
|
||||
|
||||
void rewindState();
|
||||
|
||||
|
||||
// can be used to save state to disk
|
||||
unsigned int getSavedState();
|
||||
|
||||
void restoreFromSavedState( unsigned int inSavedState );
|
||||
|
||||
|
||||
|
||||
void reseed( unsigned int inSeed );
|
||||
|
||||
|
||||
// implements these functions
|
||||
float getRandomFloat(); // in interval [0,1.0]
|
||||
double getRandomDouble(); // in interval [0,1.0]
|
||||
unsigned int getRandomInt(); // in interval [0,MAX]
|
||||
unsigned int getIntMax(); // returns MAX
|
||||
|
||||
int getRandomBoundedInt( int inRangeStart,
|
||||
int inRangeEnd );
|
||||
|
||||
double getRandomBoundedDouble( double inRangeStart,
|
||||
double inRangeEnd );
|
||||
char getRandomBoolean();
|
||||
|
||||
|
||||
private:
|
||||
double mInvMAXPlusOne; // 1 / ( MAX + 1 )
|
||||
|
||||
unsigned int mState;
|
||||
|
||||
unsigned int mSavedState;
|
||||
|
||||
|
||||
// returns next number and updates state
|
||||
unsigned int genRand32();
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
inline CustomRandomSource::CustomRandomSource() {
|
||||
MAX = 4294967295U;
|
||||
mState = (unsigned)( time(NULL) );
|
||||
invMAX = (float)1.0 / ((float)MAX);
|
||||
invDMAX = 1.0 / ((double)MAX);
|
||||
mInvMAXPlusOne = 1.0 / ( ( (float)MAX ) + 1.0 );
|
||||
|
||||
saveState();
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline CustomRandomSource::CustomRandomSource( unsigned int inSeed ) {
|
||||
MAX = 4294967295U;
|
||||
mState = inSeed;
|
||||
invMAX = (float)1.0 / ((float)MAX);
|
||||
invDMAX = 1.0 / ((double)MAX);
|
||||
mInvMAXPlusOne = 1.0 / ( ( (double)MAX ) + 1.0 );
|
||||
|
||||
saveState();
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline void CustomRandomSource::saveState() {
|
||||
mSavedState = mState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline void CustomRandomSource::rewindState() {
|
||||
mState = mSavedState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline unsigned int CustomRandomSource::getSavedState() {
|
||||
return mSavedState;
|
||||
}
|
||||
|
||||
|
||||
inline void CustomRandomSource::restoreFromSavedState(
|
||||
unsigned int inSavedState) {
|
||||
|
||||
mState = inSavedState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
inline void CustomRandomSource::reseed( unsigned int inSeed ) {
|
||||
mState = inSeed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// from Cultivation/Passage's landscape.cpp
|
||||
// faster as a set of macros
|
||||
#define CustNum1( inSeed ) \
|
||||
( ( inSeed * 0xFEA09B9DU ) + 1 )
|
||||
|
||||
#define CustNum2( inSeed ) \
|
||||
( ( ( inSeed ^ CustNum1( inSeed ) ) * 0x9C129511U ) + 1 )
|
||||
|
||||
#define CustNum3( inSeed ) \
|
||||
( ( inSeed * 0x2512CFB8U ) + 1 )
|
||||
|
||||
#define CustNum4( inSeed ) \
|
||||
( ( ( inSeed ^ CustNum3( inSeed ) ) * 0xB89C8895U ) + 1 )
|
||||
|
||||
#define CustNum5( inSeed ) \
|
||||
( ( inSeed * 0x6BF962C1U ) + 1 )
|
||||
|
||||
#define CustNum6( inSeed ) \
|
||||
( ( ( inSeed ^ CustNum5( inSeed ) ) * 0x4BF962C1U ) + 1 )
|
||||
|
||||
|
||||
|
||||
|
||||
inline unsigned int CustomRandomSource::genRand32() {
|
||||
mState =
|
||||
CustNum2( mState ) ^
|
||||
(CustNum4( mState ) >> 11) ^
|
||||
(CustNum6( mState ) >> 22);
|
||||
|
||||
return mState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline float CustomRandomSource::getRandomFloat() {
|
||||
|
||||
return (float)(genRand32()) * invMAX;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline double CustomRandomSource::getRandomDouble() {
|
||||
|
||||
return (double)(genRand32()) * invDMAX;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline unsigned int CustomRandomSource::getRandomInt() {
|
||||
|
||||
return genRand32();
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline unsigned int CustomRandomSource::getIntMax() {
|
||||
|
||||
return MAX;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline int CustomRandomSource::getRandomBoundedInt( int inRangeStart,
|
||||
int inRangeEnd ) {
|
||||
|
||||
// float in range [0,1)
|
||||
double randFloat = (double)( genRand32() ) * mInvMAXPlusOne;
|
||||
|
||||
int onePastRange = inRangeEnd + 1;
|
||||
|
||||
int magnitude = (int)( randFloat * ( onePastRange - inRangeStart ) );
|
||||
|
||||
return magnitude + inRangeStart;
|
||||
}
|
||||
|
||||
|
||||
inline double CustomRandomSource::getRandomBoundedDouble( double inRangeStart,
|
||||
double inRangeEnd ) {
|
||||
|
||||
// double in range [0,1]
|
||||
double randDouble = getRandomDouble();
|
||||
|
||||
double magnitude = randDouble * ( inRangeEnd - inRangeStart );
|
||||
|
||||
return magnitude + inRangeStart;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline char CustomRandomSource::getRandomBoolean() {
|
||||
|
||||
// float in range [0,1]
|
||||
double randFloat = getRandomFloat();
|
||||
|
||||
if( randFloat < 0.5 ) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
312
minorGems/util/random/Noise.cpp
Normal file
312
minorGems/util/random/Noise.cpp
Normal file
|
@ -0,0 +1,312 @@
|
|||
// Jason Rohrer
|
||||
// Noise.cpp
|
||||
|
||||
/**
|
||||
*
|
||||
* Noise generation implementation
|
||||
*
|
||||
*
|
||||
* Created 11-3-99
|
||||
* Mods:
|
||||
* Jason Rohrer 12-20-2000 Changed genFractalNoise2d function to make
|
||||
* it less blocky.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "Noise.h"
|
||||
|
||||
|
||||
// fills 2d image with ARGB noise
|
||||
void genRandNoise2d(unsigned long *buff, int buffHigh, int buffWide) {
|
||||
|
||||
int *yOffset = new int[buffHigh];
|
||||
|
||||
// precalc y offsets
|
||||
for( int y=0; y<buffHigh; y++) {
|
||||
yOffset[y] = buffWide*y;
|
||||
}
|
||||
|
||||
|
||||
int red = (int)(255 * floatRand());
|
||||
int green = (int)(255 * floatRand());
|
||||
int blue = (int)(255 * floatRand());
|
||||
int alpha = (int)(255 * floatRand());
|
||||
|
||||
for( int y=0; y<buffHigh; y++) {
|
||||
int yContrib = yOffset[y];
|
||||
|
||||
|
||||
|
||||
for( int x=0; x<buffWide; x++) {
|
||||
|
||||
|
||||
/* int red = (int)(255 * floatRand());
|
||||
int green = (int)(255 * floatRand());
|
||||
int blue = (int)(255 * floatRand());
|
||||
int alpha = (int)(255 * floatRand());
|
||||
*/
|
||||
buff[ yContrib + x] = blue | green << 8 | red << 16 | alpha << 24;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
delete [] yOffset;
|
||||
}
|
||||
|
||||
|
||||
// fills 2d image with ARGB fractal noise
|
||||
void genFractalNoise2d(unsigned long *buff, int buffHigh, int buffWide) {
|
||||
|
||||
int *yOffset = new int[buffHigh];
|
||||
|
||||
// precalc y offsets
|
||||
for( int y=0; y<buffHigh; y++) {
|
||||
yOffset[y] = buffWide*y;
|
||||
}
|
||||
|
||||
// first, zero out the buffer
|
||||
|
||||
for( int y=0; y<buffHigh; y++) {
|
||||
int yContrib = yOffset[y];
|
||||
for( int x=0; x<buffWide; x++) {
|
||||
buff[ yContrib + x] = 127 | 127 << 8 | 127 << 16 | 127 << 24;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// walk through each frequency....
|
||||
// weight in sum of frequencies by 1/f
|
||||
|
||||
// frequency in cycles per buffer width
|
||||
// stop when frequency == buffer width
|
||||
|
||||
for( int f=1; f<=buffWide; f++) { // for each frequency
|
||||
|
||||
float weight = 1 / (float)(f);
|
||||
|
||||
// number of pixels in each cycle
|
||||
int blockWide = (int)(buffWide * weight );
|
||||
int blockHigh = (int)(buffHigh * weight );
|
||||
|
||||
|
||||
|
||||
int buffY = 0;
|
||||
|
||||
while( buffY < buffHigh ) {
|
||||
|
||||
int startY = buffY;
|
||||
|
||||
int buffX = 0;
|
||||
while( buffX < buffWide ) {
|
||||
|
||||
buffY = startY;
|
||||
int startX = buffX;
|
||||
|
||||
// color components for this block
|
||||
// weighted by frequency
|
||||
int red = (int)((255 * floatRand() - 127) * weight);
|
||||
int green = (int)((255 * floatRand() - 127) * weight);
|
||||
int blue = (int)((255 * floatRand() - 127) * weight);
|
||||
int alpha = (int)((255 * floatRand() - 127) * weight);
|
||||
|
||||
|
||||
int blockY = 0;
|
||||
while( blockY < blockHigh) {
|
||||
int blockX = 0;
|
||||
buffX = startX;
|
||||
while( blockX < blockWide) {
|
||||
|
||||
unsigned long buffARGB = buff[ yOffset[buffY] + buffX];
|
||||
int buffAlpha = (buffARGB >> 24 & 0xFF) + alpha;
|
||||
int buffRed = (buffARGB >> 16 & 0xFF) + red;
|
||||
int buffGreen = (buffARGB >> 8 & 0xFF) + green;
|
||||
int buffBlue = (buffARGB & 0xFF) + blue;
|
||||
|
||||
|
||||
if( buffAlpha < 0) buffAlpha = 0;
|
||||
if( buffRed < 0) buffRed = 0;
|
||||
if( buffGreen < 0) buffGreen = 0;
|
||||
if( buffBlue < 0) buffBlue = 0;
|
||||
|
||||
if( buffAlpha > 255) buffAlpha = 255;
|
||||
if( buffRed > 255) buffRed = 255;
|
||||
if( buffGreen > 255) buffGreen = 255;
|
||||
if( buffBlue > 255) buffBlue = 255;
|
||||
|
||||
|
||||
buff[ yOffset[buffY] + buffX] = buffBlue | buffGreen << 8 | buffRed << 16 | buffAlpha << 24;
|
||||
|
||||
buffX++;
|
||||
blockX++;
|
||||
if( buffX >= buffWide ) blockX = blockWide; // if this block hangs outside buffer
|
||||
|
||||
}
|
||||
buffY++;
|
||||
blockY++;
|
||||
if( buffY >= buffHigh ) blockY = blockHigh; // if this block hangs outside buffer
|
||||
|
||||
}
|
||||
buffX = startX + blockWide;
|
||||
}
|
||||
buffY = startY + blockHigh;
|
||||
}
|
||||
}
|
||||
|
||||
delete [] yOffset;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void genFractalNoise2d( double *inBuffer, int inWidth, int inMaxFrequency,
|
||||
double inFPower, char inInterpolate, RandomSource *inRandSource ) {
|
||||
|
||||
RandomSource *r = inRandSource;
|
||||
|
||||
int w = inWidth;
|
||||
|
||||
int i, x, y, f;
|
||||
|
||||
int numPoints = w * w;
|
||||
|
||||
// first, fill surface with a uniform 0.5 value
|
||||
for( i=0; i<numPoints; i++ ) {
|
||||
inBuffer[i] = 0.5;
|
||||
}
|
||||
|
||||
// for each frequency
|
||||
for( f=2; f<=inMaxFrequency; f = f * 2 ) {
|
||||
double weight = 1.0 / pow( f, inFPower );
|
||||
|
||||
int blockSize = (int)( (double)w / (double)f + 1.0 );
|
||||
|
||||
// one extra block to handle boundary case where x or y is 0
|
||||
int numBlocks = (f+1) * (f+1);
|
||||
double *blockValues = new double[ numBlocks ];
|
||||
|
||||
// assign a random value to each block
|
||||
for( i=0; i<numBlocks; i++ ) {
|
||||
blockValues[i] = ( 2 * r->getRandomDouble() - 1 ) * weight;
|
||||
}
|
||||
|
||||
// now walk though 2d array and perform
|
||||
// bilinear interpolation between blocks
|
||||
for( y=0; y<w; y++ ) {
|
||||
// handle boundary case by skipping first row of blocks
|
||||
int yBlock = y / blockSize + 1;
|
||||
double yWeight;
|
||||
yWeight = (double)(y % blockSize) / blockSize;
|
||||
|
||||
|
||||
for( x=0; x<w; x++ ) {
|
||||
// handle boundary case by skipping first column of blocks
|
||||
int xBlock = x / blockSize + 1;
|
||||
double xWeight;
|
||||
xWeight = (double)(x % blockSize) / blockSize;
|
||||
|
||||
|
||||
// if interpolating take weighted sum with previous blocks
|
||||
double value;
|
||||
if( inInterpolate ) {
|
||||
value =
|
||||
xWeight *
|
||||
( yWeight *
|
||||
blockValues[ yBlock * f + xBlock ] +
|
||||
(1-yWeight) *
|
||||
blockValues[ (yBlock-1) * f + xBlock ] ) +
|
||||
(1-xWeight) *
|
||||
( yWeight *
|
||||
blockValues[ yBlock * f + xBlock - 1 ] +
|
||||
(1-yWeight) *
|
||||
blockValues[ (yBlock-1) * f + xBlock - 1 ] );
|
||||
}
|
||||
else {
|
||||
value =
|
||||
blockValues[ yBlock * f + xBlock ];
|
||||
}
|
||||
|
||||
// modulate current value by new value
|
||||
inBuffer[ y * w + x ] += value;
|
||||
|
||||
// clip values as we go along
|
||||
if( inBuffer[y * w + x] > 1.0 ) {
|
||||
inBuffer[y * w + x] = 1.0;
|
||||
}
|
||||
else if( inBuffer[y * w + x] < 0.0 ) {
|
||||
inBuffer[y * w + x] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete [] blockValues;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void genFractalNoise( double *inBuffer, int inWidth, int inMaxFrequency,
|
||||
double inFPower, char inInterpolate, RandomSource *inRandSource ) {
|
||||
|
||||
RandomSource *r = inRandSource;
|
||||
|
||||
int w = inWidth;
|
||||
|
||||
int i, x, f;
|
||||
|
||||
// first, fill array with uniform 0.5 values
|
||||
for( i=0; i<w; i++ ) {
|
||||
inBuffer[i] = 0.5;
|
||||
}
|
||||
|
||||
// for each frequency
|
||||
for( f=2; f<=inMaxFrequency; f = f * 2 ) {
|
||||
double weight = 1.0 / pow( f, inFPower );
|
||||
|
||||
int blockSize = (int)( (double)w / (double)f + 1.0 );
|
||||
|
||||
// one extra block to handle boundary case where x is 0
|
||||
int numBlocks = (f+1);
|
||||
double *blockValues = new double[ numBlocks ];
|
||||
|
||||
// assign a random value to each block
|
||||
for( i=0; i<numBlocks; i++ ) {
|
||||
blockValues[i] = ( 2 * r->getRandomDouble() - 1 ) * weight;
|
||||
}
|
||||
|
||||
// now walk though array and perform linear interpolation between blocks
|
||||
|
||||
for( x=0; x<w; x++ ) {
|
||||
// handle boundary case by skipping first column of blocks
|
||||
int xBlock = x / blockSize + 1;
|
||||
double xWeight;
|
||||
xWeight = (double)(x % blockSize) / blockSize;
|
||||
|
||||
|
||||
// take weighted sum with previous blocks, but watch for
|
||||
// boundary cases
|
||||
double value;
|
||||
if( inInterpolate ) {
|
||||
value =
|
||||
xWeight * blockValues[ xBlock ] +
|
||||
(1-xWeight) * blockValues[ xBlock - 1 ];
|
||||
}
|
||||
else {
|
||||
value =
|
||||
blockValues[ xBlock ];
|
||||
}
|
||||
|
||||
// modulate current value by new value
|
||||
inBuffer[ x ] += value;
|
||||
|
||||
// clip values as we go along
|
||||
if( inBuffer[x] > 1.0 ) {
|
||||
inBuffer[x] = 1.0;
|
||||
}
|
||||
else if( inBuffer[x] < 0.0 ) {
|
||||
inBuffer[x] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
delete [] blockValues;
|
||||
}
|
||||
|
||||
}
|
89
minorGems/util/random/Noise.h
Normal file
89
minorGems/util/random/Noise.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
// Jason Rohrer
|
||||
// Noise.h
|
||||
|
||||
/**
|
||||
*
|
||||
* Noise generation interface
|
||||
*
|
||||
*
|
||||
* Created 11-3-99
|
||||
* Mods:
|
||||
* Jason Rohrer 12-20-2000 Added a fractal noise function
|
||||
* that fills a double array.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "minorGems/common.h"
|
||||
|
||||
|
||||
|
||||
#ifndef NOISE_INCLUDED
|
||||
#define NOISE_INCLUDED
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "RandomSource.h"
|
||||
|
||||
|
||||
|
||||
|
||||
// fills 2d image with RGBA noise
|
||||
void genRandNoise2d(unsigned long *buff, int buffHigh, int buffWide);
|
||||
|
||||
|
||||
|
||||
// returns a random floating point between 0 and 1
|
||||
inline float floatRand() {
|
||||
float invRandMax = 1 / ((float)RAND_MAX);
|
||||
return (float)(rand()) * invRandMax;
|
||||
}
|
||||
|
||||
|
||||
// fills 2d image with ARGB fractal noise
|
||||
void genFractalNoise2d(unsigned long *buff, int buffHigh, int buffWide);
|
||||
|
||||
|
||||
/**
|
||||
* Fills a 2d array with 1/f fractal noise.
|
||||
*
|
||||
* @param inBuffer a pre-allocated buffer to fill.
|
||||
* @param inWidth the width and height of the 2d array
|
||||
* contained in the buffer.
|
||||
* Must be a power of 2.
|
||||
* @param inMaxFrequency the maximum frequency of noise modulation to
|
||||
* include, in [2,inWidth]. Lower values produce more "blurry" or
|
||||
* blocky noise.
|
||||
* @param inFPower power to raise F to whene generating noise.
|
||||
* Amplitude of modulation = 1 / (F^inFPower).
|
||||
* @param inInterpolate set to true to perform interpolation of
|
||||
* each frequency modulation. Setting to false produces a "blockier"
|
||||
* noise, while setting to true makes the noise more cloud-like.
|
||||
* @param inRandSource the source to use for random numbers.
|
||||
*/
|
||||
void genFractalNoise2d( double *inBuffer, int inWidth, int inMaxFrequency,
|
||||
double inFPower, char inInterpolate, RandomSource *inRandSource );
|
||||
|
||||
|
||||
/**
|
||||
* Fills a 1d array with 1/f fractal noise.
|
||||
*
|
||||
* @param inBuffer a pre-allocated buffer to fill.
|
||||
* @param inWidth the width of the 2d array
|
||||
* contained in the buffer.
|
||||
* Must be a power of 2.
|
||||
* @param inMaxFrequency the maximum frequency of noise modulation to
|
||||
* include, in [2,inWidth]. Lower values produce more "blurry" or
|
||||
* blocky noise.
|
||||
* @param inFPower power to raise F to whene generating noise.
|
||||
* Amplitude of modulation = 1 / (F^inFPower).
|
||||
* @param inInterpolate set to true to perform interpolation of
|
||||
* each frequency modulation. Setting to false produces a "blockier"
|
||||
* noise, while setting to true makes the noise more cloud-like.
|
||||
* @param inRandSource the source to use for random numbers.
|
||||
*/
|
||||
void genFractalNoise( double *inBuffer, int inWidth, int inMaxFrequency,
|
||||
double inFPower, char inInterpolate, RandomSource *inRandSource );
|
||||
|
||||
#endif
|
86
minorGems/util/random/RandomSource.h
Normal file
86
minorGems/util/random/RandomSource.h
Normal file
|
@ -0,0 +1,86 @@
|
|||
// Jason Rohrer
|
||||
// RandomSource.h
|
||||
|
||||
/**
|
||||
*
|
||||
* abstract interface for random number generation
|
||||
*
|
||||
* Can be implemented by:
|
||||
* --stdlib rand() function calls
|
||||
* --seed file full of random numbers
|
||||
*
|
||||
* Created 12-7-99
|
||||
* Mods:
|
||||
* Jason Rohrer 9-28-2000 Added a getRandomBoundedInt()
|
||||
* interface to faciliate retrieving
|
||||
* an integer in a given range [a,b]
|
||||
* where each integer in the range
|
||||
* has the same probability of being
|
||||
* returned.
|
||||
* Jason Rohrer 12-16-2000 Added a getRandomDouble() interface.
|
||||
* Jason Rohrer 11-21-2005 Added a virtual destructor.
|
||||
* Jason Rohrer 07-09-2006 Added a getRandomBoundedDouble interface.
|
||||
* Jason Rohrer 07-27-2006 Added a getRandomBoolean interface.
|
||||
*/
|
||||
|
||||
#include "minorGems/common.h"
|
||||
|
||||
|
||||
|
||||
#ifndef RANDOM_SOURCE_INCLUDED
|
||||
#define RANDOM_SOURCE_INCLUDED
|
||||
|
||||
|
||||
class RandomSource {
|
||||
|
||||
public:
|
||||
// pure virtual functions implemented by inheriting classes
|
||||
|
||||
virtual float getRandomFloat() = 0; // in interval [0,1.0]
|
||||
virtual double getRandomDouble() = 0; // in interval [0,1.0]
|
||||
virtual unsigned int getRandomInt() = 0; // in interval [0,MAX]
|
||||
virtual unsigned int getIntMax() = 0; // returns MAX
|
||||
|
||||
/**
|
||||
* Returns a random integer in [rangeStart,rangeEnd]
|
||||
* where each integer in the range has an equal
|
||||
* probability of occuring.
|
||||
*/
|
||||
virtual int getRandomBoundedInt( int inRangeStart,
|
||||
int inRangeEnd ) = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Returns a random double in [rangeStart,rangeEnd].
|
||||
*/
|
||||
virtual double getRandomBoundedDouble( double inRangeStart,
|
||||
double inRangeEnd ) = 0;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets a random true/false value.
|
||||
*/
|
||||
virtual char getRandomBoolean() = 0;
|
||||
|
||||
|
||||
|
||||
virtual ~RandomSource();
|
||||
|
||||
|
||||
protected:
|
||||
unsigned int MAX; // maximum integer random number
|
||||
float invMAX; // floating point inverse of MAX
|
||||
double invDMAX; // double invers of MAX
|
||||
};
|
||||
|
||||
|
||||
|
||||
inline RandomSource::~RandomSource() {
|
||||
// does nothing
|
||||
// exists to ensure that subclass destructors are called
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
152
minorGems/util/random/StdRandomSource.h
Normal file
152
minorGems/util/random/StdRandomSource.h
Normal file
|
@ -0,0 +1,152 @@
|
|||
// Jason Rohrer
|
||||
// StdRandomSource.h
|
||||
|
||||
/**
|
||||
*
|
||||
* Implementation of random number generation that uses stdlib calls
|
||||
*
|
||||
*
|
||||
* Created 12-7-99
|
||||
* Mods:
|
||||
* Jason Rohrer 9-28-2000 Added a getRandomBoundedInt()
|
||||
* implementation
|
||||
* Jason Rohrer 12-7-2000 Overloaded constructor to support
|
||||
* specifying a seed.
|
||||
* Jason Rohrer 12-16-2000 Added a getRandomDouble() function.
|
||||
* Jason Rohrer 12-17-2000 Fixed bug in initialization of invDMAX
|
||||
* in default constructor.
|
||||
* Jason Rohrer 9-13-2001 Fixed a bug in getRandomBoundedInt()
|
||||
* as floats were being used, and they
|
||||
* don't provide enough resolution.
|
||||
* Jason Rohrer 10-11-2002 Fixed some type casting warnings.
|
||||
* Jason Rohrer 07-09-2006 Added getRandomBoundedDouble.
|
||||
* Jason Rohrer 07-27-2006 Added getRandomBoolean.
|
||||
*/
|
||||
|
||||
#include "minorGems/common.h"
|
||||
|
||||
|
||||
|
||||
#ifndef STD_RANDOM_SOURCE_INCLUDED
|
||||
#define STD_RANDOM_SOURCE_INCLUDED
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include "RandomSource.h"
|
||||
|
||||
class StdRandomSource : public RandomSource {
|
||||
|
||||
public:
|
||||
|
||||
StdRandomSource(); // needed to seed stdlib generator
|
||||
|
||||
// specify the seed for the stdlib generator
|
||||
StdRandomSource( unsigned int inSeed );
|
||||
|
||||
|
||||
// implements these functions
|
||||
float getRandomFloat(); // in interval [0,1.0]
|
||||
double getRandomDouble(); // in interval [0,1.0]
|
||||
unsigned int getRandomInt(); // in interval [0,MAX]
|
||||
unsigned int getIntMax(); // returns MAX
|
||||
|
||||
int getRandomBoundedInt( int inRangeStart,
|
||||
int inRangeEnd );
|
||||
|
||||
double getRandomBoundedDouble( double inRangeStart,
|
||||
double inRangeEnd );
|
||||
char getRandomBoolean();
|
||||
|
||||
|
||||
private:
|
||||
double mInvMAXPlusOne; // 1 / ( MAX + 1 )
|
||||
};
|
||||
|
||||
|
||||
|
||||
inline StdRandomSource::StdRandomSource() {
|
||||
MAX = RAND_MAX;
|
||||
srand( (unsigned)time(NULL) );
|
||||
invMAX = (float)1.0 / ((float)MAX);
|
||||
invDMAX = 1.0 / ((double)MAX);
|
||||
mInvMAXPlusOne = 1.0 / ( ( (float)MAX ) + 1.0 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline StdRandomSource::StdRandomSource( unsigned int inSeed ) {
|
||||
MAX = RAND_MAX;
|
||||
srand( inSeed );
|
||||
invMAX = (float)1.0 / ((float)MAX);
|
||||
invDMAX = 1.0 / ((double)MAX);
|
||||
mInvMAXPlusOne = 1.0 / ( ( (double)MAX ) + 1.0 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline float StdRandomSource::getRandomFloat() {
|
||||
|
||||
return (float)(rand()) * invMAX;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline double StdRandomSource::getRandomDouble() {
|
||||
|
||||
return (double)(rand()) * invDMAX;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline unsigned int StdRandomSource::getRandomInt() {
|
||||
|
||||
return rand();
|
||||
}
|
||||
|
||||
inline unsigned int StdRandomSource::getIntMax() {
|
||||
|
||||
return MAX;
|
||||
}
|
||||
|
||||
inline int StdRandomSource::getRandomBoundedInt( int inRangeStart,
|
||||
int inRangeEnd ) {
|
||||
|
||||
// float in range [0,1)
|
||||
double randFloat = (double)( rand() ) * mInvMAXPlusOne;
|
||||
|
||||
int onePastRange = inRangeEnd + 1;
|
||||
|
||||
int magnitude = (int)( randFloat * ( onePastRange - inRangeStart ) );
|
||||
|
||||
return magnitude + inRangeStart;
|
||||
}
|
||||
|
||||
|
||||
inline double StdRandomSource::getRandomBoundedDouble( double inRangeStart,
|
||||
double inRangeEnd ) {
|
||||
|
||||
// double in range [0,1]
|
||||
double randDouble = getRandomDouble();
|
||||
|
||||
double magnitude = randDouble * ( inRangeEnd - inRangeStart );
|
||||
|
||||
return magnitude + inRangeStart;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline char StdRandomSource::getRandomBoolean() {
|
||||
|
||||
// float in range [0,1]
|
||||
double randFloat = getRandomFloat();
|
||||
|
||||
if( randFloat < 0.5 ) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
215
minorGems/util/random/testRandom.cpp
Normal file
215
minorGems/util/random/testRandom.cpp
Normal file
|
@ -0,0 +1,215 @@
|
|||
#include "RandomSource.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
// perform tests on a random source
|
||||
|
||||
// tests found here:
|
||||
// NIST FIPS 140-1 U.S. Federal Standard
|
||||
// http://csrc.nist.gov/publications/fips/fips140-1/fips1401.pdf
|
||||
|
||||
void testRandom( RandomSource *inSource ) {
|
||||
|
||||
int bitsPerStep = 1;
|
||||
|
||||
|
||||
// 20000 bits
|
||||
// must be a multiple of bitsPerStep
|
||||
int numBits = 20000;
|
||||
|
||||
int numSteps = numBits / bitsPerStep;
|
||||
|
||||
unsigned int *drawnNumbers = new unsigned int[ numSteps ];
|
||||
|
||||
unsigned int *drawnBits = new unsigned int[ numBits ];
|
||||
|
||||
|
||||
unsigned int bitSum = 0;
|
||||
|
||||
// 1 or 0 when we're in a run
|
||||
unsigned int currentRunType = 2;
|
||||
unsigned int currentRunLength = 0;
|
||||
|
||||
|
||||
unsigned int longestRunLength = 0;
|
||||
|
||||
#define maxRunLengthToTrack 100
|
||||
|
||||
unsigned int runLengthCounts[2][ maxRunLengthToTrack ];
|
||||
|
||||
int r;
|
||||
for( r=0; r<maxRunLengthToTrack; r++ ) {
|
||||
runLengthCounts[0][r] = 0;
|
||||
runLengthCounts[1][r] = 0;
|
||||
}
|
||||
|
||||
|
||||
int i;
|
||||
int bitIndex = 0;
|
||||
|
||||
for( i=0; i<numSteps; i++ ) {
|
||||
drawnNumbers[i] = inSource->getRandomBoundedInt( 0, 1 );
|
||||
//drawnNumbers[i] = inSource->getRandomBoolean();
|
||||
|
||||
|
||||
for( int b=0; b<bitsPerStep; b++ ) {
|
||||
unsigned int bit = ( drawnNumbers[i] >> b & 0x01 );
|
||||
bitSum += bit;
|
||||
|
||||
drawnBits[bitIndex] = bit;
|
||||
bitIndex++;
|
||||
|
||||
|
||||
if( bit == currentRunType ) {
|
||||
currentRunLength++;
|
||||
|
||||
|
||||
if( currentRunLength > longestRunLength ) {
|
||||
longestRunLength = currentRunLength;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// end of run
|
||||
|
||||
if( currentRunLength > 0 &&
|
||||
currentRunLength < maxRunLengthToTrack ) {
|
||||
// count it
|
||||
runLengthCounts[currentRunType][ currentRunLength ] ++;
|
||||
}
|
||||
|
||||
currentRunType = bit;
|
||||
currentRunLength = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float mean = (float)bitSum / numBits;
|
||||
|
||||
printf( "Mean = %f\n", mean );
|
||||
|
||||
|
||||
float varSum = 0;
|
||||
|
||||
for( i=0; i<numBits; i++ ) {
|
||||
unsigned int bit = drawnBits[i];
|
||||
|
||||
varSum += (bit - mean) * (bit - mean);
|
||||
}
|
||||
|
||||
|
||||
float variance = varSum / numBits;
|
||||
|
||||
printf( "Var = %f\n", variance );
|
||||
|
||||
printf( "Monobit count = %d (Allowed [9654 .. 10346])\n", bitSum );
|
||||
|
||||
printf( "Longest run = %d\n", longestRunLength );
|
||||
|
||||
printf( "0 Run Length\tTimes Seen\n"
|
||||
"------------\t----------\n" );
|
||||
|
||||
for( r=0; r<maxRunLengthToTrack && r <= longestRunLength; r++ ) {
|
||||
printf( "%d\t\t%d\n", r, runLengthCounts[0][r] );
|
||||
}
|
||||
printf( "1 Run Length\tTimes Seen\n"
|
||||
"------------\t----------\n" );
|
||||
|
||||
for( r=0; r<maxRunLengthToTrack && r <= longestRunLength; r++ ) {
|
||||
printf( "%d\t\t%d\n", r, runLengthCounts[1][r] );
|
||||
}
|
||||
|
||||
|
||||
// poker test
|
||||
int j;
|
||||
int numCValues = numBits / 4;
|
||||
|
||||
unsigned int *c = new unsigned int[numCValues];
|
||||
unsigned int *f = new unsigned int[16];
|
||||
|
||||
for( i=0; i<16; i++ ) {
|
||||
f[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
for( j=1; j<numCValues; j++ ) {
|
||||
//printf( "bit[%d] = %d\n", j, drawnBits[j] );
|
||||
|
||||
c[j] =
|
||||
8 * drawnBits[ 4 * j - 3]
|
||||
+
|
||||
4 * drawnBits[ 4 * j - 2]
|
||||
+
|
||||
2 * drawnBits[ 4 * j - 1]
|
||||
+
|
||||
1 * drawnBits[ 4 * j ];
|
||||
|
||||
f[ c[j] ] ++;
|
||||
}
|
||||
|
||||
int fSum = 0;
|
||||
//printf( "Poker hand counts:\n" );
|
||||
for( i=0; i<16; i++ ) {
|
||||
//printf( "f[%d] = %d\n", i, f[i] );
|
||||
|
||||
fSum += f[i] * f[i];
|
||||
}
|
||||
|
||||
float Y = 16.0f/numCValues * fSum - numCValues;
|
||||
|
||||
printf( "Poker test = %f (Allowed [1.03 .. 57.4])\n", Y );
|
||||
|
||||
delete [] c;
|
||||
delete [] f;
|
||||
|
||||
|
||||
|
||||
// autocorrelation
|
||||
char failed = false;
|
||||
|
||||
int numShifts = 5000;
|
||||
unsigned int *Z = new unsigned int[ numShifts ];
|
||||
|
||||
for( int t=1; t<numShifts; t++ ) {
|
||||
Z[t] = 0;
|
||||
|
||||
|
||||
for( int j=0; j<5000; j++ ) {
|
||||
Z[t] += drawnBits[j] ^ drawnBits[ j + t ];
|
||||
}
|
||||
|
||||
if( Z[t] > 2326 && Z[t] < 2674 ) {
|
||||
}
|
||||
else {
|
||||
failed = true;
|
||||
//printf( "autocorrelation test failed for Z[%d] = %d\n", t, Z[t] );
|
||||
}
|
||||
}
|
||||
if( !failed ) {
|
||||
printf( "Autocorrelation test passed.\n" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
delete [] drawnNumbers;
|
||||
delete [] drawnBits;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#include "CustomRandomSource.h"
|
||||
#include "StdRandomSource.h"
|
||||
|
||||
int main() {
|
||||
|
||||
CustomRandomSource randSource( 11234258 );
|
||||
//StdRandomSource randSource( 11 );
|
||||
|
||||
testRandom( &randSource );
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue