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 @ferrous26 Change ownership to The MacRuby Team and update copyrights
ferrous26 authored
1 /*
6581400 integrate Mersenne Twister based random number generator from 1.9 ups…
Laurent Sansonetti authored
2 * Random Numbers.
3 *
4 * This file is covered by the Ruby license. See COPYING for more details.
7d7d3e8 @ferrous26 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 ups…
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 ups…
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 ups…
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 ups…
Laurent Sansonetti authored
25 #include "mt.c"
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
26
6581400 integrate Mersenne Twister based random number generator from 1.9 ups…
Laurent Sansonetti authored
27 VALUE rb_cRandom;
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
28
6581400 integrate Mersenne Twister based random number generator from 1.9 ups…
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 ups…
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 ups…
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 ups…
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 ups…
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 ups…
Laurent Sansonetti authored
73 static VALUE
74 rand_init(struct MT *mt, VALUE vseed)
75 {
76 VALUE seed;
77 long blen = 0;
18e269a @Watson1978 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 ups…
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 @Watson1978 ignore higher bits if all they are same as the lower sign bit
Watson1978 authored
86 fixnum_seed = FIX2LONG(seed);
80d1bc1 @Watson1978 use the absolute value of seed to make srand(-2**40) portable with 32…
Watson1978 authored
87 if (fixnum_seed < 0)
88 fixnum_seed = -fixnum_seed;
18e269a @Watson1978 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 ups…
Laurent Sansonetti authored
90 #if SIZEOF_LONG > SIZEOF_INT32
18e269a @Watson1978 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 ups…
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 ups…
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 ups…
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 ups…
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 ups…
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 ups…
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), fast…
Laurent Sansonetti authored
156
6581400 integrate Mersenne Twister based random number generator from 1.9 ups…
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 ups…
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 ups…
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), fast…
Laurent Sansonetti authored
195 }
6581400 integrate Mersenne Twister based random number generator from 1.9 ups…
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), fast…
Laurent Sansonetti authored
208 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
209
6581400 integrate Mersenne Twister based random number generator from 1.9 ups…
Laurent Sansonetti authored
210 static VALUE
211 make_seed_value(const void *ptr)
212 {
1351eac @Watson1978 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 ups…
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 @Watson1978 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 ups…
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 @Watson1978 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 ups…
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), fast…
Laurent Sansonetti authored
243 {
6581400 integrate Mersenne Twister based random number generator from 1.9 ups…
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), fast…
Laurent Sansonetti authored
248
6581400 integrate Mersenne Twister based random number generator from 1.9 ups…
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), fast…
Laurent Sansonetti authored
283 }
6581400 integrate Mersenne Twister based random number generator from 1.9 ups…
Laurent Sansonetti authored
284 return rb_big_norm(bigo);
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
285 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
286
6581400 integrate Mersenne Twister based random number generator from 1.9 ups…
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), fast…
Laurent Sansonetti authored
290 {
6581400 integrate Mersenne Twister based random number generator from 1.9 ups…
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 ups…
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 ups…
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 ups…
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 ups…
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 ups…
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 ups…
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), fast…
Laurent Sansonetti authored
481 }
6581400 integrate Mersenne Twister based random number generator from 1.9 ups…
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 ups…
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 ups…
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 @Watson1978 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 ups…
Laurent Sansonetti authored
576 if (n <= 0) {
abd5be1 @Watson1978 Random#bytes should return a longer string
Watson1978 authored
577 return bytes;
6581400 integrate Mersenne Twister based random number generator from 1.9 ups…
Laurent Sansonetti authored
578 }
abd5be1 @Watson1978 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 ups…
Laurent Sansonetti authored
580 rb_random_t *rnd = get_rnd(obj);
abd5be1 @Watson1978 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 ups…
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 ups…
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 @Watson1978 raise ArgumentError on nil
Watson1978 authored
705 v = Qnil;
6581400 integrate Mersenne Twister based random number generator from 1.9 ups…
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), fast…
Laurent Sansonetti authored
742 }
6581400 integrate Mersenne Twister based random number generator from 1.9 ups…
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), fast…
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 ups…
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 ups…
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 ups…
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 ups…
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 ups…
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 ups…
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 ups…
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 ups…
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 ups…
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 @Watson1978 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 ups…
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 @lrz 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 ups…
Laurent Sansonetti authored
872 GC_WB(&get_rnd(random)->seed, make_seed_value(initial));
873 rb_vm_set_default_random(random);
73bdff6 @Watson1978 add rb_hash_{start, uint32, uint, end}
Watson1978 authored
874
3fb95bd @Watson1978 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 @Watson1978 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 ups…
Laurent Sansonetti authored
893 }
894
73bdff6 @Watson1978 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 ups…
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 ups…
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 ups…
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.