-
Notifications
You must be signed in to change notification settings - Fork 0
/
random.c
executable file
·137 lines (108 loc) · 2.47 KB
/
random.c
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
/******************************************************************************
The following code comes from tools.c in Yang's PAML package
U(0,1): AS 183: Appl. Stat. 31:188-190
Wichmann BA & Hill ID. 1982. An efficient and portable
pseudo-random number generator. Appl. Stat. 31:188-190
x, y, z are any numbers in the range 1-30000. Integer operation up
to 30323 required.
******************************************************************************/
#include <stdio.h>
#include <math.h>
#include "random.h"
static int z_rndu=137;
static unsigned w_rndu=13757;
void SetSeed (int seed)
{
z_rndu = 170*(seed%178) + 137;
w_rndu=seed;
}
#ifdef FAST_RANDOM_NUMBER
double rndu (void)
{
w_rndu *= 127773;
return ldexp((double)w_rndu, -32);
}
#else
double rndu (void)
{
static int x_rndu=11, y_rndu=23;
double r;
x_rndu = 171*(x_rndu%177) - 2*(x_rndu/177);
y_rndu = 172*(y_rndu%176) - 35*(y_rndu/176);
z_rndu = 170*(z_rndu%178) - 63*(z_rndu/178);
if (x_rndu<0) x_rndu+=30269;
if (y_rndu<0) y_rndu+=30307;
if (z_rndu<0) z_rndu+=30323;
r = x_rndu/30269.0 + y_rndu/30307.0 + z_rndu/30323.0;
return (r-(int)r);
}
#endif
double rndgamma1 (double s);
double rndgamma2 (double s);
double rndgamma (double s)
{
double r=0.0;
if (s <= 0.0)
puts ("Error gamma..");
else if (s < 1.0)
r = rndgamma1 (s);
else if (s > 1.0)
r = rndgamma2 (s);
else
r =- log(rndu());
return (r);
}
double rndgamma1 (double s)
{
double r, x=0.0, small=1e-37, w;
static double a, p, uf, ss=10.0, d;
if (s!=ss)
{
a = 1.0-s;
p = a/(a+s*exp(-a));
uf = p*pow(small/a,s);
d = a*log(a);
ss = s;
}
for (;;)
{
r = rndu();
if (r > p)
x = a-log((1.0-r)/(1.0-p)), w=a*log(x)-d;
else if (r>uf)
x = a*pow(r/p,1/s), w=x;
else
return (0.0);
r = rndu();
if (1.0-r <= w && r > 0.0)
if (r*(w+1.0) >= 1.0 || -log(r) <= w)
continue;
break;
}
return (x);
}
double rndgamma2 (double s)
{
double r ,d, f, g, x;
static double b, h, ss=0;
if (s!=ss)
{
b = s-1.0;
h = sqrt(3.0*s-0.75);
ss = s;
}
for (;;)
{
r = rndu();
g = r-r*r;
f = (r-0.5)*h/sqrt(g);
x = b+f;
if (x <= 0.0)
continue;
r = rndu();
d = 64*r*r*g*g*g;
if (d*x < x-2.0*f*f || log(d) < 2*(b*log(x/b)-f))
break;
}
return (x);
}