Skip to content
This repository
Newer
Older
100644 881 lines (814 sloc) 21.85 kb
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
1 /*
2 * Random Numbers.
3 *
4 * This file is covered by the Ruby license. See COPYING for more details.
5 *
6 * Copyright (C) 2007-2010, Apple Inc. All rights reserved.
7 * Copyright (C) 1993-2007 Yukihiro Matsumoto
8 */
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
9
468a2ea9 » Thibault Martin-Lagardette
2010-07-08 Move Obj-C related headers around.
10 #include "ruby/macruby.h"
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
11 #include "ruby/node.h"
12 #include "vm.h"
13 #include "id.h"
cb8cef0c » Laurent Sansonetti
2010-02-17 migrating bytestrings + misc cleanup
14 #include "encoding.h"
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
15
16 #include <unistd.h>
17 #include <time.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <fcntl.h>
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
21 #include <math.h>
22 #include <errno.h>
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
23
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
24 #include "mt.c"
8f9d863c » Laurent Sansonetti
2009-10-16 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
25
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
26 VALUE rb_cRandom;
8f9d863c » Laurent Sansonetti
2009-10-16 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
27
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
28 typedef struct {
29 VALUE seed;
30 struct MT mt;
31 } rb_random_t;
32
33 #define get_rnd(obj) ((rb_random_t *)DATA_PTR(obj))
34 #define default_rnd() (get_rnd(rb_vm_default_random()))
35
36 unsigned int
37 rb_genrand_int32(void)
38 {
39 return genrand_int32(&default_rnd()->mt);
40 }
41
42 double
43 rb_genrand_real(void)
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
44 {
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
45 return genrand_real(&default_rnd()->mt);
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
46 }
47
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
48 #define BDIGITS(x) (RBIGNUM_DIGITS(x))
49 #define BITSPERDIG (SIZEOF_BDIGITS*CHAR_BIT)
50 #define BIGRAD ((BDIGIT_DBL)1 << BITSPERDIG)
51 #define DIGSPERINT (SIZEOF_INT/SIZEOF_BDIGITS)
52 #define BIGUP(x) ((BDIGIT_DBL)(x) << BITSPERDIG)
53 #define BIGDN(x) RSHIFT(x,BITSPERDIG)
54 #define BIGLO(x) ((BDIGIT)((x) & (BIGRAD-1)))
55 #define BDIGMAX ((BDIGIT)-1)
56
57 #define roomof(n, m) (int)(((n)+(m)-1) / (m))
58 #define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
59 #define SIZEOF_INT32 (31/CHAR_BIT + 1)
60
61 static VALUE random_seed(VALUE, SEL);
62
63 /* :nodoc: */
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
64 static VALUE
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
65 random_alloc(VALUE klass, SEL sel)
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
66 {
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
67 rb_random_t *r = (rb_random_t *)xmalloc(sizeof(rb_random_t));
68 r->seed = INT2FIX(0);
69 return Data_Wrap_Struct(rb_cRandom, NULL, NULL, r);
70 }
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
71
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
72 static VALUE
73 rand_init(struct MT *mt, VALUE vseed)
74 {
75 VALUE seed;
76 long blen = 0;
77 int i, j, len;
78 unsigned int buf0[SIZEOF_LONG / SIZEOF_INT32 * 4], *buf = buf0;
79
80 seed = rb_to_int(vseed);
81 switch (TYPE(seed)) {
82 case T_FIXNUM:
83 len = 1;
84 buf[0] = (unsigned int)(FIX2ULONG(seed) & 0xffffffff);
85 #if SIZEOF_LONG > SIZEOF_INT32
86 if ((buf[1] = (unsigned int)(FIX2ULONG(seed) >> 32)) != 0) ++len;
87 #endif
88 break;
89 case T_BIGNUM:
90 blen = RBIGNUM_LEN(seed);
91 if (blen == 0) {
92 len = 1;
93 }
94 else {
95 if (blen > MT_MAX_STATE * SIZEOF_INT32 / SIZEOF_BDIGITS)
96 blen = (len = MT_MAX_STATE) * SIZEOF_INT32 / SIZEOF_BDIGITS;
97 len = roomof((int)blen * SIZEOF_BDIGITS, SIZEOF_INT32);
98 }
99 /* allocate ints for init_by_array */
100 if (len > numberof(buf0)) buf = ALLOC_N(unsigned int, len);
101 memset(buf, 0, len * sizeof(*buf));
102 len = 0;
103 for (i = (int)(blen-1); 0 <= i; i--) {
104 j = i * SIZEOF_BDIGITS / SIZEOF_INT32;
105 #if SIZEOF_BDIGITS < SIZEOF_INT32
106 buf[j] <<= BITSPERDIG;
107 #endif
108 buf[j] |= RBIGNUM_DIGITS(seed)[i];
109 if (!len && buf[j]) len = j;
110 }
111 ++len;
112 break;
113 default:
114 rb_raise(rb_eTypeError, "failed to convert %s into Integer",
115 rb_obj_classname(vseed));
116 }
117 if (len <= 1) {
118 init_genrand(mt, buf[0]);
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
119 }
120 else {
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
121 if (buf[len-1] == 1) /* remove leading-zero-guard */
122 len--;
123 init_by_array(mt, buf, len);
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
124 }
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
125 return seed;
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
126 }
127
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
128 /*
129 * call-seq: Random.new([seed]) -> prng
130 *
131 * Creates new Mersenne Twister based pseudorandom number generator with
132 * seed. When the argument seed is omitted, the generator is initialized
133 * with Random.seed.
134 *
135 * The argument seed is used to ensure repeatable sequences of random numbers
136 * between different runs of the program.
137 *
138 * prng = Random.new(1234)
139 * [ prng.rand, prng.rand ] #=> [0.191519450378892, 0.622108771039832]
140 * [ prng.integer(10), prng.integer(1000) ] #=> [4, 664]
141 * prng = Random.new(1234)
142 * [ prng.rand, prng.rand ] #=> [0.191519450378892, 0.622108771039832]
143 */
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
144 static VALUE
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
145 random_init(VALUE obj, SEL sel, int argc, VALUE *argv)
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
146 {
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
147 VALUE vseed;
148 rb_random_t *rnd = get_rnd(obj);
8f9d863c » Laurent Sansonetti
2009-10-16 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
149
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
150 if (argc == 0) {
151 vseed = random_seed(0, 0);
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
152 }
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
153 else {
154 rb_scan_args(argc, argv, "01", &vseed);
155 }
156 GC_WB(&rnd->seed, rand_init(&rnd->mt, vseed));
157 return obj;
158 }
159
160 #define DEFAULT_SEED_CNT 4
161 #define DEFAULT_SEED_LEN (DEFAULT_SEED_CNT * sizeof(int))
162
163 static void
164 fill_random_seed(unsigned int seed[DEFAULT_SEED_CNT])
165 {
166 static int n = 0;
167 struct timeval tv;
168 int fd;
169 struct stat statbuf;
170
171 memset(seed, 0, DEFAULT_SEED_LEN);
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
172
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
173 if ((fd = open("/dev/urandom", O_RDONLY
174 #ifdef O_NONBLOCK
175 |O_NONBLOCK
176 #endif
177 #ifdef O_NOCTTY
178 |O_NOCTTY
179 #endif
180 #ifdef O_NOFOLLOW
181 |O_NOFOLLOW
182 #endif
183 )) >= 0) {
184 if (fstat(fd, &statbuf) == 0 && S_ISCHR(statbuf.st_mode)) {
185 (void)read(fd, seed, DEFAULT_SEED_LEN);
186 }
187 close(fd);
8f9d863c » Laurent Sansonetti
2009-10-16 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
188 }
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
189
190 gettimeofday(&tv, 0);
191 seed[0] ^= tv.tv_usec;
192 seed[1] ^= (unsigned int)tv.tv_sec;
193 #if SIZEOF_TIME_T > SIZEOF_INT
194 seed[0] ^= (unsigned int)((time_t)tv.tv_sec >> SIZEOF_INT * CHAR_BIT);
195 #endif
196 seed[2] ^= getpid() ^ (n++ << 16);
197 seed[3] ^= (unsigned int)(VALUE)&seed;
198 #if SIZEOF_VOIDP > SIZEOF_INT
199 seed[2] ^= (unsigned int)((VALUE)&seed >> SIZEOF_INT * CHAR_BIT);
200 #endif
8f9d863c » Laurent Sansonetti
2009-10-16 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
201 }
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
202
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
203 static VALUE
204 make_seed_value(const void *ptr)
205 {
206 BDIGIT *digits;
207 NEWOBJ(big, struct RBignum);
208 OBJSETUP(big, rb_cBignum, T_BIGNUM);
209
210 RBIGNUM_SET_SIGN(big, 1);
211 rb_big_resize((VALUE)big, DEFAULT_SEED_LEN / SIZEOF_BDIGITS + 1);
212 digits = RBIGNUM_DIGITS(big);
213
214 MEMCPY(digits, ptr, char, DEFAULT_SEED_LEN);
215
216 /* set leading-zero-guard if need. */
217 digits[RBIGNUM_LEN(big)-1] = digits[RBIGNUM_LEN(big)-2] <= 1 ? 1 : 0;
218
219 return rb_big_norm((VALUE)big);
220 }
221
222 /*
223 * call-seq: Random.seed -> integer
224 *
225 * Returns arbitrary value for seed.
226 */
227 static VALUE
228 random_seed(VALUE rcv, SEL sel)
8f9d863c » Laurent Sansonetti
2009-10-16 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
229 {
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
230 unsigned int buf[DEFAULT_SEED_CNT];
231 fill_random_seed(buf);
232 return make_seed_value(buf);
233 }
8f9d863c » Laurent Sansonetti
2009-10-16 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
234
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
235 /*
236 * call-seq: prng.seed -> integer
237 *
238 * Returns the seed of the generator.
239 */
240 static VALUE
241 random_get_seed(VALUE obj, SEL sel)
242 {
243 return get_rnd(obj)->seed;
244 }
245
246 /* :nodoc: */
247 static VALUE
248 random_copy(VALUE obj, SEL sel, VALUE orig)
249 {
250 rb_random_t *rnd1 = get_rnd(obj);
251 rb_random_t *rnd2 = get_rnd(orig);
252 struct MT *mt = &rnd1->mt;
253
254 *rnd1 = *rnd2;
255 GC_WB(&rnd1->seed, rnd2->seed);
256 mt->next = mt->state + numberof(mt->state) - mt->left + 1;
257 return obj;
258 }
259
260 static VALUE
261 mt_state(const struct MT *mt)
262 {
263 const int n = numberof(mt->state);
264 VALUE bigo = rb_big_new(n, 1);
265 BDIGIT *d = RBIGNUM_DIGITS(bigo);
266 for (int i = 0; i < n; i++) {
267 unsigned int x = mt->state[i];
268 *d++ = (BDIGIT)x;
8f9d863c » Laurent Sansonetti
2009-10-16 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
269 }
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
270 return rb_big_norm(bigo);
8f9d863c » Laurent Sansonetti
2009-10-16 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
271 }
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
272
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
273 /* :nodoc: */
274 static VALUE
275 random_state(VALUE obj, SEL sel)
8f9d863c » Laurent Sansonetti
2009-10-16 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
276 {
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
277 rb_random_t *rnd = get_rnd(obj);
278 return mt_state(&rnd->mt);
279 }
280
281 /* :nodoc: */
282 static VALUE
283 random_s_state(VALUE klass, SEL sel)
284 {
285 return mt_state(&default_rnd()->mt);
286 }
287
288 /* :nodoc: */
289 static VALUE
290 random_left(VALUE obj, SEL sel)
291 {
292 rb_random_t *rnd = get_rnd(obj);
293 return INT2FIX(rnd->mt.left);
294 }
295
296 /* :nodoc: */
297 static VALUE
298 random_s_left(VALUE klass, SEL sel)
299 {
300 return INT2FIX(default_rnd()->mt.left);
301 }
302
303 /* :nodoc: */
304 static VALUE
305 random_dump(VALUE obj, SEL sel)
306 {
307 rb_random_t *rnd = get_rnd(obj);
308 VALUE dump = rb_ary_new2(3);
309
310 rb_ary_push(dump, mt_state(&rnd->mt));
311 rb_ary_push(dump, INT2FIX(rnd->mt.left));
312 rb_ary_push(dump, rnd->seed);
313
314 return dump;
315 }
316
317 /* :nodoc: */
318 static VALUE
319 random_load(VALUE obj, SEL sel, VALUE dump)
320 {
321 rb_random_t *rnd = get_rnd(obj);
322 struct MT *mt = &rnd->mt;
323 VALUE state, left = INT2FIX(1), seed = INT2FIX(0);
324 unsigned long x;
325
326 Check_Type(dump, T_ARRAY);
327 switch (RARRAY_LEN(dump)) {
328 case 3:
329 seed = RARRAY_AT(dump, 2);
330 case 2:
331 left = RARRAY_AT(dump, 1);
332 case 1:
333 state = RARRAY_AT(dump, 0);
334 break;
335 default:
336 rb_raise(rb_eArgError, "wrong dump data");
337 }
338 memset(mt->state, 0, sizeof(mt->state));
339 #if 0
340 if (FIXNUM_P(state)) {
341 x = FIX2ULONG(state);
342 mt->state[0] = (unsigned int)x;
343 #if SIZEOF_LONG / SIZEOF_INT >= 2
344 mt->state[1] = (unsigned int)(x >> BITSPERDIG);
345 #endif
346 #if SIZEOF_LONG / SIZEOF_INT >= 3
347 mt->state[2] = (unsigned int)(x >> 2 * BITSPERDIG);
348 #endif
349 #if SIZEOF_LONG / SIZEOF_INT >= 4
350 mt->state[3] = (unsigned int)(x >> 3 * BITSPERDIG);
351 #endif
352 }
353 else {
354 BDIGIT *d;
355 long len;
356 Check_Type(state, T_BIGNUM);
357 len = RBIGNUM_LEN(state);
358 if (len > roomof(sizeof(mt->state), SIZEOF_BDIGITS)) {
359 len = roomof(sizeof(mt->state), SIZEOF_BDIGITS);
360 }
361 #if SIZEOF_BDIGITS < SIZEOF_INT
362 else if (len % DIGSPERINT) {
363 d = RBIGNUM_DIGITS(state) + len;
364 # if DIGSPERINT == 2
365 --len;
366 x = *--d;
367 # else
368 x = 0;
369 do {
370 x = (x << BITSPERDIG) | *--d;
371 } while (--len % DIGSPERINT);
372 # endif
373 mt->state[len / DIGSPERINT] = (unsigned int)x;
374 }
375 #endif
376 if (len > 0) {
377 d = BDIGITS(state) + len;
378 do {
379 --len;
380 x = *--d;
381 # if DIGSPERINT == 2
382 --len;
383 x = (x << BITSPERDIG) | *--d;
384 # elif SIZEOF_BDIGITS < SIZEOF_INT
385 do {
386 x = (x << BITSPERDIG) | *--d;
387 } while (--len % DIGSPERINT);
388 # endif
389 mt->state[len / DIGSPERINT] = (unsigned int)x;
390 } while (len > 0);
391 }
392 }
393 #endif
394 x = NUM2ULONG(left);
395 if (x > numberof(mt->state)) {
396 rb_raise(rb_eArgError, "wrong value");
397 }
398 mt->left = (unsigned int)x;
399 mt->next = mt->state + numberof(mt->state) - x + 1;
400 GC_WB(&rnd->seed, rb_to_int(seed));
401
402 return obj;
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
403 }
404
405 /*
406 * call-seq:
407 * srand(number=0) => old_seed
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
408 *
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
409 * Seeds the pseudorandom number generator to the value of
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
410 * <i>number</i>. If <i>number</i> is omitted
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
411 * or zero, seeds the generator using a combination of the time, the
412 * process id, and a sequence number. (This is also the behavior if
413 * <code>Kernel::rand</code> is called without previously calling
414 * <code>srand</code>, but without the sequence.) By setting the seed
415 * to a known value, scripts can be made deterministic during testing.
416 * The previous seed value is returned. Also see <code>Kernel::rand</code>.
417 */
418
419 static VALUE
349dd2b1 » Laurent Sansonetti
2009-05-29 ported the random.c apis to the new runtime
420 rb_f_srand(VALUE obj, SEL sel, int argc, VALUE *argv)
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
421 {
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
422 VALUE seed, old;
423 rb_random_t *r = default_rnd();
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
424
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
425 rb_secure(4);
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
426 if (argc == 0) {
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
427 seed = random_seed(0, 0);
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
428 }
429 else {
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
430 rb_scan_args(argc, argv, "01", &seed);
431 }
432 old = r->seed;
433 GC_WB(&r->seed, rand_init(&r->mt, seed));
434
435 return old;
436 }
437
438 static unsigned long
439 make_mask(unsigned long x)
440 {
441 x = x | x >> 1;
442 x = x | x >> 2;
443 x = x | x >> 4;
444 x = x | x >> 8;
445 x = x | x >> 16;
446 #if 4 < SIZEOF_LONG
447 x = x | x >> 32;
448 #endif
449 return x;
450 }
451
452 static unsigned long
453 limited_rand(struct MT *mt, unsigned long limit)
454 {
455 if (limit == 0) {
456 return 0;
457 }
458 unsigned long val, mask = make_mask(limit);
459 retry:
460 val = 0;
461 for (int i = SIZEOF_LONG / SIZEOF_INT32 - 1; 0 <= i; i--) {
462 if ((mask >> (i * 32)) & 0xffffffff) {
463 val |= (unsigned long)genrand_int32(mt) << (i * 32);
464 val &= mask;
465 if (limit < val) {
466 goto retry;
8f9d863c » Laurent Sansonetti
2009-10-16 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
467 }
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
468 }
469 }
470 return val;
471 }
472
473 static VALUE
474 limited_big_rand(struct MT *mt, struct RBignum *limit)
475 {
9bb27513 » Patrick Thomson
2010-03-19 Fix random generation of bignums on 64-bit 10.6+ machines.
476 #if SIZEOF_BDIGITS < 8
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
477 const long len = (RBIGNUM_LEN(limit) * SIZEOF_BDIGITS + 3) / 4;
9bb27513 » Patrick Thomson
2010-03-19 Fix random generation of bignums on 64-bit 10.6+ machines.
478 #else
479 const long len = (RBIGNUM_LEN(limit) * SIZEOF_BDIGITS + 3) / 8;
480 #endif
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
481 struct RBignum *val = (struct RBignum *)rb_big_clone((VALUE)limit);
482 RBIGNUM_SET_SIGN(val, 1);
483 #if SIZEOF_BDIGITS == 2
484 # define BIG_GET32(big,i) \
485 (RBIGNUM_DIGITS(big)[(i)*2] | \
486 ((i)*2+1 < RBIGNUM_LEN(big) ? \
487 (RBIGNUM_DIGITS(big)[(i)*2+1] << 16) : \
488 0))
489 # define BIG_SET32(big,i,d) \
490 ((RBIGNUM_DIGITS(big)[(i)*2] = (d) & 0xffff), \
491 ((i)*2+1 < RBIGNUM_LEN(big) ? \
492 (RBIGNUM_DIGITS(big)[(i)*2+1] = (d) >> 16) : \
493 0))
494 #else
495 /* SIZEOF_BDIGITS == 4 */
496 # define BIG_GET32(big,i) (RBIGNUM_DIGITS(big)[i])
497 # define BIG_SET32(big,i,d) (RBIGNUM_DIGITS(big)[i] = (d))
498 #endif
499 unsigned long mask;
500 int boundary;
501 retry:
502 mask = 0;
503 boundary = 1;
504 for (long i = len - 1; 0 <= i; i--) {
505 const unsigned long lim = BIG_GET32(limit, i);
506 unsigned long rnd;
507 mask = mask != 0 ? 0xffffffff : make_mask(lim);
508 if (mask != 0) {
509 rnd = genrand_int32(mt) & mask;
510 if (boundary) {
511 if (lim < rnd) {
512 goto retry;
513 }
514 if (rnd < lim) {
515 boundary = 0;
516 }
517 }
518 }
519 else {
520 rnd = 0;
521 }
522 BIG_SET32(val, i, (BDIGIT)rnd);
523 }
524 return rb_big_norm((VALUE)val);
525 }
526
527 unsigned long
528 rb_rand_internal(unsigned long i)
529 {
530 struct MT *mt = &default_rnd()->mt;
531 if (!genrand_initialized(mt)) {
532 rand_init(mt, random_seed(0, 0));
533 }
534 return limited_rand(mt, i);
535 }
536
537 unsigned int
538 rb_random_int32(VALUE obj)
539 {
540 rb_random_t *rnd = get_rnd(obj);
541 return genrand_int32(&rnd->mt);
542 }
543
544 double
545 rb_random_real(VALUE obj)
546 {
547 rb_random_t *rnd = get_rnd(obj);
548 return genrand_real(&rnd->mt);
549 }
550
551 /*
552 * call-seq: prng.bytes(size) -> prng
553 *
554 * Returns a random binary string. The argument size specified the length of
555 * the result string.
556 */
557 static VALUE
558 random_bytes(VALUE obj, SEL sel, VALUE len)
559 {
560 long n = NUM2LONG(rb_to_int(len));
561 if (n <= 0) {
562 return rb_str_new2("");
563 }
564 rb_random_t *rnd = get_rnd(obj);
565 UInt8 *ptr = (UInt8 *)malloc(n);
566 unsigned int r = genrand_int32(&rnd->mt);
567 for (long i = 0; i < n; i++) {
568 ptr[i] = (char)r;
569 r >>= CHAR_BIT;
570 }
adfb9727 » Laurent Sansonetti
2010-03-09 expose the bstr APIs
571 VALUE bytes = rb_bstr_new_with_data(ptr, n);
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
572 free(ptr);
573 return bytes;
574 }
575
576 static VALUE
577 range_values(VALUE vmax, VALUE *begp, int *exclp)
578 {
579 VALUE end;
580 if (!rb_range_values(vmax, begp, &end, exclp)) {
581 return Qfalse;
582 }
583 if (!rb_vm_respond_to(end, selMINUS, false)) {
584 return Qfalse;
585 }
70ea0b5a » Laurent Sansonetti
2010-06-01 per-vm method cache + misc fixes/improvements
586 VALUE r = rb_vm_call(end, selMINUS, 1, begp);
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
587 if (NIL_P(r)) {
588 return Qfalse;
589 }
590 return r;
591 }
592
593 static VALUE
594 rand_int(struct MT *mt, VALUE vmax, int restrictive)
595 {
596 long max;
597 unsigned long r;
598
599 if (FIXNUM_P(vmax)) {
600 max = FIX2LONG(vmax);
601 if (!max) return Qnil;
602 if (max < 0) {
603 if (restrictive) return Qnil;
604 max = -max;
605 }
606 r = limited_rand(mt, (unsigned long)max - 1);
607 return ULONG2NUM(r);
608 }
609 else {
610 VALUE ret;
611 if (rb_bigzero_p(vmax)) return Qnil;
612 if (!RBIGNUM_SIGN(vmax)) {
613 if (restrictive) return Qnil;
614 vmax = rb_big_clone(vmax);
615 RBIGNUM_SET_SIGN(vmax, 1);
616 }
617 vmax = rb_big_minus(vmax, INT2FIX(1));
618 if (FIXNUM_P(vmax)) {
619 max = FIX2LONG(vmax);
620 if (max == -1) return Qnil;
621 r = limited_rand(mt, max);
622 return LONG2NUM(r);
623 }
624 ret = limited_big_rand(mt, RBIGNUM(vmax));
625 return ret;
626 }
627 }
628
629 static inline double
630 float_value(VALUE v)
631 {
632 double x = RFLOAT_VALUE(v);
633 if (isinf(x) || isnan(x)) {
634 VALUE error = INT2FIX(EDOM);
635 rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError));
636 }
637 return x;
638 }
639
640 /*
641 * call-seq:
642 * prng.rand -> float
643 * prng.rand(limit) -> number
644 *
645 * When the argument is an +Integer+ or a +Bignum+, it returns a
646 * random integer greater than or equal to zero and less than the
647 * argument. Unlike Random.rand, when the argument is a negative
648 * integer or zero, it raises an ArgumentError.
649 *
650 * When the argument is a +Float+, it returns a random floating point
651 * number between 0.0 and _max_, including 0.0 and excluding _max_.
652 *
653 * When the argument _limit_ is a +Range+, it returns a random
654 * number where range.member?(number) == true.
655 * prng.rand(5..9) # => one of [5, 6, 7, 8, 9]
656 * prng.rand(5...9) # => one of [5, 6, 7, 8]
657 * prng.rand(5.0..9.0) # => between 5.0 and 9.0, including 9.0
658 * prng.rand(5.0...9.0) # => between 5.0 and 9.0, excluding 9.0
659 *
660 * +begin+/+end+ of the range have to have subtract and add methods.
661 *
662 * Otherwise, it raises an ArgumentError.
663 */
664 static VALUE
665 random_rand(VALUE obj, SEL sel, int argc, VALUE *argv)
666 {
667 rb_random_t *rnd = get_rnd(obj);
668 VALUE beg = Qundef, v;
669 int excl = 0;
670
671 if (argc == 0) {
672 zero_arg:
673 return rb_float_new(genrand_real(&rnd->mt));
674 }
675 else if (argc != 1) {
676 rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..1)", argc);
677 }
678 VALUE vmax = argv[0];
679 if (NIL_P(vmax)) {
680 goto zero_arg;
681 }
682 else if (TYPE(vmax) != T_FLOAT
683 && (v = rb_check_to_integer(vmax, "to_int"), !NIL_P(v))) {
684 v = rand_int(&rnd->mt, vmax = v, 1);
685 }
686 else if (v = rb_check_to_float(vmax), !NIL_P(v)) {
687 const double max = float_value(v);
688 if (max > 0.0) {
689 v = rb_float_new(max * genrand_real(&rnd->mt));
690 }
691 else {
692 v = Qnil;
693 }
694 }
695 else if ((v = range_values(vmax, &beg, &excl)) != Qfalse) {
696 vmax = v;
697 if (TYPE(vmax) != T_FLOAT
698 && (v = rb_check_to_integer(vmax, "to_int"), !NIL_P(v))) {
699 long max;
700 vmax = v;
701 v = Qnil;
702 if (FIXNUM_P(vmax)) {
703 fixnum:
704 if ((max = FIX2LONG(vmax) - excl) >= 0) {
705 unsigned long r = limited_rand(&rnd->mt, (unsigned long)max);
706 v = ULONG2NUM(r);
707 }
708 }
709 else if (BUILTIN_TYPE(vmax) == T_BIGNUM && RBIGNUM_SIGN(vmax)
710 && !rb_bigzero_p(vmax)) {
711 vmax = excl ? rb_big_minus(vmax, INT2FIX(1)) : rb_big_norm(vmax);
712 if (FIXNUM_P(vmax)) {
713 excl = 0;
714 goto fixnum;
715 }
716 v = limited_big_rand(&rnd->mt, RBIGNUM(vmax));
8f9d863c » Laurent Sansonetti
2009-10-16 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
717 }
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
718 }
719 else if (v = rb_check_to_float(vmax), !NIL_P(v)) {
720 double max = float_value(v), r;
721 v = Qnil;
722 if (max > 0.0) {
723 if (excl) {
724 r = genrand_real(&rnd->mt);
725 }
726 else {
727 r = genrand_real2(&rnd->mt);
728 }
729 v = rb_float_new(r * max);
730 }
731 else if (max == 0.0 && !excl) {
732 v = rb_float_new(0.0);
8f9d863c » Laurent Sansonetti
2009-10-16 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
733 }
734 }
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
735 }
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
736 else {
737 v = Qnil;
5950c895 » Laurent Sansonetti
2010-05-03 fix clang build (patch by Jordan Hubbard)
738 (void)NUM2LONG(vmax);
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
739 }
740 if (NIL_P(v)) {
741 VALUE mesg = rb_str_new2("invalid argument - ");
742 rb_str_append(mesg, rb_obj_as_string(argv[0]));
743 rb_exc_raise(rb_exc_new3(rb_eArgError, mesg));
744 }
745 if (beg == Qundef) {
746 return v;
747 }
748 if (FIXNUM_P(beg) && FIXNUM_P(v)) {
749 long x = FIX2LONG(beg) + FIX2LONG(v);
750 return LONG2NUM(x);
751 }
752 switch (TYPE(v)) {
753 case T_BIGNUM:
754 return rb_big_plus(v, beg);
755 case T_FLOAT:
756 {
757 double d = RFLOAT_VALUE(v) + RFLOAT_VALUE(rb_check_to_float(beg));
758 return DOUBLE2NUM(d);
759 }
760 default:
70ea0b5a » Laurent Sansonetti
2010-06-01 per-vm method cache + misc fixes/improvements
761 return rb_vm_call(v, selPLUS, 1, &beg);
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
762 }
763 }
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
764
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
765 /*
766 * call-seq:
767 * prng1 == prng2 -> true or false
768 *
769 * Returns true if the generators' states equal.
770 */
771 static VALUE
772 random_equal(VALUE self, SEL sel, VALUE other)
773 {
774 if (rb_obj_class(self) != rb_obj_class(other)) {
775 return Qfalse;
776 }
777 rb_random_t *r1 = get_rnd(self);
778 rb_random_t *r2 = get_rnd(other);
779 if (rb_equal(r1->seed, r2->seed) != Qtrue) {
780 return Qfalse;
781 }
782 if (memcmp(r1->mt.state, r2->mt.state, sizeof(r1->mt.state))) {
783 return Qfalse;
784 }
785 if ((r1->mt.next - r1->mt.state) != (r2->mt.next - r2->mt.state)) {
786 return Qfalse;
787 }
788 if (r1->mt.left != r2->mt.left) {
789 return Qfalse;
790 }
791 return Qtrue;
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
792 }
793
794 /*
795 * call-seq:
796 * rand(max=0) => number
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
797 *
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
798 * Converts <i>max</i> to an integer using max1 =
799 * max<code>.to_i.abs</code>. If the result is zero, returns a
800 * pseudorandom floating point number greater than or equal to 0.0 and
801 * less than 1.0. Otherwise, returns a pseudorandom integer greater
802 * than or equal to zero and less than max1. <code>Kernel::srand</code>
803 * may be used to ensure repeatable sequences of random numbers between
804 * different runs of the program. Ruby currently uses a modified
805 * Mersenne Twister with a period of 2**19937-1.
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
806 *
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
807 * srand 1234 #=> 0
808 * [ rand, rand ] #=> [0.191519450163469, 0.49766366626136]
809 * [ rand(10), rand(1000) ] #=> [6, 817]
810 * srand 1234 #=> 1234
811 * [ rand, rand ] #=> [0.191519450163469, 0.49766366626136]
812 */
813
814 static VALUE
349dd2b1 » Laurent Sansonetti
2009-05-29 ported the random.c apis to the new runtime
815 rb_f_rand(VALUE obj, SEL sel, int argc, VALUE *argv)
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
816 {
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
817 struct MT *mt = &default_rnd()->mt;
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
818
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
819 if (!genrand_initialized(mt)) {
820 rand_init(mt, random_seed(0, 0));
821 }
822 if (argc == 0) {
823 goto zero_arg;
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
824 }
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
825 VALUE vmax;
826 rb_scan_args(argc, argv, "01", &vmax);
827 if (NIL_P(vmax)) {
828 goto zero_arg;
829 }
830 vmax = rb_to_int(vmax);
831 VALUE r;
832 if (vmax == INT2FIX(0) || NIL_P(r = rand_int(mt, vmax, 0))) {
833 zero_arg:
834 return DBL2NUM(genrand_real(mt));
835 }
836 return r;
837 }
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
838
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
839 static void
840 Init_RandomSeed(void)
841 {
842 VALUE random = random_alloc(0, 0);
843 unsigned int initial[DEFAULT_SEED_CNT];
844 GC_WB(&get_rnd(random)->seed, make_seed_value(initial));
845 rb_vm_set_default_random(random);
846 }
847
848 void
849 rb_reset_random_seed(void)
850 {
851 rb_random_t *r = default_rnd();
852 uninit_genrand(&r->mt);
853 r->seed = INT2FIX(0);
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
854 }
855
856 void
857 Init_Random(void)
858 {
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
859 Init_RandomSeed();
cbe906ec » Laurent Sansonetti
2009-08-26 introduce rb_objc_define_module_function() which mimics the ruby spec
860 rb_objc_define_module_function(rb_mKernel, "srand", rb_f_srand, -1);
861 rb_objc_define_module_function(rb_mKernel, "rand", rb_f_rand, -1);
65814005 » Laurent Sansonetti
2010-02-13 integrate Mersenne Twister based random number generator from 1.9 ups…
862
863 rb_cRandom = rb_define_class("Random", rb_cObject);
864 rb_objc_define_method(*(VALUE *)rb_cRandom, "alloc", random_alloc, 0);
865 rb_objc_define_method(rb_cRandom, "initialize", random_init, -1);
866 rb_objc_define_method(rb_cRandom, "rand", random_rand, -1);
867 rb_objc_define_method(rb_cRandom, "bytes", random_bytes, 1);
868 rb_objc_define_method(rb_cRandom, "seed", random_get_seed, 0);
869 rb_objc_define_method(rb_cRandom, "initialize_copy", random_copy, 1);
870 rb_objc_define_method(rb_cRandom, "marshal_dump", random_dump, 0);
871 rb_objc_define_method(rb_cRandom, "marshal_load", random_load, 1);
872 rb_objc_define_private_method(rb_cRandom, "state", random_state, 0);
873 rb_objc_define_private_method(rb_cRandom, "left", random_left, 0);
874 rb_objc_define_method(rb_cRandom, "==", random_equal, 1);
875
876 rb_objc_define_method(*(VALUE *)rb_cRandom, "srand", rb_f_srand, -1);
877 rb_objc_define_method(*(VALUE *)rb_cRandom, "rand", rb_f_rand, -1);
878 rb_objc_define_method(*(VALUE *)rb_cRandom, "new_seed", random_seed, 0);
879 rb_objc_define_private_method(*(VALUE *)rb_cRandom, "state", random_s_state, 0);
880 rb_objc_define_private_method(*(VALUE *)rb_cRandom, "left", random_s_left, 0);
9c1d2307 » Laurent Sansonetti
2009-03-11 committing experimental branch content
881 }
Something went wrong with that request. Please try again.