Added the cFastRandom class

git-svn-id: http://mc-server.googlecode.com/svn/trunk@1672 0a769ca7-a7f5-676a-18bf-c427514a06d6
master
madmaxoft@gmail.com 2013-07-11 08:34:41 +00:00
parent 94a92a219b
commit f5e475d44f
3 changed files with 239 additions and 0 deletions

View File

@ -402,6 +402,14 @@
RelativePath="..\source\Endianness.h"
>
</File>
<File
RelativePath="..\source\FastRandom.cpp"
>
</File>
<File
RelativePath="..\source\FastRandom.h"
>
</File>
<File
RelativePath="..\source\FurnaceRecipe.cpp"
>

174
source/FastRandom.cpp Normal file
View File

@ -0,0 +1,174 @@
// FastRandom.cpp
// Implements the cFastRandom class representing a fast random number generator
#include "Globals.h"
#include <time.h>
#include "FastRandom.h"
#if 0 && defined(_DEBUG)
// Self-test
// Both ints and floats are quick-tested to see if the random is calculated correctly, checking the range in ASSERTs,
// and if it performs well in terms of distribution (checked by avg, expected to be in the range midpoint
class cFastRandomTest
{
public:
cFastRandomTest(void)
{
TestInts();
TestFloats();
}
void TestInts(void)
{
printf("Testing ints...\n");
cFastRandom rnd;
int sum = 0;
const int BUCKETS = 8;
int Counts[BUCKETS];
memset(Counts, 0, sizeof(Counts));
const int ITER = 10000;
for (int i = 0; i < ITER; i++)
{
int v = rnd.NextInt(1000);
ASSERT(v >= 0);
ASSERT(v < 1000);
Counts[v % BUCKETS]++;
sum += v;
}
double avg = (double)sum / ITER;
printf("avg: %f\n", avg);
for (int i = 0; i < BUCKETS; i++)
{
printf(" bucket %d: %d\n", i, Counts[i]);
}
}
void TestFloats(void)
{
printf("Testing floats...\n");
cFastRandom rnd;
float sum = 0;
const int BUCKETS = 8;
int Counts[BUCKETS];
memset(Counts, 0, sizeof(Counts));
const int ITER = 10000;
for (int i = 0; i < ITER; i++)
{
float v = rnd.NextFloat(1000);
ASSERT(v >= 0);
ASSERT(v <= 1000);
Counts[((int)v) % BUCKETS]++;
sum += v;
}
sum = sum / ITER;
printf("avg: %f\n", sum);
for (int i = 0; i < BUCKETS; i++)
{
printf(" bucket %d: %d\n", i, Counts[i]);
}
}
} g_Test;
#endif
int cFastRandom::m_SeedCounter = 0;
cFastRandom::cFastRandom(void) :
m_Seed(m_SeedCounter++)
{
}
int cFastRandom::NextInt(int a_Range)
{
ASSERT(a_Range <= 1000000); // The random is not sufficiently linearly distributed with bigger ranges
ASSERT(a_Range > 0);
// Make the m_Counter operations as minimal as possible, to emulate atomicity
int Counter = m_Counter++;
// Use a_Range, m_Counter and m_Seed as inputs to the pseudorandom function:
int n = a_Range + m_Counter * 57 + m_Seed * 57 * 57;
n = (n << 13) ^ n;
n = ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff);
return ((n / 11) % a_Range);
}
int cFastRandom::NextInt(int a_Range, int a_Salt)
{
ASSERT(a_Range <= 1000000); // The random is not sufficiently linearly distributed with bigger ranges
ASSERT(a_Range > 0);
// Make the m_Counter operations as minimal as possible, to emulate atomicity
int Counter = m_Counter++;
// Use a_Range, a_Salt, m_Counter and m_Seed as inputs to the pseudorandom function:
int n = a_Range + m_Counter * 57 + m_Seed * 57 * 57 + a_Salt * 57 * 57 * 57;
n = (n << 13) ^ n;
n = ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff);
return ((n / 11) % a_Range);
}
float cFastRandom::NextFloat(float a_Range)
{
// Make the m_Counter operations as minimal as possible, to emulate atomicity
int Counter = m_Counter++;
// Use a_Range, a_Salt, m_Counter and m_Seed as inputs to the pseudorandom function:
int n = (int)a_Range + m_Counter * 57 + m_Seed * 57 * 57;
n = (n << 13) ^ n;
n = ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff);
// Convert the integer into float with the specified range:
return (((float)n / (float)0x7fffffff) * a_Range);
}
float cFastRandom::NextFloat(float a_Range, int a_Salt)
{
// Make the m_Counter operations as minimal as possible, to emulate atomicity
int Counter = m_Counter++;
// Use a_Range, a_Salt, m_Counter and m_Seed as inputs to the pseudorandom function:
int n = (int)a_Range + m_Counter * 57 + m_Seed * 57 * 57 + a_Salt * 57 * 57 * 57;
n = (n << 13) ^ n;
n = ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff);
// Convert the integer into float with the specified range:
return (((float)n / (float)0x7fffffff) * a_Range);
}

57
source/FastRandom.h Normal file
View File

@ -0,0 +1,57 @@
// FastRandom.h
// Declares the cFastRandom class representing a fast random number generator
/*
The cFastRandom aims to provide a very fast, although not very cryptographically secure, random generator.
It is fast to instantiate, fast to query next, and partially multi-thread-safe.
It is multi-thread-safe in the sense that it can be accessed from multiple threads without crashing, but it may
yield duplicate numbers in that case.
Internally, this works similar to cNoise's integral noise generation, with some predefined inputs: the seed is
taken from a global counter and the random is calculated using a counter that is incremented on each use (hence
the multi-thread duplication). Two alternatives exists for each function, one that takes a range parameter,
and another that takes an additional "salt" parameter; this salt is used as an additional input to the random,
in order to avoid multi-thread duplication. If two threads both use the class at the same time with different
salts, the values they get will be different.
*/
#pragma once
class cFastRandom
{
public:
cFastRandom(void);
/// Returns a random int in the range [0 .. a_Range - 1]; a_Range must be less than 1M
int NextInt(int a_Range);
/// Returns a random int in the range [0 .. a_Range - 1]; a_Range must be less than 1M; a_Salt is additional source of randomness
int NextInt(int a_Range, int a_Salt);
/// Returns a random float in the range [0 .. a_Range]; a_Range must be less than 1M
float NextFloat(float a_Range);
/// Returns a random float in the range [0 .. a_Range]; a_Range must be less than 1M; a_Salt is additional source of randomness
float NextFloat(float a_Range, int a_Salt);
protected:
int m_Seed;
int m_Counter;
/// Counter that is used to initialize the seed, incremented for each object created
static int m_SeedCounter;
} ;