Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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