-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathrbeta.cpp
152 lines (120 loc) · 3.05 KB
/
rbeta.cpp
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
/*
Taken from R project 2.13.2
[email protected] oct 07 2011
This should proberly be implemented better using gsl or boost.
we should cite the R project ....
*/
/* Reference:
* R. C. H. Cheng (1978).
* Generating beta variates with nonintegral shape parameters.
* Communications of the ACM 21, 317-322.
* (Algorithms BB and BC)
*/
#include <cstdlib>
#include <cstdlib>
#include <cmath>
#include <cstdio>
#include <cfloat>
#define expmax (DBL_MAX_EXP * M_LN2)/* = log(DBL_MAX) */
double unif_rand() {
return((double)rand() / (double)RAND_MAX);
}
double fmax2(double x, double y)
{
#ifdef IEEE_754
if (ISNAN(x) || ISNAN(y))
return x + y;
#endif
return (x < y) ? y : x;
}
double fmin2(double x, double y)
{
#ifdef IEEE_754
if (ISNAN(x) || ISNAN(y))
return x + y;
#endif
return (x < y) ? x : y;
}
double rbeta(double aa, double bb)
{
double a, b, alpha;
double r, s, t, u1, u2, v, w, y, z;
int qsame;
/* FIXME: Keep Globals (properly) for threading */
/* Uses these GLOBALS to save time when many rv's are generated : */
static double beta, gamma, delta, k1, k2;
static double olda = -1.0;
static double oldb = -1.0;
if (aa <= 0. || bb <= 0. || (std::isinf(aa) && std::isinf(bb)))
// fprintf(stderr,"Thorfinn write better error\n");
if (std::isinf(aa))
return 1.0;
if (std::isinf(bb))
return 0.0;
/* Test if we need new "initializing" */
qsame = (olda == aa) && (oldb == bb);
if (!qsame) { olda = aa; oldb = bb; }
a = fmin2(aa, bb);
b = fmax2(aa, bb); /* a <= b */
alpha = a + b;
#define v_w_from__u1_bet(AA) \
v = beta * log(u1 / (1.0 - u1)); \
if (v <= expmax) { \
w = AA * exp(v); \
if(std::isinf(w)) w = DBL_MAX; \
} else \
w = DBL_MAX
if (a <= 1.0) { /* --- Algorithm BC --- */
/* changed notation, now also a <= b (was reversed) */
if (!qsame) { /* initialize */
beta = 1.0 / a;
delta = 1.0 + b - a;
k1 = delta * (0.0138889 + 0.0416667 * a) / (b * beta - 0.777778);
k2 = 0.25 + (0.5 + 0.25 / delta) * a;
}
/* FIXME: "do { } while()", but not trivially because of "continue"s:*/
for(;;) {
u1 = unif_rand();
u2 = unif_rand();
if (u1 < 0.5) {
y = u1 * u2;
z = u1 * y;
if (0.25 * u2 + z - y >= k1)
continue;
} else {
z = u1 * u1 * u2;
if (z <= 0.25) {
v_w_from__u1_bet(b);
break;
}
if (z >= k2)
continue;
}
v_w_from__u1_bet(b);
if (alpha * (log(alpha / (a + w)) + v) - 1.3862944 >= log(z))
break;
}
return (aa == a) ? a / (a + w) : w / (a + w);
}
else { /* Algorithm BB */
if (!qsame) { /* initialize */
beta = sqrt((alpha - 2.0) / (2.0 * a * b - alpha));
gamma = a + 1.0 / beta;
}
do {
u1 = unif_rand();
u2 = unif_rand();
v_w_from__u1_bet(a);
z = u1 * u1 * u2;
r = gamma * v - 1.3862944;
s = a + r - w;
if (s + 2.609438 >= 5.0 * z)
break;
t = log(z);
if (s > t)
break;
}
while (r + alpha * log(alpha / (b + w)) < t);
return (aa != a) ? b / (b + w) : w / (b + w);
}
}