-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrand.c
More file actions
439 lines (350 loc) · 12.3 KB
/
rand.c
File metadata and controls
439 lines (350 loc) · 12.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "rand.h"
#define NN 312
#define MM 156
#define MATRIX_A 0xB5026F5AA96619E9ULL
#define UM 0xFFFFFFFF80000000ULL /* Most significant 33 bits */
#define LM 0x7FFFFFFFULL /* Least significant 31 bits */
/*
A C-program for MT19937-64 (2004/9/29 version).
Coded by Takuji Nishimura and Makoto Matsumoto.
This is a 64-bit version of Mersenne Twister pseudorandom number
generator.
Before using, initialize the state by using init_genrand64(seed)
or init_by_array64(init_key, key_length).
Copyright (C) 2004, Makoto Matsumoto and Takuji Nishimura,
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The names of its contributors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
References:
T. Nishimura, ``Tables of 64-bit Mersenne Twisters''
ACM Transactions on Modeling and
Computer Simulation 10. (2000) 348--357.
M. Matsumoto and T. Nishimura,
``Mersenne Twister: a 623-dimensionally equidistributed
uniform pseudorandom number generator''
ACM Transactions on Modeling and
Computer Simulation 8. (Jan. 1998) 3--30.
Any feedback is very welcome.
http://www.math.hiroshima-u.ac.jp/~m-mat/MT/emt.html
email: m-mat @ math.sci.hiroshima-u.ac.jp (remove spaces)
*/
/* The array for the state vector */
static unsigned long long mt[NN];
/* mti==NN+1 means mt[NN] is not initialized */
static int mti=NN+1;
/* initializes mt[NN] with a seed */
void init_genrand64(unsigned long long seed)
{
mt[0] = seed;
for (mti=1; mti<NN; mti++)
mt[mti] = (6364136223846793005ULL * (mt[mti-1] ^ (mt[mti-1] >> 62)) + mti);
}
/* initialize by an array with array-length */
/* init_key is the array for initializing keys */
/* key_length is its length */
void init_by_array64(unsigned long long init_key[],
unsigned long long key_length)
{
unsigned long long i, j, k;
init_genrand64(19650218ULL);
i=1; j=0;
k = (NN>key_length ? NN : key_length);
for (; k; k--) {
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 62)) * 3935559000370003845ULL))
+ init_key[j] + j; /* non linear */
i++; j++;
if (i>=NN) { mt[0] = mt[NN-1]; i=1; }
if (j>=key_length) j=0;
}
for (k=NN-1; k; k--) {
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 62)) * 2862933555777941757ULL))
- i; /* non linear */
i++;
if (i>=NN) { mt[0] = mt[NN-1]; i=1; }
}
mt[0] = 1ULL << 63; /* MSB is 1; assuring non-zero initial array */
}
/* generates a random number on [0, 2^64-1]-interval */
unsigned long long genrand64_int64(void)
{
int i;
unsigned long long x;
static unsigned long long mag01[2]={0ULL, MATRIX_A};
if (mti >= NN) { /* generate NN words at one time */
/* if init_genrand64() has not been called, */
/* a default initial seed is used */
if (mti == NN+1)
init_genrand64(5489ULL);
for (i=0;i<NN-MM;i++) {
x = (mt[i]&UM)|(mt[i+1]&LM);
mt[i] = mt[i+MM] ^ (x>>1) ^ mag01[(int)(x&1ULL)];
}
for (;i<NN-1;i++) {
x = (mt[i]&UM)|(mt[i+1]&LM);
mt[i] = mt[i+(MM-NN)] ^ (x>>1) ^ mag01[(int)(x&1ULL)];
}
x = (mt[NN-1]&UM)|(mt[0]&LM);
mt[NN-1] = mt[MM-1] ^ (x>>1) ^ mag01[(int)(x&1ULL)];
mti = 0;
}
x = mt[mti++];
x ^= (x >> 29) & 0x5555555555555555ULL;
x ^= (x << 17) & 0x71D67FFFEDA60000ULL;
x ^= (x << 37) & 0xFFF7EEE000000000ULL;
x ^= (x >> 43);
return x;
}
/* generates a random number on [0, 2^63-1]-interval */
long long genrand64_int63(void)
{
return (long long)(genrand64_int64() >> 1);
}
/* generates a random number on [0,1]-real-interval */
double genrand64_real1(void)
{
return (genrand64_int64() >> 11) * (1.0/9007199254740991.0);
}
/* generates a random number on [0,1)-real-interval */
double genrand64_real2(void)
{
return (genrand64_int64() >> 11) * (1.0/9007199254740992.0);
}
/* generates a random number on (0,1)-real-interval */
double genrand64_real3(void)
{
return ((genrand64_int64() >> 12) + 0.5) * (1.0/4503599627370496.0);
}
/*
int main(void)
{
int i;
unsigned long long init[4]={0x12345ULL, 0x23456ULL, 0x34567ULL, 0x45678ULL}, length=4;
init_by_array64(init, length);
printf("1000 outputs of genrand64_int64()\n");
for (i=0; i<1000; i++) {
printf("%20llu ", genrand64_int64());
if (i%5==4) printf("\n");
}
printf("\n1000 outputs of genrand64_real2()\n");
for (i=0; i<1000; i++) {
printf("%10.8f ", genrand64_real2());
if (i%5==4) printf("\n");
}
return 0;
}
*/
/*------------- UNIFORM [0, 1) RANDOM NUMBER GENERATOR -------------*/
double uniform(void)
{
//return drand48();
return genrand64_real2();
}
/*------------- UNIFORM (0, 1) RANDOM NUMBER GENERATOR -------------*/
double uniform_pos(void)
{
double g;
g = uniform();
while (g == 0.0)
g = uniform();
return g;
/*
return genrand64_real3();
*/
}
/*-------------------------- SET SEED --------------------------*/
void seed( long int n)
{ /* set seed to n */
//srand48(n);
unsigned long long init[4]={n, n+3, n+5, n+13}, length=4;
init_by_array64(init, length);
}
/*------------ UNIFORM [a, b) RANDOM VARIATE GENERATOR -------------*/
double uniform_ab(double a, double b)
{ /* 'uniform' returns a psuedo-random variate from a uniform */
/* distribution with lower bound a and upper bound b. */
if (a>b) printf("uniform Argument Error: a > b\n");
return(a+(b-a)*uniform());
}
/*-------------------- RANDOM INTEGER GENERATOR --------------------*/
int uniform_int(int i, int n)
{ /* 'random' returns an integer equiprobably selected from the */
/* set of integers i, i+1, i+2, . . , n. */
if (i>n) printf("random Argument Error: i > n\n");
n-=i; n=(n+1.0)*uniform();
return(i+n);
}
/*-------------- EXPONENTIAL RANDOM VARIATE GENERATOR --------------*/
/* The exponential distribution has the form
p(x) dx = exp(-x/landa) dx/landa
for x = 0 ... +infty
*/
double exponential(double landa)
{
/* 'exponential' returns a psuedo-random variate from a negative */
/* exponential distribution with mean 1/landa. */
double u = uniform_pos();
double mean = 1.0 / landa;
return -mean * log(1-u);
}
/*---------------- ERLANG RANDOM VARIATE GENERATOR -----------------*/
double erlang(double x, double s)
{ /* 'erlang' returns a psuedo-random variate from an erlang */
/* distribution with mean x and standard deviation s. */
int i,k; double z;
if (s>x) printf("erlang Argument Error: s > x\n");
z=x/s; k=(int)z*z;
z=1.0; for (i=0; i<k; i++) z*=uniform_pos();
return(-(x/k)*log(z));
}
/*----------- HYPEREXPONENTIAL RANDOM VARIATE GENERATION -----------*/
double hyperx(double x, double s)
{ /* 'hyperx' returns a psuedo-random variate from Morse's two- */
/* stage hyperexponential distribution with mean x and standard */
/* deviation s, s>x. */
double cv,z,p;
if (s<=x) printf("hyperx Argument Error: s not > x\n");
cv=s/x; z=cv*cv; p=0.5*(1.0-sqrt((z-1.0)/(z+1.0)));
z=(uniform_pos()>p)? (x/(1.0-p)):(x/p);
return(-0.5*z*log(uniform_pos()));
}
/*----------------- NORMAL RANDOM VARIATE GENERATOR ----------------*/
double normal(double x, double s)
{ /* 'normal' returns a psuedo-random variate from a normal dis- */
/* tribution with mean x and standard deviation s. */
double v1,v2,w,z1; static double z2=0.0;
if (z2!=0.0)
{z1=z2; z2=0.0;} /* use value from previous call */
else
{
do
{v1=2.0*uniform_pos()-1.0; v2=2.0*uniform_pos()-1.0; w=v1*v1+v2*v2;}
while (w>=1.0);
w=sqrt((-2.0*log(w))/w); z1=v1*w; z2=v2*w;
}
return(x+z1*s);
}
/* The Weibull distribution has the form,
p(x) dx = (k/a) (x/a)^(k-1) exp(-(x/a)^k) dx
k = shape
a = landa = scale
*/
double ran_weibull ( const double k, const double a)
{
double x = uniform_pos ();
double z = pow (-log (x), 1 / k);
return a * z;
}
/* The Gamma distribution
k = shape
b = teta = scale
p(x) dx = {1 / \Gamma(k) b^a } x^{k-1} e^{-x/b} dx
for x>0. If X and Y are independent gamma-distributed random
variables of order a1 and a2 with the same scale parameter b, then
X+Y has gamma distribution of order a1+a2.
The algorithms below are from Knuth, vol 2, 2nd ed, p. 129. */
double ran_gamma (const double k, const double b)
{
/* assume a > 0 */
unsigned int na = floor (k);
if (k == na)
{
return b * ran_gamma_int (na);
}
else if (na == 0)
{
return b * gamma_frac (k);
}
else
{
return b * (ran_gamma_int (na) + gamma_frac (k - na)) ;
}
}
double ran_gamma_int (const unsigned int a)
{
if (a < 12)
{
unsigned int i;
double prod = 1;
for (i = 0; i < a; i++)
{
prod *= uniform_pos ();
}
/* Note: for 12 iterations we are safe against underflow, since
the smallest positive random number is O(2^-32). This means
the smallest possible product is 2^(-12*32) = 10^-116 which
is within the range of double precision. */
return -log (prod);
}
else
{
return gamma_large ((double) a);
}
}
static double gamma_large (const double a)
{
/* Works only if a > 1, and is most efficient if a is large
This algorithm, reported in Knuth, is attributed to Ahrens. A
faster one, we are told, can be found in: J. H. Ahrens and
U. Dieter, Computing 12 (1974) 223-246 begin_of_the_skype_highlighting 12 (1974) 223-246 end_of_the_skype_highlighting. */
double sqa, x, y, v;
sqa = sqrt (2 * a - 1);
do
{
do
{
y = tan (M_PI * uniform ());
x = sqa * y + a - 1;
}
while (x <= 0);
v = uniform ();
}
while (v > (1 + y * y) * exp ((a - 1) * log (x / (a - 1)) - sqa * y));
return x;
}
static double gamma_frac (const double a)
{
/* This is exercise 16 from Knuth; see page 135, and the solution is
on page 551. */
double p, q, x, u, v;
p = M_E / (a + M_E);
do
{
u = uniform ();
v = uniform_pos ();
if (u < p)
{
x = exp ((1 / a) * log (v));
q = exp (-x);
}
else
{
x = 1 - log (v);
q = exp ((a - 1) * log (x));
}
}
while (uniform () >= q);
return x;
}