randomext 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,323 @@
1
+ #include "randomext.h"
2
+
3
+ typedef struct {
4
+ int n;
5
+ double theta;
6
+ int N;
7
+ int k;
8
+ double *p;
9
+ int *T;
10
+ int *K;
11
+ double *V;
12
+ } binomial_t;
13
+
14
+ static double binomial_distribution(int k, int n, double theta)
15
+ {
16
+ double ret = 1.0;
17
+ int i;
18
+ for (i=1; i <= k; ++i) {
19
+ ret *= n-k+i;
20
+ ret /= i;
21
+ ret *= theta;
22
+ if (i <= n - k)
23
+ ret *= 1 - theta;
24
+ }
25
+ for (i=0; i<n-2*k; ++i)
26
+ ret *= 1 - theta;
27
+
28
+ return ret;
29
+ }
30
+
31
+ /* Returns Bin(x+1| n, theta)/Bin(x| n, theta) */
32
+ inline static double forward_ratio(double x, double n, double theta)
33
+ {
34
+ return ((n+1)/(x+1) - 1)*(theta/(1-theta));
35
+ }
36
+
37
+ /* Returns Bin(x-1| n, theta)/Bin(x| n, theta) */
38
+ inline static double backward_ratio(double x, double n, double theta)
39
+ {
40
+ return ((n+1)/(n+1-x)-1)*((1-theta)/theta);
41
+ }
42
+
43
+ static void check_binomial_params(int n, double theta, const char* method_name)
44
+ {
45
+ if (n < 1)
46
+ rb_raise(rb_eArgError, "%s: n must be >= 1", method_name);
47
+ if (theta <= 0.0 || 1.0 <= theta)
48
+ rb_raise(rb_eArgError, "%s: n must be in (0, 1)", method_name);
49
+
50
+ }
51
+ /*
52
+ * Draws a random sample from a binomial distribution
53
+ *
54
+ * Inverse function method is used.
55
+ *
56
+ * @overload binomial(n, theta)
57
+ * @param [Integer] n the number of trials (n > 0)
58
+ * @param [Float] theta success probability (0 < theta < 1)
59
+ * @return [Integer] a random sample in 0..n
60
+ */
61
+ static VALUE random_binomial_inv(VALUE self, VALUE num, VALUE prob)
62
+ {
63
+ int n = NUM2INT(num);
64
+ double theta = NUM2DBL(prob);
65
+ int mode = floor(theta*(n+1));
66
+ int xl = mode;
67
+ int xu = mode+1;
68
+ double pl = binomial_distribution(xl, n, theta);
69
+ double pu = pl*forward_ratio(xl, n, theta);
70
+ double u = rb_random_real(self);
71
+
72
+ check_binomial_params(n, theta, "Random#binomial");
73
+
74
+ for (;xl >=0 || xu <= n;) {
75
+ if (xl >= 0) {
76
+ if (u <= pl)
77
+ return INT2NUM(xl);
78
+ u = u - pl;
79
+ pl *= backward_ratio(xl, n, theta);
80
+ --xl;
81
+ }
82
+ if (xu <= n) {
83
+ if (u <= pu)
84
+ return INT2NUM(xu);
85
+ u = u - pu;
86
+ pu *= forward_ratio(xu, n, theta);
87
+ ++xu;
88
+ }
89
+ }
90
+
91
+ return INT2FIX(0);
92
+ }
93
+
94
+ static void fill_binomial_table(binomial_t *bin)
95
+ {
96
+ double theta = bin->theta;
97
+ double n = bin->n;
98
+ int mode = floor(theta*(n+1));
99
+ int k;
100
+
101
+ bin->p[mode] = binomial_distribution(mode, n, theta);
102
+ for (k = mode+1; k <= n; ++k) {
103
+ bin->p[k] = bin->p[k-1]*forward_ratio(k-1, n, theta);
104
+ }
105
+ for (k = mode-1; k >= 0; --k) {
106
+ bin->p[k] = bin->p[k+1]*backward_ratio(k+1, n, theta);
107
+ }
108
+ }
109
+
110
+ static void fill_binomial_VK_table(binomial_t *bin, double ntheta[])
111
+ {
112
+ double c = 1.0/(bin->n + 1);
113
+ int i, j, n, x;
114
+
115
+ bin->K = ALLOC_N(int, bin->n + 1);
116
+ bin->V = ALLOC_N(double, bin->n + 1);
117
+
118
+ for (i=0; i<=bin->n; ++i) {
119
+ bin->K[i] = i;
120
+ bin->V[i] = (i+1)*c;
121
+ }
122
+
123
+ for (n=0; n<bin->n; ++n) {
124
+ for (x=0, i=j=0; x<=bin->n; ++x) {
125
+ if (ntheta[x] < ntheta[i])
126
+ i = x;
127
+ if (ntheta[x] > ntheta[j])
128
+ j = x;
129
+ }
130
+ bin->K[i] = j;
131
+ bin->V[i] = i*c + ntheta[i];
132
+ ntheta[j] = ntheta[j] - (c - ntheta[i]);
133
+ ntheta[i] = c;
134
+ }
135
+ }
136
+
137
+ static void fill_binomial_T_VT_table(binomial_t *bin)
138
+ {
139
+ int k, i, x;
140
+ int nt;
141
+ int *qt = ALLOC_N(int, bin->n + 2);
142
+ double *theta = ALLOC_N(double, bin->n + 1);
143
+ double *ntheta = ALLOC_N(double, bin->n + 1);
144
+ double sum_theta = 0;
145
+
146
+ for (k=7; ;k++) {
147
+ int b = pow2(k);
148
+ nt = 0;
149
+ qt[0] = 0;
150
+ for (x=0; x<=bin->n; x++) {
151
+ qt[x+1] = floor(b*bin->p[x]) + qt[x];
152
+ }
153
+ if (k > 16 || qt[bin->n + 1] > 0.9*b)
154
+ break;
155
+ }
156
+
157
+ bin->k = k;
158
+ bin->N = pow2(k);
159
+ bin->T = ALLOC_N(int, bin->N);
160
+ for (x=0; x<=bin->n; ++x) {
161
+ for (i=qt[x]; i<qt[x+1]; ++i)
162
+ bin->T[i] = x;
163
+ }
164
+ for (i=qt[bin->n + 1]; i<bin->N; ++i)
165
+ bin->T[i] = -1;
166
+
167
+ for (x=0; x<=bin->n; ++x) {
168
+ theta[x] = pow2(k) * bin->p[x] - (qt[x+1]-qt[x]);
169
+ sum_theta += theta[x];
170
+ }
171
+
172
+ for (x=0; x<=bin->n; ++x)
173
+ ntheta[x] = theta[x]/sum_theta;
174
+
175
+ fill_binomial_VK_table(bin, ntheta);
176
+
177
+ xfree(qt);
178
+ xfree(theta);
179
+ xfree(ntheta);
180
+ }
181
+
182
+ static void binomial_free(binomial_t *bin)
183
+ {
184
+ xfree(bin->p);
185
+ xfree(bin->T);
186
+ xfree(bin->K);
187
+ xfree(bin->V);
188
+ xfree(bin);
189
+ }
190
+
191
+ static VALUE binomial_alloc(VALUE klass)
192
+ {
193
+ binomial_t *bin;
194
+ VALUE obj = Data_Make_Struct(klass, binomial_t, 0, binomial_free, bin);
195
+ bin->n = -1;
196
+ bin->p = NULL; bin->T = NULL; bin->K = NULL; bin->V = NULL;
197
+ return obj;
198
+ }
199
+
200
+ /*
201
+ * Returns a random sampler from a binomial distribution.
202
+ *
203
+ * This sampler uses table plus square histgram method with
204
+ * Robin Hoot method. This method constructs a table for each
205
+ * distribution. If you once construct the table, you can
206
+ * draw a random sample fast for large n (n >= 40), but the
207
+ * cost of the table construction is expensive. Therefore,
208
+ * if you need to draw many samples from the same binomial distribution,
209
+ * you had better to use this class. Otherwise, you should use
210
+ * Random#binomial.
211
+ *
212
+ * @overload initialize(rng, n, theta)
213
+ * @param [Random] rng a random number generator
214
+ * @param [Integer] n the number of trials (n > 0)
215
+ * @param [Float] theta success probability (0 < theta < 1)
216
+ * @return [Random::Binomial] a random number generator from the specified binomial distribution
217
+ */
218
+ static VALUE binomial_initialize(VALUE self, VALUE rng, VALUE num, VALUE prob)
219
+ {
220
+ binomial_t *bin;
221
+ int n = NUM2INT(num);
222
+ double theta = NUM2DBL(prob);
223
+
224
+ check_binomial_params(n, theta, "Random::Binomial.new");
225
+
226
+ rb_iv_set(self, "rng", rng);
227
+ Data_Get_Struct(self, binomial_t, bin);
228
+ bin->n = n;
229
+ bin->theta = theta;
230
+ bin->p = ALLOC_N(double, bin->n + 1);
231
+
232
+ fill_binomial_table(bin);
233
+ fill_binomial_T_VT_table(bin);
234
+
235
+ return Qnil;
236
+ }
237
+
238
+ /*
239
+ * Draws a sample from the binomimial distribution whose parameters
240
+ * are specified in Random::Binomial.new.
241
+ *
242
+ * @return [Integer] a random sample
243
+ */
244
+ static VALUE binomial_rand(VALUE self)
245
+ {
246
+ VALUE rng = rb_iv_get(self, "rng");
247
+ binomial_t *bin;
248
+ uint32_t I0 = rb_random_int32(rng);
249
+ uint32_t ILk;
250
+ double U;
251
+ int J;
252
+
253
+ Data_Get_Struct(self, binomial_t, bin);
254
+
255
+ ILk = I0 & MASK(bin->k);
256
+ if (bin->T[ILk] >= 0)
257
+ return INT2NUM(bin->T[ILk]);
258
+
259
+ U = rb_random_real(rng);
260
+ J = floor((bin->n + 1)*U);
261
+ if (U < bin->V[J])
262
+ return INT2NUM(J);
263
+ else
264
+ return INT2NUM(bin->K[J]);
265
+ }
266
+
267
+ /*
268
+ * @!attribute [r] n
269
+ * @return [Integer] the parameter n
270
+ */
271
+ static VALUE binomial_n(VALUE self)
272
+ {
273
+ binomial_t *bin;
274
+ Data_Get_Struct(self, binomial_t, bin);
275
+
276
+ return INT2NUM(bin->n);
277
+ }
278
+
279
+ /*
280
+ * @!attribute [r] theta
281
+ * @return [Float] the parameter theta
282
+ */
283
+ static VALUE binomial_theta(VALUE self)
284
+ {
285
+ binomial_t *bin;
286
+ Data_Get_Struct(self, binomial_t, bin);
287
+
288
+ return DBL2NUM(bin->theta);
289
+ }
290
+
291
+ #if 0
292
+ static VALUE binomial_debug_info(VALUE self)
293
+ {
294
+ binomial_t *bin;
295
+ int i;
296
+
297
+ Data_Get_Struct(self, binomial_t, bin);
298
+
299
+
300
+ printf("N=%d\n", bin->N);
301
+ for (i=0; i<bin->N; ++i) {
302
+ printf("%d ", bin->T[i]);
303
+ }
304
+ puts("");
305
+ for (i=0; i<=bin->n; ++i) {
306
+ printf("%f %d\n", bin->V[i], bin->K[i]);
307
+ }
308
+ return Qnil;
309
+ }
310
+ #endif
311
+
312
+ void randomext_binomial_init(VALUE cRandom)
313
+ {
314
+ VALUE cBinomial = rb_define_class_under(cRandom, "Binomial", rb_cObject);
315
+
316
+ rb_define_method(cRandom, "binomial", random_binomial_inv, 2);
317
+ rb_define_alloc_func(cBinomial, binomial_alloc);
318
+ rb_define_method(cBinomial, "initialize", binomial_initialize, 3);
319
+ rb_define_method(cBinomial, "rand", binomial_rand, 0);
320
+ rb_define_method(cBinomial, "n", binomial_n, 0);
321
+ rb_define_method(cBinomial, "theta", binomial_theta, 0);
322
+ //rb_define_method(cBinomial, "debug_info", binomial_debug_info, 0);
323
+ }
@@ -0,0 +1,3 @@
1
+ require 'mkmf'
2
+
3
+ create_makefile('randomext_native')
@@ -0,0 +1,32 @@
1
+ #include "randomext.h"
2
+
3
+ /*
4
+ * @private
5
+ */
6
+ static VALUE random_gamma(VALUE self, VALUE shape)
7
+ {
8
+ double c, d;
9
+
10
+ if (NUM2DBL(shape) < 1.0)
11
+ rb_raise(rb_eArgError, "Random#_gamma: shape parameter must be >= 1.0");
12
+
13
+ d = NUM2DBL(shape) - 1.0/3.0;
14
+ c = 1/sqrt(9*d);
15
+
16
+ for (;;) {
17
+ double z, v, y, w, u;
18
+ z = randomext_random_standard_normal(self);
19
+ v = 1 + c*z;
20
+ if (v <= 0) continue;
21
+ w = v*v*v; y = d*w;
22
+ u = random_open_interval(self);
23
+ if (u > 1 - 0.0331*(z*z*z*z) && z*z/2 + d*log(w) - y + d < log(u))
24
+ continue;
25
+ return DBL2NUM(y);
26
+ }
27
+ }
28
+
29
+ void randomext_gamma_init(VALUE cRandom)
30
+ {
31
+ rb_define_private_method(cRandom, "_gamma", random_gamma, 1);
32
+ }
@@ -0,0 +1,81 @@
1
+ #include "randomext.h"
2
+
3
+ /* Returns HGeo(x+1| N, M, n)/HGeo(x| N, M, n) */
4
+ inline static double forward_ratio(int x, int N, int M, int n)
5
+ {
6
+ return (double)((M-x)*(n-x))/((x+1)*(N-M-n+x+1));
7
+ }
8
+
9
+ /* Returns HGeo(x-1| N, M, n)/HGeo(x| N, M, n) */
10
+ inline static double backward_ratio(int x, int N, int M, int n)
11
+ {
12
+ return 1.0/forward_ratio(x-1, N, M, n);
13
+ }
14
+
15
+ /* Returns HGeo(x| N, M, n) */
16
+ static inline double hypergeometric_distribution(int x, int N, int M, int n)
17
+ {
18
+ return exp(randomext_logcombination(M, x)
19
+ + randomext_logcombination(N-M, n-x)
20
+ - randomext_logcombination(N, n));
21
+ }
22
+
23
+ /*
24
+ * Draws a random sample from a hypergeometric distribution.
25
+ *
26
+ * Inverse method is used.
27
+ *
28
+ * @overload hypergeometric(N, M, n)
29
+ * @param [Integer] N a population (N >= 0)
30
+ * @param [Integer] M the number of successes (0 <= M <= N)
31
+ * @param [Integer] n the number of samples (0 <= n <= N)
32
+ * @return [Integer] a random sample in [max(0, n-(N-M)), min(n, M)]
33
+ */
34
+ static VALUE random_hypergoemtric_inv(VALUE self, VALUE vN, VALUE vM, VALUE vn)
35
+ {
36
+ int N = NUM2INT(vN);
37
+ int M = NUM2INT(vM);
38
+ int n = NUM2INT(vn);
39
+ int ok = (N >= 0) && (M >= 0) && (n >= 0) && (M <= N) && (n <= N);
40
+ int mode, x_min, x_max, xu, xl;
41
+ double pl, pu;
42
+ double u;
43
+
44
+ if (!ok)
45
+ rb_raise(rb_eArgError,
46
+ "Random#hypergeometric: paramters must be:"
47
+ "(N >= 0) && (M >= 0) && (n >= 0) && (M <= N) && (n <= N)");
48
+
49
+ mode = (M+1)*(n+1) / (N+2);
50
+ x_min = MAX2(0, n - (N-M));
51
+ x_max = MIN2(n, M);
52
+ xu = mode;
53
+ pu = hypergeometric_distribution(mode, N, M, n);
54
+ xl = mode-1;
55
+ pl = pu * backward_ratio(mode, N, M, n);
56
+ u = rb_random_real(self);
57
+
58
+ for (;x_min <= xl || xu <= x_max;) {
59
+ if (xu <= x_max) {
60
+ if (u <= pu)
61
+ return INT2NUM(xu);
62
+ u -= pu;
63
+ pu *= forward_ratio(xu, N, M, n);
64
+ ++xu;
65
+ }
66
+ if (xl >= x_min) {
67
+ if (u <= pl)
68
+ return INT2NUM(xl);
69
+ u -= pl;
70
+ pl *= backward_ratio(xl, N, M, n);
71
+ --xl;
72
+ }
73
+ }
74
+
75
+ return INT2NUM(x_min);
76
+ }
77
+
78
+ void randomext_hypergeometric_init(VALUE cRandom)
79
+ {
80
+ rb_define_method(cRandom, "hypergeometric", random_hypergoemtric_inv, 3);
81
+ }
@@ -0,0 +1,122 @@
1
+ #include "randomext.h"
2
+
3
+ /*
4
+ * Draws a random sample from a von Mises distribution.
5
+ *
6
+ * The return value is contained in [-PI, PI].
7
+ *
8
+ * @overload vonmises(mu, kappa)
9
+ * @param [Float] mu direction parameter (-PI <= mu <= PI)
10
+ * @param [Float] kappa concentration parameter (kappa > 0)
11
+ * @return [Float] A random sample in [-PI, PI]
12
+ */
13
+ static VALUE random_vonmises(VALUE self, VALUE vmu, VALUE vkappa)
14
+ {
15
+ double mu = NUM2DBL(vmu);
16
+ double kappa = NUM2DBL(vkappa);
17
+ double s;
18
+
19
+ if (kappa <= 0)
20
+ rb_raise(rb_eArgError, "Random#vonmises: parameter kappa must be positive");
21
+
22
+ s = (1 + sqrt(1+4*kappa*kappa))/(2*kappa);
23
+
24
+ for (;;) {
25
+ double u = rb_random_real(self);
26
+ double z = cos(2*M_PI*u);
27
+ double W = (1-s*z)/(s-z);
28
+ double T = kappa*(s-W);
29
+ double U = rb_random_real(self);
30
+ double V = rb_random_real(self);
31
+ double x, y;
32
+
33
+ if (V > T*(2-T) && V > T*exp(1-T))
34
+ continue;
35
+
36
+ if (U < 0.5)
37
+ y = -acos(W);
38
+ else
39
+ y = acos(W);
40
+ x = y + mu;
41
+ if (x >= M_PI)
42
+ return DBL2NUM(x - M_PI);
43
+ else if (x < -M_PI)
44
+ return DBL2NUM(x + M_PI);
45
+ else
46
+ return DBL2NUM(x);
47
+ }
48
+ }
49
+
50
+ /*
51
+ * Draws a random sample from a Zipf-Mandelbrot distribution.
52
+ *
53
+ * In case of q == 0.0, the distribution is called a Zipf distribution.
54
+ *
55
+ * @overload zipf_mandelbrot(n, q=0.0, s=1.0)
56
+ * @param [Integer] n the maximum of return value (n > 0)
57
+ * @param [Float] q a parameter (q >= 0.0)
58
+ * @param [Float] s a parameter (s > 0.0)
59
+ * @return [Integer] a random sample in 1..n
60
+ */
61
+ static VALUE random_zipf(int argc, VALUE *argv, VALUE self)
62
+ {
63
+ VALUE vN, vs, vq;
64
+ int N;
65
+ double s, q;
66
+ double sum;
67
+ int i;
68
+ double u;
69
+
70
+ rb_scan_args(argc, argv, "12", &vN, &vq, &vs);
71
+ N = NUM2INT(vN);
72
+ s = NIL_P(vs) ? 1.0 : NUM2DBL(vs);
73
+ q = NIL_P(vq) ? 0.0 : NUM2DBL(vq);
74
+
75
+ if (N <= 0 || s <= 0 || q < 0)
76
+ rb_raise(rb_eArgError, "Random#zipf_mandelbrot: parameters must be N >0, s > 0, q >= 0");
77
+
78
+ for (i=1, sum=0; i<=N; ++i)
79
+ sum += 1.0/pow(i+q, s);
80
+
81
+ u = rb_random_real(self);
82
+
83
+ for (i=1; i<=N; ++i) {
84
+ double p = 1.0/pow(i+q, s)/sum;
85
+ if (u <= p)
86
+ return INT2NUM(i);
87
+ u -= p;
88
+ }
89
+
90
+ return INT2NUM(N);
91
+ }
92
+
93
+ /*
94
+ * Draws a random sample from a zeta distribution.
95
+ *
96
+ * @overload zeta(s)
97
+ * @param [Integer] s a parameter (s > 0.0)
98
+ * @return [Integer] a random sample in [1, INFINITY)
99
+ */
100
+ static VALUE random_zeta(VALUE self, VALUE vs)
101
+ {
102
+ double s = NUM2DBL(vs);
103
+ double q = s - 1.0;
104
+ double r = -1.0/q;
105
+ double t = pow(2.0, q);
106
+
107
+ for (;;) {
108
+ double u = 1.0 - rb_random_real(self);
109
+ double v = rb_random_real(self);
110
+ int x = floor(pow(u, r));
111
+ double w = pow(1.0 + 1.0/x, q);
112
+ if (v*x*(w-1)/(t-1) <= w/t)
113
+ return INT2NUM(x);
114
+ }
115
+ }
116
+
117
+ void randomext_other_init(VALUE cRandom)
118
+ {
119
+ rb_define_method(cRandom, "vonmises", random_vonmises, 2);
120
+ rb_define_method(cRandom, "zipf_mandelbrot", random_zipf, -1);
121
+ rb_define_method(cRandom, "zeta", random_zeta, 1);
122
+ }
@@ -0,0 +1,65 @@
1
+ #include "randomext.h"
2
+
3
+ static double poisson_distribution(int m, double lambda)
4
+ {
5
+ return exp(-lambda + m*log(lambda) - randomext_sumlog(1, m));
6
+ }
7
+
8
+ /* Returns Poi(x+1|lambda)/Poi(x|lambda) */
9
+ static inline double forward_ratio(int x, double lambda)
10
+ {
11
+ return lambda/(x+1);
12
+ }
13
+
14
+ /* Returns Poi(x-1|lambda)/Poi(x|lambda) */
15
+ static inline double backward_ratio(int x, double lambda)
16
+ {
17
+ return x/lambda;
18
+ }
19
+
20
+ /*
21
+ * Draws a random sample from a Poisson distribution.
22
+ *
23
+ * Inverse function method is used.
24
+ *
25
+ * @overload poisson(lambda)
26
+ * @param [Float] lambda mean
27
+ * @return [Integer] a random sample in [0, INFINITY)
28
+ */
29
+ static VALUE random_poisson_inv(VALUE self, VALUE l)
30
+ {
31
+ double lambda = NUM2DBL(l);
32
+ int mode, xu, xl;
33
+ double pu, pl, u;
34
+
35
+ if (lambda <= 0.0)
36
+ rb_raise(rb_eArgError, "Random#poisson: lambda must be positive");
37
+
38
+ mode = floor(lambda);
39
+ xu = mode;
40
+ xl = mode - 1;
41
+ pu = poisson_distribution(mode, lambda);
42
+ pl = pu * backward_ratio(xu, lambda);
43
+ u = rb_random_real(self);
44
+
45
+ for (;;) {
46
+ if (u <= pu)
47
+ return INT2NUM(xu);
48
+ u = u - pu;
49
+ pu *= forward_ratio(xu, lambda);
50
+ ++xu;
51
+
52
+ if (xl >= 0) {
53
+ if (u <= pl)
54
+ return INT2NUM(xl);
55
+ u = u - pl;
56
+ pl *= backward_ratio(xl, lambda);
57
+ --xl;
58
+ }
59
+ }
60
+ }
61
+
62
+ void randomext_poisson_init(VALUE cRandom)
63
+ {
64
+ rb_define_method(cRandom, "poisson", random_poisson_inv, 1);
65
+ }
@@ -0,0 +1,27 @@
1
+ #include <ruby.h>
2
+ #include <math.h>
3
+ #include <stdint.h>
4
+
5
+ double randomext_random_standard_normal(VALUE random);
6
+ double randomext_sumlog(int from, int to);
7
+ double randomext_logcombination(int n, int m);
8
+
9
+ inline static uint64_t pow2(int r)
10
+ {
11
+ return (uint64_t)1<<r;
12
+ }
13
+
14
+ inline static double random_open_interval(VALUE random)
15
+ {
16
+ for (;;) {
17
+ double u = rb_random_real(random);
18
+ if (u != 0.0) return u;
19
+ }
20
+ }
21
+
22
+ #define MASK(bits) (~(~0<<(bits)))
23
+ #define BIT(nth) (1<<(nth))
24
+
25
+ #define MAX2(n, m) (((n) < (m)) ? (m) : (n))
26
+ #define MIN2(n, m) (((n) < (m)) ? (n) : (m))
27
+
@@ -0,0 +1,76 @@
1
+ #include "randomext.h"
2
+
3
+ #define SUMLOG_TABLE_SIZE_INIT 1024
4
+ #define SUMLOG_TABLE_SIZE_MAX (1024*32)
5
+
6
+ /* sumlog_table[0] = 0 */
7
+ /* sumlog_table[i] = log(1) + log(2) + ... + log(i) */
8
+ static double* sumlog_table = NULL;
9
+ static int sumlog_table_size = -1;
10
+
11
+ static inline void setup_sumlog_table(int need)
12
+ {
13
+ int old_sumlog_table_size;
14
+ int i;
15
+
16
+ if (sumlog_table_size > need || need >= SUMLOG_TABLE_SIZE_MAX)
17
+ return;
18
+
19
+ if (sumlog_table == NULL) {
20
+ sumlog_table_size = SUMLOG_TABLE_SIZE_INIT;
21
+ sumlog_table = ALLOC_N(double, sumlog_table_size);
22
+ sumlog_table[0] = 0;
23
+ old_sumlog_table_size = 1;
24
+ } else {
25
+ old_sumlog_table_size = sumlog_table_size;
26
+ }
27
+
28
+ for (;sumlog_table_size < need; sumlog_table_size <<= 1)
29
+ ;
30
+
31
+ REALLOC_N(sumlog_table, double, sumlog_table_size);
32
+
33
+ for (i = old_sumlog_table_size; i < sumlog_table_size; ++i) {
34
+ sumlog_table[i] = sumlog_table[i-1] + log(i);
35
+ }
36
+ }
37
+
38
+ double randomext_sumlog(int from, int to)
39
+ {
40
+ int i;
41
+ double ret = 0.0;
42
+
43
+ setup_sumlog_table(to);
44
+ if (to < SUMLOG_TABLE_SIZE_MAX)
45
+ return sumlog_table[to] - sumlog_table[from-1];
46
+
47
+ for (i=from; i<=to; ++i)
48
+ ret += log(i);
49
+ return ret;
50
+ }
51
+
52
+ double randomext_logcombination(int n, int m)
53
+ {
54
+ return randomext_sumlog(n-m+1, n) - randomext_sumlog(1, m);
55
+ }
56
+
57
+ extern void randomext_standard_normal_init(VALUE cRandom);
58
+ extern void randomext_standard_exponential_init(VALUE cRandom);
59
+ extern void randomext_gamma_init(VALUE cRandom);
60
+ extern void randomext_binomial_init(VALUE cRandom);
61
+ extern void randomext_poisson_init(VALUE cRandom);
62
+ extern void randomext_hypergeometric_init(VALUE cRandom);
63
+ extern void randomext_other_init(VALUE cRandom);
64
+
65
+ void Init_randomext_native()
66
+ {
67
+ VALUE cRandom = rb_const_get(rb_cObject, rb_intern("Random"));
68
+
69
+ randomext_standard_normal_init(cRandom);
70
+ randomext_standard_exponential_init(cRandom);
71
+ randomext_gamma_init(cRandom);
72
+ randomext_binomial_init(cRandom);
73
+ randomext_poisson_init(cRandom);
74
+ randomext_hypergeometric_init(cRandom);
75
+ randomext_other_init(cRandom);
76
+ }
@@ -0,0 +1,79 @@
1
+ #include "randomext.h"
2
+
3
+ #define K 8
4
+ #define n (1<<K)
5
+ #define v 0.00394965982258
6
+ #define r 7.697117470131
7
+ #define m 64
8
+
9
+ static double* w = NULL;
10
+ static double* f;
11
+ static uint64_t* k;
12
+
13
+ void init_exponentail_table(void)
14
+ {
15
+ double xi;
16
+ int i;
17
+
18
+ w = ALLOC_N(double, n);
19
+ f = ALLOC_N(double, n);
20
+ k = ALLOC_N(uint64_t, n);
21
+
22
+ w[n-1] = v*exp(r)/pow2(m-K);
23
+ w[n-2] = r/pow2(m-K);
24
+ k[n-1] = floor(r/w[n-1]);
25
+ f[n-1] = exp(-r);
26
+ xi = r;
27
+
28
+ for (i=n-2; i >= 1; --i) {
29
+ xi = -log(exp(-xi) + v/xi);
30
+ w[i-1] = xi/pow2(m-K);
31
+ k[i] = floor(xi/w[i]);
32
+ f[i] = exp(-xi);
33
+ }
34
+ k[0] = 0;
35
+ f[0] = 1;
36
+ }
37
+
38
+ static double standard_exponential(VALUE rng)
39
+ {
40
+ uint32_t u1;
41
+ uint32_t i;
42
+ uint64_t u2;
43
+
44
+ if (w == NULL)
45
+ init_exponentail_table();
46
+
47
+ retry:
48
+ u1 = rb_random_int32(rng);
49
+ i = MASK(K) & u1;
50
+ u2 = (uint64_t)rb_random_int32(rng) | (((uint64_t)u1 >> K) << 32);
51
+
52
+ if (u2 < k[i])
53
+ return (double)u2 * w[i];
54
+ if (i == n-1) {
55
+ double u = rb_random_real(rng);
56
+ return r - log(1-u);
57
+ } else {
58
+ double ux = u2*w[i];
59
+ double u = rb_random_real(rng);
60
+ if (u*(f[i]-f[i+1]) <= exp(-ux) - f[i+1])
61
+ return ux;
62
+ goto retry;
63
+ }
64
+ }
65
+
66
+ /*
67
+ * Draws a random sample from the standard exponential distribution.
68
+ *
69
+ * @return [Float] a random sample
70
+ */
71
+ static VALUE random_standard_exp(VALUE self)
72
+ {
73
+ return DBL2NUM(standard_exponential(self));
74
+ }
75
+
76
+ void randomext_standard_exponential_init(VALUE cRandom)
77
+ {
78
+ rb_define_method(cRandom, "standard_exponential", random_standard_exp, 0);
79
+ }
@@ -0,0 +1,94 @@
1
+ #include "randomext.h"
2
+
3
+ #define R 3.442619855899
4
+ #define V 9.91256303526217e-3
5
+ #define K 7
6
+ #define M 64
7
+ #define N (1<<K)
8
+
9
+ static double* w = NULL;
10
+ static uint64_t* k;
11
+ static double* f;
12
+
13
+ inline static double sn(double x)
14
+ {
15
+ return exp(-x*x/2);
16
+ }
17
+
18
+ static void init_snormal_table(void)
19
+ {
20
+ int i;
21
+ double xi;
22
+
23
+ w = ALLOC_N(double, N);
24
+ k = ALLOC_N(uint64_t, N);
25
+ f = ALLOC_N(double, N);
26
+
27
+ w[N-1] = V*exp(R*R/2)/pow2(M-K-1);
28
+ w[N-2] = R/pow2(M-K-1);
29
+ k[N-1] = floor(R/w[N-1]);
30
+ f[N-1] = sn(R);
31
+ xi = R;
32
+
33
+ for (i=N-2; i>=1; --i) {
34
+ xi = sqrt(-2*log(sn(xi)+V/xi));
35
+ w[i-1] = xi/pow2(M-K-1);
36
+ k[i] = floor(xi/w[i]);
37
+ f[i] = sn(xi);
38
+ }
39
+ k[0] = 0;
40
+ f[0] = 1;
41
+ }
42
+
43
+ static double sample_from_tail(VALUE random)
44
+ {
45
+ for (;;) {
46
+ double x = sqrt(R*R-2*log(1-rb_random_real(random)));
47
+ if (x*rb_random_real(random) <= R)
48
+ return x;
49
+ }
50
+ }
51
+
52
+ double randomext_random_standard_normal(VALUE random)
53
+ {
54
+ int i;
55
+ uint64_t u;
56
+ int sign;
57
+ double ux;
58
+
59
+ if (w == NULL)
60
+ init_snormal_table();
61
+
62
+ for (;;) {
63
+ unsigned int u0 = rb_random_int32(random);
64
+ i = u0 & MASK(K);
65
+ sign = (u0 & BIT(K)) ? 1 : -1;
66
+ u = ((uint64_t)(u0 >> (K+1)) << 32) | rb_random_int32(random);
67
+
68
+ if (u < k[i])
69
+ return sign*(u*w[i]);
70
+ if (i == N-1)
71
+ return sign*sample_from_tail(random);
72
+ ux = u * w[i];
73
+ if ( rb_random_real(random)*(f[i]-f[i+1]) <= sn(ux)-f[i+1])
74
+ return sign*ux;
75
+ }
76
+
77
+ }
78
+
79
+ /*
80
+ * Draws a random sample from the standard normal distribution.
81
+ *
82
+ * Ziggurat method is used for random sampling.
83
+ *
84
+ * @return [Float] a random sample
85
+ */
86
+ static VALUE random_standard_normal(VALUE self)
87
+ {
88
+ return DBL2NUM(randomext_random_standard_normal(self));
89
+ }
90
+
91
+ void randomext_standard_normal_init(VALUE cRandom)
92
+ {
93
+ rb_define_method(cRandom, "standard_normal", random_standard_normal, 0);
94
+ }
@@ -0,0 +1,373 @@
1
+ require 'randomext_native'
2
+
3
+ class Random
4
+ # Draws a random sample from a normal(Gaussian) distribution.
5
+ #
6
+ # @param [Float] mean mean
7
+ # @param [Float] sd standard deviarion
8
+ # @return [Float] a random sample
9
+ def normal(mean=0.0, sd=1.0)
10
+ mean + standard_normal()*sd
11
+ end
12
+
13
+ # Draws a random sample from a log normal distribution.
14
+ #
15
+ # The probabilistic mass function of lognormal distribution is defined:
16
+ #
17
+ # 1/sqrt(2*PI*sigma**2)*exp(-(log(x)-mu)**2/(2*sigma**2))
18
+ #
19
+ # @param [Float] mu the mean in a normal distribution
20
+ # @param [Float] sigma the standard deviarion in a normal distribution
21
+ # @return [Float] a random sample in (0, INFINITY)
22
+ def lognormal(mu=0.0, sigma=1.0)
23
+ Math.exp(normal(mu, sigma))
24
+ end
25
+
26
+ # Draws a random sample from a Cauthy distribution.
27
+ #
28
+ # @param [Float] loc location parameter
29
+ # @param [Float] scale scale parameter
30
+ # @return [Float] a random sample
31
+ def cauthy(loc, scale)
32
+ loc + scale*standard_cauthy()
33
+ end
34
+
35
+ # Draws a random sample from the standard Cauthy distribution.
36
+ #
37
+ # Computed using Polar method from the standard normal distribution.
38
+ # @return [Float] a random sample
39
+ def standard_cauthy
40
+ y1 = standard_normal()
41
+ begin; y2 = standard_normal(); end until y2 != 0.0
42
+ return y1/y2
43
+ end
44
+
45
+ # Draws a random sample from a Levy distribution.
46
+ #
47
+ # @param [Float] loc location parameter
48
+ # @param [Float] scale scale parameter
49
+ # @return [Float] a random sample
50
+ def levy(loc=0.0, scale=1.0)
51
+ begin z = standard_normal.abs; end until z > 0
52
+ loc + scale/z**2
53
+ end
54
+
55
+ # Draws a random sample from a exponential distribution.
56
+ #
57
+ # Inverse function method is used.
58
+ # @param [Float] scale scale parameter (scale > 0)
59
+ # @return [Float] a random sample
60
+ def exponential(scale=1.0)
61
+ if scale < 0.0
62
+ raise ArgumentError, "Random#exponential: scale parameter must be positive"
63
+ end
64
+ scale * standard_exponential
65
+ end
66
+
67
+ # Draws a random sample from a Laplace distribution
68
+ #
69
+ # @param [Float] loc location parameter
70
+ # @param [Float] scale scale parameter
71
+ # @return [Float] a random sample
72
+ def laplace(loc=0.0, scale=1.0)
73
+ sign = rand(2) == 1 ? 1 : -1
74
+ loc + sign*scale*standard_exponential
75
+ end
76
+
77
+ # Draws a random sample from a Rayleigh distribution
78
+ #
79
+ # @param [Float] sigma scale parameter
80
+ # @return [Float] a random sample
81
+ def rayleigh(sigma=1.0)
82
+ sigma*Math.sqrt(2*standard_exponential)
83
+ end
84
+
85
+ # Draws a random sample from a Weibull distribution
86
+ #
87
+ # @param [Float] g shape parameter (g > 0.0)
88
+ # @param [Float] mu scale parameter
89
+ # @return [Float] a random sample
90
+ def weibull(g, mu=1.0)
91
+ if g <= 0
92
+ raise ArgumentError, "Random#weibull: shape parameter must be positive"
93
+ end
94
+ mu * standard_exponential**(1.0/g)
95
+ end
96
+
97
+ # Draws a random sample from a Gumbel distribution
98
+ #
99
+ # @param [Float] loc location parameter
100
+ # @param [Float] scale scale parameter
101
+ # @return [Float] a random sample
102
+ def gumbel(loc=0.0, scale=1.0)
103
+ loc - scale * Math.log(standard_exponential)
104
+ end
105
+
106
+ # Draws a random sample from a gamma distribution
107
+ #
108
+ # @param [Float] shape shape parameter (shape > 0.0)
109
+ # @param [Float] scale scale parameter (scale > 0.0)
110
+ # @return [Float] a random sample
111
+ def gamma(shape, scale=1.0)
112
+ if scale <= 0.0
113
+ raise ArgumentError, "Random#gamma: scale parameter must be positive"
114
+ end
115
+
116
+ case
117
+ when shape <= 0.0
118
+ raise ArgumentError, "Random#gamma: shape parameter must be positive"
119
+ when shape > 1.0
120
+ scale * _gamma(shape)
121
+ when shape == 1.0
122
+ exponential(scale)
123
+ when shape < 1.0
124
+ scale*_gamma(shape+1)*rand_open_interval**(1.0/shape)
125
+ end
126
+ end
127
+
128
+ # Draws a random sample from a beta distribution.
129
+ #
130
+ # @param [Float] alpha a shape parameter (alpha > 0.0)
131
+ # @param [Float] beta another shape parameter (beta > 0.0)
132
+ # @return [Float] a random sample
133
+ def beta(alpha, beta)
134
+ y1 = gamma(alpha); y2 = gamma(beta)
135
+ y1/(y1+y2)
136
+ end
137
+
138
+ # Draws a random sample from a Dirichlet distribution.
139
+ #
140
+ # @param [Array<Float>] as shape parameters
141
+ # @return [Array<Float>] a random sample in the (K-1)-dimensional simplex (K == as.size)
142
+ def dirichlet(*as)
143
+ if as.any?{|a| a <= 0.0}
144
+ raise ArgumentError, "Random#dirichlet: parameters must be positive"
145
+ end
146
+
147
+ ys = as.map{|a| gamma(a) }
148
+ sum = ys.inject(0.0, &:+)
149
+ ys.map{|y| y/sum }
150
+ end
151
+
152
+ # Draws a random sample from a power function distribution
153
+ #
154
+ # @param [Float] shape shape parameter (shape > 0.0)
155
+ # @param [Float] a lower boundary parameter
156
+ # @param [Float] b upper boundary parameter (a < b)
157
+ # @return [Float] a random sample
158
+ def power(shape, a, b)
159
+ if shape <= 0 || a >= b
160
+ raise ArgumentError, "Random#power: shape must be positive, and b should be greater than a"
161
+ end
162
+
163
+ a + (b-a)*(rand_open_interval**(1/shape))
164
+ end
165
+ # Draw a random sample from a chi_square distribution.
166
+ #
167
+ # @param [Integer] r degree of freedom (r >= 1)
168
+ # @return [Float] a random sample
169
+ def chi_square(r)
170
+ if r == 1
171
+ standard_normal ** 2
172
+ elsif r > 1
173
+ gamma(r*0.5, 2)
174
+ else
175
+ raise ArgumentError, "Random#chi_square:r (degree of freedom) must be >= 1"
176
+ end
177
+ end
178
+
179
+ # Draws a random sample from a F distribution.
180
+ #
181
+ # @param [Integer] r1 degree of freedom (r1 >= 1)
182
+ # @param [Integer] r2 degree of freedom (r2 >= 1)
183
+ # @return [Float] a random sample
184
+ def F(r1, r2)
185
+ f = r2 / r1.to_f
186
+ f*chi_square(r1)/chi_square(r2)
187
+ end
188
+
189
+ # Draws a random sample from a t distribution.
190
+ #
191
+ # @param [Integer] r degree of freedom (r >= 1)
192
+ # @return [Float] a random sample
193
+ def t(r)
194
+ if r ==1
195
+ standard_cauthy
196
+ elsif r == 2
197
+ standard_normal/Math.sqrt(exponential(1))
198
+ elsif r > 2
199
+ rdiv2 = r/2.0
200
+ Math.sqrt(rdiv2)*standard_normal/Math.sqrt(_gamma(rdiv2))
201
+ else
202
+ raise ArgumentError, "Random#t: r (degree of freedom) must be >= 1"
203
+ end
204
+ end
205
+
206
+ # Draws a random sample from a wald distribution.
207
+ #
208
+ # A wald distribution is also called an inverse Gaussian distribution.
209
+ #
210
+ # @param [Float] mean mean
211
+ # @param [Float] shape shape parameter (shape > 0.0)
212
+ # @return [Float] a random sample in (0, INFINITY)
213
+ def wald(mean, shape)
214
+ if shape <= 0.0
215
+ raise ArgumentError, "Random#wald: shape parameter must be positive"
216
+ end
217
+ p = mean**2
218
+ q = p/(2*shape)
219
+ z = standard_normal
220
+ return mean if z == 0.0
221
+ v = mean + q*z**2
222
+ x1 = v + Math.sqrt(v**2-p)
223
+ return x1 if rand*(x1 + mean) <= mean
224
+ return p/x1
225
+ end
226
+
227
+ # Draws a random sample from a Pareto distribution.
228
+ #
229
+ # The probabilistic mass function for the distribution is defined as:
230
+ #
231
+ # p(x) = a*b**a/x**(a+1)
232
+ #
233
+ # @param [Float] a shape parameter (a > 0.0)
234
+ # @param [Float] b scale parameter (b > 0.0)
235
+ # @return [Float] a random sample in [b, INFINITY)
236
+ def pareto(a, b=1.0)
237
+ if a <= 0 || b <= 0
238
+ raise ArgumentError, "Random#pareto: parameters a and b must be positive"
239
+ end
240
+ b * (1.0 - rand)**(-1/a)
241
+ end
242
+
243
+ # Draws a random sample from a logistic distribution.
244
+ #
245
+ # @param [Float] mu the location parameter
246
+ # @param [Float] theta the scale parameter
247
+ # @return [Float] a random sample
248
+ def logistic(mu, theta)
249
+ u = rand_open_interval
250
+ mu + theta*log(u/(1-u))
251
+ end
252
+
253
+ # Draws a random sample from a Non-Central Chi-Square distribution.
254
+ #
255
+ # @param [Integer] r a parameter (r > 0)
256
+ # @param [Float] lambda another parameter (lambda > 0)
257
+ # @return [Float] a random sample in (0, INFINITY)
258
+ def non_central_chi_square(r, lambda)
259
+ if lambda < 0.0
260
+ raise ArgumentError, "Random#non_central_chi_square: lambda must be positive"
261
+ end
262
+ if !r.integer? || r <= 0
263
+ raise ArgumentError, "Random#non_central_chi_square: r must be positive integer"
264
+ end
265
+ j = poisson(lambda/2)
266
+ chi_square(r + 2*j)
267
+ end
268
+
269
+ # Draws a random sample from a Non-Central t distribution
270
+ #
271
+ # @param [Integer] r a parameter (r > 0)
272
+ # @param [Float] lambda another parameter (lambda > 0)
273
+ # @return [Float] a random sample
274
+ def non_central_t(r, lambda)
275
+ if lambda == 0.0
276
+ raise ArgumentError, "Random#non_central_t: lambda must not be 0"
277
+ end
278
+
279
+ if r == 1
280
+ z = standard_normal + lambda
281
+ w = standard_normal.abs
282
+ z/w
283
+ elsif r == 2
284
+ z = standard_normal + lambda
285
+ w = standard_exponential
286
+ z/Math.sqrt(w)
287
+ elsif r > 2
288
+ d = Math.sqrt(r/2.0)
289
+ z = standard_normal + lambda
290
+ w = _gamma(r/2.0)
291
+ d*z/Math.sqrt(w)
292
+ else
293
+ raise ArgumentError, "Random#non_central_t: r must be positive"
294
+ end
295
+ end
296
+
297
+ # Draw a random sample from a Bernoulli distribution.
298
+ #
299
+ # @param [Float] p the probability returning 1
300
+ # @return [Integer] a random sample, 0 or 1
301
+ def bernoulli(p)
302
+ (rand < p) ? 1 : 0
303
+ end
304
+
305
+ # Draws a random sample from a geometric distribution.
306
+ #
307
+ # @param [Float] theta the probability of sucess (0 < theta < 1)
308
+ # @return [Integer] a random sample in [1, INFINITY)
309
+ def geometric(theta)
310
+ if theta <= 0.0 || theta >= 1.0
311
+ raise ArgumentError, "Random#geometric: theta should be in (0, 1)"
312
+ end
313
+
314
+ d= -1/(Math.log(1-theta))
315
+ (d * standard_exponential).floor + 1
316
+ end
317
+
318
+ # Draws a random sample from a Planck distribution.
319
+ #
320
+ # @param [Float] a shape parameter
321
+ # @param [Float] b scale parameter
322
+ # @return [Float] a random sample in (0, INFINITY)
323
+ def planck(a, b)
324
+ if a <= 0 || b <= 0
325
+ raise ArgumentError, "Random#planck: parameters must be positive"
326
+ end
327
+
328
+ y = _gamma(a+1)
329
+ j = zeta(a+1)
330
+ b*y/j
331
+ end
332
+
333
+ # Draws a random sample from a negative binomial distribution.
334
+ #
335
+ # @param [Float] r s parameter (0 < r)
336
+ # @param [Float] theta a parameter (0 < theta < 1)
337
+ # @return [Integer] a random sample in [0, INFINITY)
338
+ def negative_binomial(r, theta)
339
+ if r <= 0.0
340
+ raise ArgumentError, "Random#negative_binomial: r must be positive"
341
+ end
342
+ if theta <= 0.0 && theta >= 1.0
343
+ raise ArgumentError, "Random#negative_binomial: theta must be in (0, 1)"
344
+ end
345
+ poisson(gamma(r, 1/theta - 1))
346
+ end
347
+
348
+ # Draws a random sample from a log series distribution.
349
+ #
350
+ # @param [Float] theta a parameter (0 < theta < 1)
351
+ # @return [Integer] a random sample in [0, INFINITY)
352
+ def logseries(theta)
353
+ if theta <= 0 || 1 <= theta
354
+ raise ArgumentError, "Random#logseries: theta must be in (0, 1)"
355
+ end
356
+ q = 1 - theta
357
+ v = rand_open_interval
358
+ if v >= theta
359
+ 1
360
+ else
361
+ u = rand_open_interval
362
+ (log(v)/log(1-q**u)).ceil
363
+ end
364
+ end
365
+
366
+ # Draw a sample from the uniform distribution on (0, 1)
367
+ #
368
+ # @return [Float] a random sample in (0, 1)
369
+ def rand_open_interval
370
+ begin; x = rand; end until x != 0.0
371
+ x
372
+ end
373
+ end
metadata ADDED
@@ -0,0 +1,60 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: randomext
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ippei Obayashi
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-11-14 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: ! "This library extends class Random in the Ruby standard library.\nThe
15
+ Random class in the Ruby standard library supports only \nrandom sampling from discrete/continuous
16
+ uniform distribution.\n\nThis library provides random sampling methods from \nmany
17
+ kinds of probability distributions such as normal, gamma,\nbeta, chi_square, t,
18
+ F, binomial, Poisson, and many other\ndistributions.\n"
19
+ email: ohai@kmc.gr.jp
20
+ executables: []
21
+ extensions:
22
+ - ext/extconf.rb
23
+ extra_rdoc_files: []
24
+ files:
25
+ - lib/randomext.rb
26
+ - ext/extconf.rb
27
+ - ext/standard_exponential.c
28
+ - ext/randomext.h
29
+ - ext/other.c
30
+ - ext/hypergeometric.c
31
+ - ext/randomext_native.c
32
+ - ext/poisson.c
33
+ - ext/binomial.c
34
+ - ext/gamma.c
35
+ - ext/standard_normal.c
36
+ homepage: http://www.kmc.gr.jp/~ohai/randomext/
37
+ licenses: []
38
+ post_install_message:
39
+ rdoc_options: []
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ requirements: []
55
+ rubyforge_project:
56
+ rubygems_version: 1.8.23
57
+ signing_key:
58
+ specification_version: 3
59
+ summary: This library extend Random class of Ruby standard library
60
+ test_files: []