|
|
Home What's New Advice & Strategy Ask the Wizard Gambling online Play for Fun Site Map About Us Colors |
|
Until December 2001 I used the stock random number generator that came with Microsoft Visual C++ and Visual J++ to create programs. The rand() function returns a "random" integer from 0 to 215-1 (32767). This function is flawed in that the numbers are drawn in a cycle. After 231 (2,147,483,648) calls the cycle starts over again. I also discovered that it repeats odd and even numbers in an even smaller cycle of 217 (131,072). From Dec 2001 to Oct 2008 I used what I’ll call the Nathan Reynolds code below. Nathan was very patient with me, helping me get this code to compile on Visual Studio 6.0, which wasn’t easy. It seemed to draw good random numbers, but was quite slow at only about 37,000 random numbers per second. In 2008 someone wrote to me saying that the Nathan Reynolds code was much too slow, and suggested a Mersennse Twister random number generator by Takuji Nishimura and Makoto Matsumoto. After hours of trying, I learned it doesn't work in Visual Studio 6.0, but does work in Visual Studio 2005. I had to make some changes to the code from the source linked to above to get it to work. The following code will draws one billion random numbers in 77 seconds, or about 13 million per second. The function genrand_int32() returns a random integer from 0 to 232-1. I hope the authors, Takuji Nishimura and Makoto Matsumoto, will not mind me republishing their code.
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdio.h>
using namespace std;
/* Period parameters */
#define N 624
#define M 397
#define MATRIX_A 0x9908b0dfUL /* constant vector a */
#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
#define LOWER_MASK 0x7fffffffUL /* least significant r bits */
static unsigned long mt[N]; /* the array for the state vector */
static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */
unsigned long genrand_int32(void);
int main()
{
int i;
unsigned int rn;
__int64 count,RandNum_array[64];
time_t starttime,endtime;
count=0;
for (i=0; i<64; i++)
RandNum_array[i]=0;
starttime=time(NULL);
count=0;
for (i=1; i<=1000000000; i++)
{
count++;
rn=genrand_int32()%64;
RandNum_array[rn]++;
}
endtime=time(NULL);
for (i=0; i<64; i++)
printf("%i\t%I64i\n",i,RandNum_array[i]);
printf("Total = %I64i\n",count);
printf("Total seconds = %i \n",endtime-starttime);
return 1;
}
/* initializes mt[N] with a seed */
void init_genrand(unsigned long s)
{
mt[0]= s & 0xffffffffUL;
for (mti=1; mti<N; mti++) {
mt[mti] =
(1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
/* In the previous versions, MSBs of the seed affect */
/* only MSBs of the array mt[]. */
/* 2002/01/09 modified by Makoto Matsumoto */
mt[mti] &= 0xffffffffUL;
/* for >32 bit machines */
}
}
/* initialize by an array with array-length */
/* init_key is the array for initializing keys */
/* key_length is its length */
/* slight change for C++, 2004/2/26 */
void init_by_array(unsigned long init_key[], int key_length)
{
int i, j, k;
init_genrand(19650218UL);
i=1; j=0;
k = (N>key_length ? N : key_length);
for (; k; k--) {
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL))
+ init_key[j] + j; /* non linear */
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
i++; j++;
if (i>=N) { mt[0] = mt[N-1]; i=1; }
if (j>=key_length) j=0;
}
for (k=N-1; k; k--) {
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL))
- i; /* non linear */
mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
i++;
if (i>=N) { mt[0] = mt[N-1]; i=1; }
}
mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */
}
/* generates a random number on [0,0xffffffff]-interval */
unsigned long genrand_int32(void)
{
unsigned long y;
static unsigned long mag01[2]={0x0UL, MATRIX_A};
/* mag01[x] = x * MATRIX_A for x=0,1 */
if (mti >= N) { /* generate N words at one time */
int kk;
if (mti == N+1) /* if init_genrand() has not been called, */
init_genrand(5489UL); /* a default initial seed is used */
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 & 0x1UL];
}
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 & 0x1UL];
}
y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK);
mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
mti = 0;
}
y = mt[mti++];
/* Tempering */
y ^= (y >> 11);
y ^= (y << 7) & 0x9d2c5680UL;
y ^= (y << 15) & 0xefc60000UL;
y ^= (y >> 18);
return y;
}
The following shows the output of the program.
A chi-squared test on the results has a p value of 0.784793212.
©1998-2010 Wizard Of Odds Consulting, Inc. All rights reserved. Privacy/Terms Contact Advertise About Us Links
The Wizard's other sites:
Wizard of Vegas,
Wizard of Macau,
Math Problems
The Wizard recommends:
The Bear Growls,
Casinomeister,
Online Casino Suite
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||