Skyscraper 2.0
random.cpp
Go to the documentation of this file.
1/*
2 This random number generator originally appeared in "Toward a Universal
3 Random Number Generator" by George Marsaglia and Arif Zaman.
4 Florida State University Report: FSU-SCRI-87-50 (1987)
5
6 It was later modified by F. James and published in "A Review of Pseudo-
7 random Number Generators"
8
9 THIS IS THE BEST KNOWN RANDOM NUMBER GENERATOR AVAILABLE.
10 (However, a newly discovered technique can yield
11 a period of 10^600. But that is still in the development stage.)
12
13 It passes ALL of the tests for random number generators and has a period
14 of 2^144, is completely portable (gives bit identical results on all
15 machines with at least 24-bit mantissas in the floating point
16 representation).
17
18 The algorithm is a combination of a Fibonacci sequence (with lags of 97
19 and 33, and operation "subtraction plus one, modulo one") and an
20 "arithmetic sequence" (using subtraction).
21*/
22
23/*
24 This C++ language version was written by Andrew Zabolotny, and was
25 based on the C language version that was written by Jim Butler,
26 which in turn was based on a FORTRAN program posted by David LaSalle
27 of Florida State University.
28*/
29
30#include "globals.h"
31#include "random.h"
32#include <stdio.h>
33#include <time.h>
34
35namespace SBS {
36
41
42RandomGen::RandomGen(unsigned int iSeed)
43{
44 //initialize with given seed
45 Initialize(iSeed);
46}
47
49{
50 //initialize generator using time() as seed
51 Initialize((unsigned int)time(0));
52}
53
54void RandomGen::Initialize(unsigned int iSeed)
55{
56 //select sequence number out of 942,438,978
57 unsigned int ij = iSeed % 31329UL;
58 unsigned int kl = (iSeed / 31329UL) % 30082UL;
59 InitRANMAR(ij, kl);
60}
61
62void RandomGen::InitRANMAR(unsigned int ij, unsigned int kl)
63{
64 /*
65 This is the initialization routine for the random number generator RANMAR()
66 NOTE: The seed variables can have values between: 0 <= IJ <= 31328
67 0 <= KL <= 30081
68 The random number sequences created by these two seeds are of sufficient
69 length to complete an entire calculation with. For example, if several
70 different groups are working on different parts of the same calculation,
71 each group could be assigned its own IJ seed. This would leave each group
72 with 30000 choices for the second seed. That is to say, this random
73 number generator can create 900 million different subsequences -- with
74 each subsequence having a length of approximately 10^30.
75 */
76
77 int i, j, k, l, m;
78 float s, t;
79
80 i = (ij / 177) % 177 + 2;
81 j = ij % 177 + 2;
82 k = (kl / 169) % 178 + 1;
83 l = kl % 169;
84
85 for (int ii = 1; ii <= 97; ii++)
86 {
87 s = 0.0;
88 t = 0.5;
89 for (int jj = 1; jj <= 24; jj++)
90 {
91 m = (((i * j) % 179) * k) % 179;
92 i = j;
93 j = k;
94 k = m;
95 l = (53 * l + 1) % 169;
96 if ((l * m) % 64 >= 32)
97 s += t;
98 t *= 0.5;
99 }
100 u[ii] = s;
101 }
102
103 c = 362436.0 / 16777216.0;
104 cd = 7654321.0 / 16777216.0;
105 cm = 16777213.0 / 16777216.0;
106
107 i97 = 97;
108 j97 = 33;
109}
110
112{
113 float uni; /* the random number itself */
114
115 uni = u [i97] - u [j97]; /* difference between two [0..1] numbers */
116 if (uni < 0.0)
117 uni += 1.0;
118 u [i97] = uni;
119 i97--; /* i97 ptr decrements and wraps around */
120 if (i97 == 0)
121 i97 = 97;
122 j97--; /* j97 ptr decrements likewise */
123 if (j97 == 0)
124 j97 = 97;
125 c -= cd; /* finally, condition with c-decrement */
126 if (c < 0.0)
127 c += cm; /* cm > cd we hope! (only way c always >0) */
128 uni -= c;
129 if (uni < 0.0)
130 uni += 1.0;
131
132 return (uni); /* return the random number */
133}
134
136{
137 //get a floating point random number less than 1
138 return RANMAR();
139}
140
141unsigned int RandomGen::Get(unsigned int iLimit)
142{
143 //get a random number less than iLimit
144 return int(Get() * iLimit);
145}
146
148{
149 /*
150 Use IJ = 1802 & KL = 9373 to test the random number generator. The
151 subroutine RANMAR should be used to generate 20000 random numbers.
152 Then display the next six random numbers generated multiplied by 4096*4096
153 If the random number generator is working properly, the random numbers
154 should be:
155 6533892.0 14220222.0 7275067.0
156 6172232.0 8354498.0 10633180.0
157 */
158 InitRANMAR(1802, 9373);
159 for (int i = 0; i < 20000; i++)
160 RANMAR();
161 if ((RANMAR() * 4096 * 4096 != 6533892.0)
162 || (RANMAR() * 4096 * 4096 != 14220222.0)
163 || (RANMAR() * 4096 * 4096 != 7275067.0)
164 || (RANMAR() * 4096 * 4096 != 6172232.0)
165 || (RANMAR() * 4096 * 4096 != 8354498.0)
166 || (RANMAR() * 4096 * 4096 != 10633180.0))
167 {
168 puts("WARNING: The random number generator is not working properly!\n");
169 return false;
170 }
171 return true;
172}
173
174}
float Get()
Definition random.cpp:135
void Initialize()
Definition random.cpp:48
void InitRANMAR(unsigned int ij, unsigned int kl)
Definition random.cpp:62
bool SelfTest()
Definition random.cpp:147
float u[98]
Definition random.h:19
float RANMAR()
Definition random.cpp:111