randomext 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []