Skip to content
This repository
Browse code

integrate Mersenne Twister based random number generator from 1.9 ups…

…tream

git-svn-id: http://svn.macosforge.org/repository/ruby/MacRuby/trunk@3519 23306eb0-4c56-4727-a40e-e92c0eb68959
  • Loading branch information...
commit 65814005b81a13732bceab91ec2e971c9398a3f4 1 parent a6878c4
Laurent Sansonetti authored
12 bignum.c
@@ -53,6 +53,12 @@ bigzero_p(VALUE x)
53 53 }
54 54
55 55 int
  56 +rb_bigzero_p(VALUE x)
  57 +{
  58 + return BIGZEROP(x);
  59 +}
  60 +
  61 +int
56 62 rb_cmpint(VALUE val, VALUE a, VALUE b)
57 63 {
58 64 if (NIL_P(val)) {
@@ -696,6 +702,12 @@ rb_bignum_new_retained(const char *str)
696 702 return v;
697 703 }
698 704
  705 +VALUE
  706 +rb_big_new(long len, int sign)
  707 +{
  708 + return bignew(len, sign != 0);
  709 +}
  710 +
699 711 const char ruby_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz";
700 712
701 713 static VALUE bigsqr(VALUE x);
6 include/ruby/intern.h
@@ -95,6 +95,8 @@ VALUE rb_cstr2inum(const char*, int);
95 95 VALUE rb_str2inum(VALUE, int);
96 96 VALUE rb_big2str(VALUE, int);
97 97 VALUE rb_big2str0(VALUE, int, int);
  98 +VALUE rb_big_new(long len, int sign);
  99 +int rb_bigzero_p(VALUE x);
98 100 SIGNED_VALUE rb_big2long(VALUE);
99 101 #define rb_big2int(x) rb_big2long(x)
100 102 VALUE rb_big2ulong(VALUE);
@@ -453,6 +455,7 @@ VALUE rb_String(VALUE);
453 455 VALUE rb_Array(VALUE);
454 456 double rb_cstr_to_dbl(const char*, int);
455 457 double rb_str_to_dbl(VALUE, int);
  458 +VALUE rb_check_to_float(VALUE val);
456 459 /* parse.y */
457 460 RUBY_EXTERN int ruby_sourceline;
458 461 RUBY_EXTERN char *ruby_sourcefile;
@@ -497,8 +500,9 @@ VALUE rb_detach_process(rb_pid_t pid);
497 500 void rb_range_extract(VALUE range, VALUE *begp, VALUE *endp, bool *exclude);
498 501 VALUE rb_range_new(VALUE, VALUE, int);
499 502 VALUE rb_range_beg_len(VALUE, long*, long*, long, int);
  503 +int rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp);
500 504 /* random.c */
501   -unsigned long rb_genrand_int32(void);
  505 +unsigned int rb_genrand_int32(void);
502 506 double rb_genrand_real(void);
503 507 /* re.c */
504 508 #define rb_memcmp memcmp
2  include/ruby/ruby.h
@@ -580,6 +580,7 @@ __rb_float_value(VALUE v)
580 580 }
581 581 #define RFLOAT_VALUE(v) (__rb_float_value((VALUE)v))
582 582 #define DOUBLE2NUM(dbl) rb_float_new(dbl)
  583 +#define DBL2NUM DOUBLE2NUM
583 584
584 585 #if WITH_OBJC
585 586 struct RFixnum {
@@ -1130,6 +1131,7 @@ RUBY_EXTERN VALUE rb_cUnboundMethod;
1130 1131 RUBY_EXTERN VALUE rb_cISeq;
1131 1132 RUBY_EXTERN VALUE rb_cVM;
1132 1133 RUBY_EXTERN VALUE rb_cEnv;
  1134 +RUBY_EXTERN VALUE rb_cRandom;
1133 1135
1134 1136 #if WITH_OBJC
1135 1137 RUBY_EXTERN VALUE rb_cCFString;
178 mt.c
... ... @@ -0,0 +1,178 @@
  1 +/*
  2 + * This is based on trimmed version of MT19937. To get the original version,
  3 + * contact <http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html>.
  4 + *
  5 + * The original copyright notice follows.
  6 + *
  7 + * A C-program for MT19937, with initialization improved 2002/2/10.
  8 + * Coded by Takuji Nishimura and Makoto Matsumoto.
  9 + * This is a faster version by taking Shawn Cokus's optimization,
  10 + * Matthe Bellew's simplification, Isaku Wada's real version.
  11 + *
  12 + * Before using, initialize the state by using init_genrand(mt, seed)
  13 + * or init_by_array(mt, init_key, key_length).
  14 + *
  15 + * Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura,
  16 + * All rights reserved.
  17 + *
  18 + * Redistribution and use in source and binary forms, with or without
  19 + * modification, are permitted provided that the following conditions
  20 + * are met:
  21 + *
  22 + * 1. Redistributions of source code must retain the above copyright
  23 + * notice, this list of conditions and the following disclaimer.
  24 + *
  25 + * 2. Redistributions in binary form must reproduce the above copyright
  26 + * notice, this list of conditions and the following disclaimer in the
  27 + * documentation and/or other materials provided with the distribution.
  28 + *
  29 + * 3. The names of its contributors may not be used to endorse or promote
  30 + * products derived from this software without specific prior written
  31 + * permission.
  32 + *
  33 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  34 + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  35 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  36 + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  37 + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  38 + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  39 + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  40 + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  41 + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  42 + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  43 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  44 + *
  45 + *
  46 + * Any feedback is very welcome.
  47 + * http://www.math.keio.ac.jp/matumoto/emt.html
  48 + * email: matumoto@math.keio.ac.jp
  49 + */
  50 +
  51 +#include <limits.h>
  52 +typedef int int_must_be_32bit_at_least[sizeof(int) * CHAR_BIT < 32 ? -1 : 1];
  53 +
  54 +/* Period parameters */
  55 +#define N 624
  56 +#define M 397
  57 +#define MATRIX_A 0x9908b0dfU /* constant vector a */
  58 +#define UMASK 0x80000000U /* most significant w-r bits */
  59 +#define LMASK 0x7fffffffU /* least significant r bits */
  60 +#define MIXBITS(u,v) ( ((u) & UMASK) | ((v) & LMASK) )
  61 +#define TWIST(u,v) ((MIXBITS(u,v) >> 1) ^ ((v)&1U ? MATRIX_A : 0U))
  62 +
  63 +enum {MT_MAX_STATE = N};
  64 +
  65 +struct MT {
  66 + /* assume int is enough to store 32bits */
  67 + unsigned int state[N]; /* the array for the state vector */
  68 + unsigned int *next;
  69 + int left;
  70 +};
  71 +
  72 +#define genrand_initialized(mt) ((mt)->next != 0)
  73 +#define uninit_genrand(mt) ((mt)->next = 0)
  74 +
  75 +/* initializes state[N] with a seed */
  76 +static void
  77 +init_genrand(struct MT *mt, unsigned int s)
  78 +{
  79 + int j;
  80 + mt->state[0] = s & 0xffffffffU;
  81 + for (j=1; j<N; j++) {
  82 + mt->state[j] = (1812433253U * (mt->state[j-1] ^ (mt->state[j-1] >> 30)) + j);
  83 + /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
  84 + /* In the previous versions, MSBs of the seed affect */
  85 + /* only MSBs of the array state[]. */
  86 + /* 2002/01/09 modified by Makoto Matsumoto */
  87 + mt->state[j] &= 0xffffffff; /* for >32 bit machines */
  88 + }
  89 + mt->left = 1;
  90 + mt->next = mt->state + N;
  91 +}
  92 +
  93 +/* initialize by an array with array-length */
  94 +/* init_key is the array for initializing keys */
  95 +/* key_length is its length */
  96 +/* slight change for C++, 2004/2/26 */
  97 +static void
  98 +init_by_array(struct MT *mt, unsigned int init_key[], int key_length)
  99 +{
  100 + int i, j, k;
  101 + init_genrand(mt, 19650218U);
  102 + i=1; j=0;
  103 + k = (N>key_length ? N : key_length);
  104 + for (; k; k--) {
  105 + mt->state[i] = (mt->state[i] ^ ((mt->state[i-1] ^ (mt->state[i-1] >> 30)) * 1664525U))
  106 + + init_key[j] + j; /* non linear */
  107 + mt->state[i] &= 0xffffffffU; /* for WORDSIZE > 32 machines */
  108 + i++; j++;
  109 + if (i>=N) { mt->state[0] = mt->state[N-1]; i=1; }
  110 + if (j>=key_length) j=0;
  111 + }
  112 + for (k=N-1; k; k--) {
  113 + mt->state[i] = (mt->state[i] ^ ((mt->state[i-1] ^ (mt->state[i-1] >> 30)) * 1566083941U))
  114 + - i; /* non linear */
  115 + mt->state[i] &= 0xffffffffU; /* for WORDSIZE > 32 machines */
  116 + i++;
  117 + if (i>=N) { mt->state[0] = mt->state[N-1]; i=1; }
  118 + }
  119 +
  120 + mt->state[0] = 0x80000000U; /* MSB is 1; assuring non-zero initial array */
  121 +}
  122 +
  123 +static void
  124 +next_state(struct MT *mt)
  125 +{
  126 + unsigned int *p = mt->state;
  127 + int j;
  128 +
  129 + /* if init_genrand() has not been called, */
  130 + /* a default initial seed is used */
  131 + if (!genrand_initialized(mt)) init_genrand(mt, 5489U);
  132 +
  133 + mt->left = N;
  134 + mt->next = mt->state;
  135 +
  136 + for (j=N-M+1; --j; p++)
  137 + *p = p[M] ^ TWIST(p[0], p[1]);
  138 +
  139 + for (j=M; --j; p++)
  140 + *p = p[M-N] ^ TWIST(p[0], p[1]);
  141 +
  142 + *p = p[M-N] ^ TWIST(p[0], mt->state[0]);
  143 +}
  144 +
  145 +/* generates a random number on [0,0xffffffff]-interval */
  146 +static unsigned int
  147 +genrand_int32(struct MT *mt)
  148 +{
  149 + unsigned int y;
  150 +
  151 + if (--mt->left <= 0) next_state(mt);
  152 + y = *mt->next++;
  153 +
  154 + /* Tempering */
  155 + y ^= (y >> 11);
  156 + y ^= (y << 7) & 0x9d2c5680;
  157 + y ^= (y << 15) & 0xefc60000;
  158 + y ^= (y >> 18);
  159 +
  160 + return y;
  161 +}
  162 +
  163 +/* generates a random number on [0,1) with 53-bit resolution*/
  164 +static double
  165 +genrand_real(struct MT *mt)
  166 +{
  167 + unsigned int a = genrand_int32(mt)>>5, b = genrand_int32(mt)>>6;
  168 + return(a*67108864.0+b)*(1.0/9007199254740992.0);
  169 +}
  170 +
  171 +/* generates a random number on [0,1] with 53-bit resolution*/
  172 +// TODO
  173 +#define genrand_real2 genrand_real
  174 +
  175 +/* These real versions are due to Isaku Wada, 2002/01/09 added */
  176 +
  177 +#undef N
  178 +#undef M
12 object.c
@@ -2778,6 +2778,18 @@ rb_f_float(VALUE obj, SEL sel, VALUE arg)
2778 2778 return rb_Float(arg);
2779 2779 }
2780 2780
  2781 +VALUE
  2782 +rb_check_to_float(VALUE val)
  2783 +{
  2784 + if (TYPE(val) == T_FLOAT) {
  2785 + return val;
  2786 + }
  2787 + if (!rb_obj_is_kind_of(val, rb_cNumeric)) {
  2788 + return Qnil;
  2789 + }
  2790 + return rb_check_convert_type(val, T_FLOAT, "Float", "to_f");
  2791 +}
  2792 +
2781 2793 double
2782 2794 rb_num2dbl(VALUE val)
2783 2795 {
928 random.c
... ... @@ -1,119 +1,412 @@
1   -/**********************************************************************
2   -
3   - random.c -
4   -
5   - $Author: matz $
6   - created at: Fri Dec 24 16:39:21 JST 1993
7   -
8   - Copyright (C) 1993-2007 Yukihiro Matsumoto
9   -
10   -**********************************************************************/
  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 + */
11 9
12 10 #include "ruby/ruby.h"
  11 +#include "ruby/node.h"
  12 +#include "vm.h"
  13 +#include "id.h"
13 14
14   -#ifdef HAVE_UNISTD_H
15 15 #include <unistd.h>
16   -#endif
17   -#include <limits.h>
18   -#include <math.h>
19 16 #include <time.h>
20 17 #include <sys/types.h>
21 18 #include <sys/stat.h>
22   -#ifdef HAVE_FCNTL_H
23 19 #include <fcntl.h>
24   -#endif
  20 +#include <math.h>
  21 +#include <errno.h>
25 22
26   -#include "ruby/node.h"
27   -#include "vm.h"
  23 +#include "mt.c"
28 24
  25 +VALUE rb_cRandom;
29 26
30   -static void
31   -init_random(void)
  27 +typedef struct {
  28 + VALUE seed;
  29 + struct MT mt;
  30 +} rb_random_t;
  31 +
  32 +#define get_rnd(obj) ((rb_random_t *)DATA_PTR(obj))
  33 +#define default_rnd() (get_rnd(rb_vm_default_random()))
  34 +
  35 +unsigned int
  36 +rb_genrand_int32(void)
  37 +{
  38 + return genrand_int32(&default_rnd()->mt);
  39 +}
  40 +
  41 +double
  42 +rb_genrand_real(void)
32 43 {
33   - srandomdev();
  44 + return genrand_real(&default_rnd()->mt);
34 45 }
35 46
  47 +#define BDIGITS(x) (RBIGNUM_DIGITS(x))
  48 +#define BITSPERDIG (SIZEOF_BDIGITS*CHAR_BIT)
  49 +#define BIGRAD ((BDIGIT_DBL)1 << BITSPERDIG)
  50 +#define DIGSPERINT (SIZEOF_INT/SIZEOF_BDIGITS)
  51 +#define BIGUP(x) ((BDIGIT_DBL)(x) << BITSPERDIG)
  52 +#define BIGDN(x) RSHIFT(x,BITSPERDIG)
  53 +#define BIGLO(x) ((BDIGIT)((x) & (BIGRAD-1)))
  54 +#define BDIGMAX ((BDIGIT)-1)
  55 +
  56 +#define roomof(n, m) (int)(((n)+(m)-1) / (m))
  57 +#define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
  58 +#define SIZEOF_INT32 (31/CHAR_BIT + 1)
  59 +
  60 +static VALUE random_seed(VALUE, SEL);
  61 +
  62 +/* :nodoc: */
36 63 static VALUE
37   -random_number_with_limit(long limit)
  64 +random_alloc(VALUE klass, SEL sel)
38 65 {
39   - long val;
  66 + rb_random_t *r = (rb_random_t *)xmalloc(sizeof(rb_random_t));
  67 + r->seed = INT2FIX(0);
  68 + return Data_Wrap_Struct(rb_cRandom, NULL, NULL, r);
  69 +}
40 70
41   - if (limit == 0) {
42   - /*
43   - * #rand(0) needs to generate a float x, such as 0.0 <= x <= 1.0. However,
44   - * srandom() returns a long. We want to convert that long by divide by RAND_MAX
45   - */
46   - val = random();
47   - return DOUBLE2NUM((double)val / ((unsigned long)RAND_MAX+1));
  71 +static VALUE
  72 +rand_init(struct MT *mt, VALUE vseed)
  73 +{
  74 + VALUE seed;
  75 + long blen = 0;
  76 + int i, j, len;
  77 + unsigned int buf0[SIZEOF_LONG / SIZEOF_INT32 * 4], *buf = buf0;
  78 +
  79 + seed = rb_to_int(vseed);
  80 + switch (TYPE(seed)) {
  81 + case T_FIXNUM:
  82 + len = 1;
  83 + buf[0] = (unsigned int)(FIX2ULONG(seed) & 0xffffffff);
  84 +#if SIZEOF_LONG > SIZEOF_INT32
  85 + if ((buf[1] = (unsigned int)(FIX2ULONG(seed) >> 32)) != 0) ++len;
  86 +#endif
  87 + break;
  88 + case T_BIGNUM:
  89 + blen = RBIGNUM_LEN(seed);
  90 + if (blen == 0) {
  91 + len = 1;
  92 + }
  93 + else {
  94 + if (blen > MT_MAX_STATE * SIZEOF_INT32 / SIZEOF_BDIGITS)
  95 + blen = (len = MT_MAX_STATE) * SIZEOF_INT32 / SIZEOF_BDIGITS;
  96 + len = roomof((int)blen * SIZEOF_BDIGITS, SIZEOF_INT32);
  97 + }
  98 + /* allocate ints for init_by_array */
  99 + if (len > numberof(buf0)) buf = ALLOC_N(unsigned int, len);
  100 + memset(buf, 0, len * sizeof(*buf));
  101 + len = 0;
  102 + for (i = (int)(blen-1); 0 <= i; i--) {
  103 + j = i * SIZEOF_BDIGITS / SIZEOF_INT32;
  104 +#if SIZEOF_BDIGITS < SIZEOF_INT32
  105 + buf[j] <<= BITSPERDIG;
  106 +#endif
  107 + buf[j] |= RBIGNUM_DIGITS(seed)[i];
  108 + if (!len && buf[j]) len = j;
  109 + }
  110 + ++len;
  111 + break;
  112 + default:
  113 + rb_raise(rb_eTypeError, "failed to convert %s into Integer",
  114 + rb_obj_classname(vseed));
  115 + }
  116 + if (len <= 1) {
  117 + init_genrand(mt, buf[0]);
48 118 }
49 119 else {
50   - if (limit < 0) {
51   - /* -LONG_MIN = LONG_MIN, let's avoid that */
52   - if (limit == LONG_MIN) {
53   - limit += 1;
54   - }
55   - limit = -limit;
56   - }
57   - val = random() % limit;
58   - return LONG2NUM(val);
  120 + if (buf[len-1] == 1) /* remove leading-zero-guard */
  121 + len--;
  122 + init_by_array(mt, buf, len);
59 123 }
60   - return Qnil;
  124 + return seed;
61 125 }
62 126
63   -unsigned long rb_genrand_int32(void);
64   -
  127 +/*
  128 + * call-seq: Random.new([seed]) -> prng
  129 + *
  130 + * Creates new Mersenne Twister based pseudorandom number generator with
  131 + * seed. When the argument seed is omitted, the generator is initialized
  132 + * with Random.seed.
  133 + *
  134 + * The argument seed is used to ensure repeatable sequences of random numbers
  135 + * between different runs of the program.
  136 + *
  137 + * prng = Random.new(1234)
  138 + * [ prng.rand, prng.rand ] #=> [0.191519450378892, 0.622108771039832]
  139 + * [ prng.integer(10), prng.integer(1000) ] #=> [4, 664]
  140 + * prng = Random.new(1234)
  141 + * [ prng.rand, prng.rand ] #=> [0.191519450378892, 0.622108771039832]
  142 + */
65 143 static VALUE
66   -random_number_with_bignum_limit(struct RBignum *bignum_limit)
  144 +random_init(VALUE obj, SEL sel, int argc, VALUE *argv)
67 145 {
68   - long nb_long_in_bignum;
69   - long nb_loops;
70   - struct RBignum *div_result;
71   - struct RBignum *result;
72   - int idx;
  146 + VALUE vseed;
  147 + rb_random_t *rnd = get_rnd(obj);
73 148
74   - div_result = RBIGNUM(rb_big_div((VALUE)bignum_limit, LONG2NUM(LONG_MAX)));
75   - // FIXME: Shouldn't use !, what value should I check?
76   - if (!FIXNUM_P((VALUE)div_result)) {
77   - rb_raise(rb_eArgError, "max is too huge");
  149 + if (argc == 0) {
  150 + vseed = random_seed(0, 0);
78 151 }
  152 + else {
  153 + rb_scan_args(argc, argv, "01", &vseed);
  154 + }
  155 + GC_WB(&rnd->seed, rand_init(&rnd->mt, vseed));
  156 + return obj;
  157 +}
  158 +
  159 +#define DEFAULT_SEED_CNT 4
  160 +#define DEFAULT_SEED_LEN (DEFAULT_SEED_CNT * sizeof(int))
  161 +
  162 +static void
  163 +fill_random_seed(unsigned int seed[DEFAULT_SEED_CNT])
  164 +{
  165 + static int n = 0;
  166 + struct timeval tv;
  167 + int fd;
  168 + struct stat statbuf;
  169 +
  170 + memset(seed, 0, DEFAULT_SEED_LEN);
79 171
80   - nb_long_in_bignum = FIX2LONG((VALUE)div_result);
81   - nb_loops = 1 + FIX2LONG(random_number_with_limit(nb_long_in_bignum));
82   - result = RBIGNUM(rb_int2big(0));
83   - for (idx = 0; idx < nb_loops; idx++) {
84   - // This creates a bignum on each iteration... Not really good :-/
85   - result = RBIGNUM(rb_big_plus((VALUE)result, random_number_with_limit(LONG_MAX)));
  172 + if ((fd = open("/dev/urandom", O_RDONLY
  173 +#ifdef O_NONBLOCK
  174 + |O_NONBLOCK
  175 +#endif
  176 +#ifdef O_NOCTTY
  177 + |O_NOCTTY
  178 +#endif
  179 +#ifdef O_NOFOLLOW
  180 + |O_NOFOLLOW
  181 +#endif
  182 + )) >= 0) {
  183 + if (fstat(fd, &statbuf) == 0 && S_ISCHR(statbuf.st_mode)) {
  184 + (void)read(fd, seed, DEFAULT_SEED_LEN);
  185 + }
  186 + close(fd);
86 187 }
87   - return ((VALUE)result);
  188 +
  189 + gettimeofday(&tv, 0);
  190 + seed[0] ^= tv.tv_usec;
  191 + seed[1] ^= (unsigned int)tv.tv_sec;
  192 +#if SIZEOF_TIME_T > SIZEOF_INT
  193 + seed[0] ^= (unsigned int)((time_t)tv.tv_sec >> SIZEOF_INT * CHAR_BIT);
  194 +#endif
  195 + seed[2] ^= getpid() ^ (n++ << 16);
  196 + seed[3] ^= (unsigned int)(VALUE)&seed;
  197 +#if SIZEOF_VOIDP > SIZEOF_INT
  198 + seed[2] ^= (unsigned int)((VALUE)&seed >> SIZEOF_INT * CHAR_BIT);
  199 +#endif
88 200 }
89 201
90   -unsigned long
91   -rb_genrand_int32(void)
  202 +static VALUE
  203 +make_seed_value(const void *ptr)
  204 +{
  205 + BDIGIT *digits;
  206 + NEWOBJ(big, struct RBignum);
  207 + OBJSETUP(big, rb_cBignum, T_BIGNUM);
  208 +
  209 + RBIGNUM_SET_SIGN(big, 1);
  210 + rb_big_resize((VALUE)big, DEFAULT_SEED_LEN / SIZEOF_BDIGITS + 1);
  211 + digits = RBIGNUM_DIGITS(big);
  212 +
  213 + MEMCPY(digits, ptr, char, DEFAULT_SEED_LEN);
  214 +
  215 + /* set leading-zero-guard if need. */
  216 + digits[RBIGNUM_LEN(big)-1] = digits[RBIGNUM_LEN(big)-2] <= 1 ? 1 : 0;
  217 +
  218 + return rb_big_norm((VALUE)big);
  219 +}
  220 +
  221 +/*
  222 + * call-seq: Random.seed -> integer
  223 + *
  224 + * Returns arbitrary value for seed.
  225 + */
  226 +static VALUE
  227 +random_seed(VALUE rcv, SEL sel)
92 228 {
93   - unsigned long result;
94   - short nb_loops;
95   - int idx;
  229 + unsigned int buf[DEFAULT_SEED_CNT];
  230 + fill_random_seed(buf);
  231 + return make_seed_value(buf);
  232 +}
96 233
97   - result = 0;
98   - nb_loops = 1 + (random() % 2);
99   - for (idx = 0; idx < nb_loops; idx++) {
100   - result += random();
  234 +/*
  235 + * call-seq: prng.seed -> integer
  236 + *
  237 + * Returns the seed of the generator.
  238 + */
  239 +static VALUE
  240 +random_get_seed(VALUE obj, SEL sel)
  241 +{
  242 + return get_rnd(obj)->seed;
  243 +}
  244 +
  245 +/* :nodoc: */
  246 +static VALUE
  247 +random_copy(VALUE obj, SEL sel, VALUE orig)
  248 +{
  249 + rb_random_t *rnd1 = get_rnd(obj);
  250 + rb_random_t *rnd2 = get_rnd(orig);
  251 + struct MT *mt = &rnd1->mt;
  252 +
  253 + *rnd1 = *rnd2;
  254 + GC_WB(&rnd1->seed, rnd2->seed);
  255 + mt->next = mt->state + numberof(mt->state) - mt->left + 1;
  256 + return obj;
  257 +}
  258 +
  259 +static VALUE
  260 +mt_state(const struct MT *mt)
  261 +{
  262 + const int n = numberof(mt->state);
  263 + VALUE bigo = rb_big_new(n, 1);
  264 + BDIGIT *d = RBIGNUM_DIGITS(bigo);
  265 + for (int i = 0; i < n; i++) {
  266 + unsigned int x = mt->state[i];
  267 + *d++ = (BDIGIT)x;
101 268 }
102   - return result;
  269 + return rb_big_norm(bigo);
103 270 }
104 271
105   -double
106   -rb_genrand_real(void)
  272 +/* :nodoc: */
  273 +static VALUE
  274 +random_state(VALUE obj, SEL sel)
107 275 {
108   - return NUM2DBL(random_number_with_limit(0));
  276 + rb_random_t *rnd = get_rnd(obj);
  277 + return mt_state(&rnd->mt);
  278 +}
  279 +
  280 +/* :nodoc: */
  281 +static VALUE
  282 +random_s_state(VALUE klass, SEL sel)
  283 +{
  284 + return mt_state(&default_rnd()->mt);
  285 +}
  286 +
  287 +/* :nodoc: */
  288 +static VALUE
  289 +random_left(VALUE obj, SEL sel)
  290 +{
  291 + rb_random_t *rnd = get_rnd(obj);
  292 + return INT2FIX(rnd->mt.left);
  293 +}
  294 +
  295 +/* :nodoc: */
  296 +static VALUE
  297 +random_s_left(VALUE klass, SEL sel)
  298 +{
  299 + return INT2FIX(default_rnd()->mt.left);
  300 +}
  301 +
  302 +/* :nodoc: */
  303 +static VALUE
  304 +random_dump(VALUE obj, SEL sel)
  305 +{
  306 + rb_random_t *rnd = get_rnd(obj);
  307 + VALUE dump = rb_ary_new2(3);
  308 +
  309 + rb_ary_push(dump, mt_state(&rnd->mt));
  310 + rb_ary_push(dump, INT2FIX(rnd->mt.left));
  311 + rb_ary_push(dump, rnd->seed);
  312 +
  313 + return dump;
  314 +}
  315 +
  316 +/* :nodoc: */
  317 +static VALUE
  318 +random_load(VALUE obj, SEL sel, VALUE dump)
  319 +{
  320 + rb_random_t *rnd = get_rnd(obj);
  321 + struct MT *mt = &rnd->mt;
  322 + VALUE state, left = INT2FIX(1), seed = INT2FIX(0);
  323 + unsigned long x;
  324 +
  325 + Check_Type(dump, T_ARRAY);
  326 + switch (RARRAY_LEN(dump)) {
  327 + case 3:
  328 + seed = RARRAY_AT(dump, 2);
  329 + case 2:
  330 + left = RARRAY_AT(dump, 1);
  331 + case 1:
  332 + state = RARRAY_AT(dump, 0);
  333 + break;
  334 + default:
  335 + rb_raise(rb_eArgError, "wrong dump data");
  336 + }
  337 + memset(mt->state, 0, sizeof(mt->state));
  338 +#if 0
  339 + if (FIXNUM_P(state)) {
  340 + x = FIX2ULONG(state);
  341 + mt->state[0] = (unsigned int)x;
  342 +#if SIZEOF_LONG / SIZEOF_INT >= 2
  343 + mt->state[1] = (unsigned int)(x >> BITSPERDIG);
  344 +#endif
  345 +#if SIZEOF_LONG / SIZEOF_INT >= 3
  346 + mt->state[2] = (unsigned int)(x >> 2 * BITSPERDIG);
  347 +#endif
  348 +#if SIZEOF_LONG / SIZEOF_INT >= 4
  349 + mt->state[3] = (unsigned int)(x >> 3 * BITSPERDIG);
  350 +#endif
  351 + }
  352 + else {
  353 + BDIGIT *d;
  354 + long len;
  355 + Check_Type(state, T_BIGNUM);
  356 + len = RBIGNUM_LEN(state);
  357 + if (len > roomof(sizeof(mt->state), SIZEOF_BDIGITS)) {
  358 + len = roomof(sizeof(mt->state), SIZEOF_BDIGITS);
  359 + }
  360 +#if SIZEOF_BDIGITS < SIZEOF_INT
  361 + else if (len % DIGSPERINT) {
  362 + d = RBIGNUM_DIGITS(state) + len;
  363 +# if DIGSPERINT == 2
  364 + --len;
  365 + x = *--d;
  366 +# else
  367 + x = 0;
  368 + do {
  369 + x = (x << BITSPERDIG) | *--d;
  370 + } while (--len % DIGSPERINT);
  371 +# endif
  372 + mt->state[len / DIGSPERINT] = (unsigned int)x;
  373 + }
  374 +#endif
  375 + if (len > 0) {
  376 + d = BDIGITS(state) + len;
  377 + do {
  378 + --len;
  379 + x = *--d;
  380 +# if DIGSPERINT == 2
  381 + --len;
  382 + x = (x << BITSPERDIG) | *--d;
  383 +# elif SIZEOF_BDIGITS < SIZEOF_INT
  384 + do {
  385 + x = (x << BITSPERDIG) | *--d;
  386 + } while (--len % DIGSPERINT);
  387 +# endif
  388 + mt->state[len / DIGSPERINT] = (unsigned int)x;
  389 + } while (len > 0);
  390 + }
  391 + }
  392 +#endif
  393 + x = NUM2ULONG(left);
  394 + if (x > numberof(mt->state)) {
  395 + rb_raise(rb_eArgError, "wrong value");
  396 + }
  397 + mt->left = (unsigned int)x;
  398 + mt->next = mt->state + numberof(mt->state) - x + 1;
  399 + GC_WB(&rnd->seed, rb_to_int(seed));
  400 +
  401 + return obj;
109 402 }
110 403
111 404 /*
112 405 * call-seq:
113 406 * srand(number=0) => old_seed
114   - *
  407 + *
115 408 * Seeds the pseudorandom number generator to the value of
116   - * <i>number</i>.<code>to_i.abs</code>. If <i>number</i> is omitted
  409 + * <i>number</i>. If <i>number</i> is omitted
117 410 * or zero, seeds the generator using a combination of the time, the
118 411 * process id, and a sequence number. (This is also the behavior if
119 412 * <code>Kernel::rand</code> is called without previously calling
@@ -125,55 +418,378 @@ rb_genrand_real(void)
125 418 static VALUE
126 419 rb_f_srand(VALUE obj, SEL sel, int argc, VALUE *argv)
127 420 {
128   - VALUE old_seed;
129   - VALUE seed_param;
130   - VALUE seed_int;
131   - unsigned seed = 0;
  421 + VALUE seed, old;
  422 + rb_random_t *r = default_rnd();
132 423
  424 + rb_secure(4);
133 425 if (argc == 0) {
134   - srandomdev();
135   - seed = (unsigned)random();
136   - seed_int = UINT2NUM(seed);
  426 + seed = random_seed(0, 0);
137 427 }
138 428 else {
139   - rb_scan_args(argc, argv, "01", &seed_param);
140   - seed_int = rb_to_int(seed_param);
141   - switch (TYPE(seed_int)) {
142   - case T_BIGNUM:
143   - // In case we need to keep 'seed.to_i.abs'
144   - /*
145   - if (RBIGNUM_NEGATIVE_P(seed_int)) {
146   - seed_int = rb_big_uminus(seed_int);
  429 + rb_scan_args(argc, argv, "01", &seed);
  430 + }
  431 + old = r->seed;
  432 + GC_WB(&r->seed, rand_init(&r->mt, seed));
  433 +
  434 + return old;
  435 +}
  436 +
  437 +static unsigned long
  438 +make_mask(unsigned long x)
  439 +{
  440 + x = x | x >> 1;
  441 + x = x | x >> 2;
  442 + x = x | x >> 4;
  443 + x = x | x >> 8;
  444 + x = x | x >> 16;
  445 +#if 4 < SIZEOF_LONG
  446 + x = x | x >> 32;
  447 +#endif
  448 + return x;
  449 +}
  450 +
  451 +static unsigned long
  452 +limited_rand(struct MT *mt, unsigned long limit)
  453 +{
  454 + if (limit == 0) {
  455 + return 0;
  456 + }
  457 + unsigned long val, mask = make_mask(limit);
  458 +retry:
  459 + val = 0;
  460 + for (int i = SIZEOF_LONG / SIZEOF_INT32 - 1; 0 <= i; i--) {
  461 + if ((mask >> (i * 32)) & 0xffffffff) {
  462 + val |= (unsigned long)genrand_int32(mt) << (i * 32);
  463 + val &= mask;
  464 + if (limit < val) {
  465 + goto retry;
147 466 }
148   - */
149   - for (int i = 0; i < RBIGNUM_LEN(seed_int); i++) {
150   - seed += (unsigned int)RBIGNUM_DIGITS(seed_int)[i];
  467 + }
  468 + }
  469 + return val;
  470 +}
  471 +
  472 +static VALUE
  473 +limited_big_rand(struct MT *mt, struct RBignum *limit)
  474 +{
  475 + const long len = (RBIGNUM_LEN(limit) * SIZEOF_BDIGITS + 3) / 4;
  476 + struct RBignum *val = (struct RBignum *)rb_big_clone((VALUE)limit);
  477 + RBIGNUM_SET_SIGN(val, 1);
  478 +#if SIZEOF_BDIGITS == 2
  479 +# define BIG_GET32(big,i) \
  480 + (RBIGNUM_DIGITS(big)[(i)*2] | \
  481 + ((i)*2+1 < RBIGNUM_LEN(big) ? \
  482 + (RBIGNUM_DIGITS(big)[(i)*2+1] << 16) : \
  483 + 0))
  484 +# define BIG_SET32(big,i,d) \
  485 + ((RBIGNUM_DIGITS(big)[(i)*2] = (d) & 0xffff), \
  486 + ((i)*2+1 < RBIGNUM_LEN(big) ? \
  487 + (RBIGNUM_DIGITS(big)[(i)*2+1] = (d) >> 16) : \
  488 + 0))
  489 +#else
  490 + /* SIZEOF_BDIGITS == 4 */
  491 +# define BIG_GET32(big,i) (RBIGNUM_DIGITS(big)[i])
  492 +# define BIG_SET32(big,i,d) (RBIGNUM_DIGITS(big)[i] = (d))
  493 +#endif
  494 + unsigned long mask;
  495 + int boundary;
  496 +retry:
  497 + mask = 0;
  498 + boundary = 1;
  499 + for (long i = len - 1; 0 <= i; i--) {
  500 + const unsigned long lim = BIG_GET32(limit, i);
  501 + unsigned long rnd;
  502 + mask = mask != 0 ? 0xffffffff : make_mask(lim);
  503 + if (mask != 0) {
  504 + rnd = genrand_int32(mt) & mask;
  505 + if (boundary) {
  506 + if (lim < rnd) {
  507 + goto retry;
  508 + }
  509 + if (rnd < lim) {
  510 + boundary = 0;
  511 + }
  512 + }
  513 + }
  514 + else {
  515 + rnd = 0;
  516 + }
  517 + BIG_SET32(val, i, (BDIGIT)rnd);
  518 + }
  519 + return rb_big_norm((VALUE)val);
  520 +}
  521 +
  522 +unsigned long
  523 +rb_rand_internal(unsigned long i)
  524 +{
  525 + struct MT *mt = &default_rnd()->mt;
  526 + if (!genrand_initialized(mt)) {
  527 + rand_init(mt, random_seed(0, 0));
  528 + }
  529 + return limited_rand(mt, i);
  530 +}
  531 +
  532 +unsigned int
  533 +rb_random_int32(VALUE obj)
  534 +{
  535 + rb_random_t *rnd = get_rnd(obj);
  536 + return genrand_int32(&rnd->mt);
  537 +}
  538 +
  539 +double
  540 +rb_random_real(VALUE obj)
  541 +{
  542 + rb_random_t *rnd = get_rnd(obj);
  543 + return genrand_real(&rnd->mt);
  544 +}
  545 +
  546 +/*
  547 + * call-seq: prng.bytes(size) -> prng
  548 + *
  549 + * Returns a random binary string. The argument size specified the length of
  550 + * the result string.
  551 + */
  552 +static VALUE
  553 +random_bytes(VALUE obj, SEL sel, VALUE len)
  554 +{
  555 + long n = NUM2LONG(rb_to_int(len));
  556 + if (n <= 0) {
  557 + return rb_str_new2("");
  558 + }
  559 + rb_random_t *rnd = get_rnd(obj);
  560 + UInt8 *ptr = (UInt8 *)malloc(n);
  561 + unsigned int r = genrand_int32(&rnd->mt);
  562 + for (long i = 0; i < n; i++) {
  563 + ptr[i] = (char)r;
  564 + r >>= CHAR_BIT;
  565 + }
  566 + VALUE bytes = rb_bytestring_new_with_data(ptr, n);
  567 + free(ptr);
  568 + return bytes;
  569 +}
  570 +
  571 +static VALUE
  572 +range_values(VALUE vmax, VALUE *begp, int *exclp)
  573 +{
  574 + VALUE end;
  575 + if (!rb_range_values(vmax, begp, &end, exclp)) {
  576 + return Qfalse;
  577 + }
  578 + if (!rb_vm_respond_to(end, selMINUS, false)) {
  579 + return Qfalse;
  580 + }
  581 + VALUE r = rb_vm_call(end, selMINUS, 1, begp, false);
  582 + if (NIL_P(r)) {
  583 + return Qfalse;
  584 + }
  585 + return r;
  586 +}
  587 +
  588 +static VALUE
  589 +rand_int(struct MT *mt, VALUE vmax, int restrictive)
  590 +{
  591 + long max;
  592 + unsigned long r;
  593 +
  594 + if (FIXNUM_P(vmax)) {
  595 + max = FIX2LONG(vmax);
  596 + if (!max) return Qnil;
  597 + if (max < 0) {
  598 + if (restrictive) return Qnil;
  599 + max = -max;
  600 + }
  601 + r = limited_rand(mt, (unsigned long)max - 1);
  602 + return ULONG2NUM(r);
  603 + }
  604 + else {
  605 + VALUE ret;
  606 + if (rb_bigzero_p(vmax)) return Qnil;
  607 + if (!RBIGNUM_SIGN(vmax)) {
  608 + if (restrictive) return Qnil;
  609 + vmax = rb_big_clone(vmax);
  610 + RBIGNUM_SET_SIGN(vmax, 1);
  611 + }
  612 + vmax = rb_big_minus(vmax, INT2FIX(1));
  613 + if (FIXNUM_P(vmax)) {
  614 + max = FIX2LONG(vmax);
  615 + if (max == -1) return Qnil;
  616 + r = limited_rand(mt, max);
  617 + return LONG2NUM(r);
  618 + }
  619 + ret = limited_big_rand(mt, RBIGNUM(vmax));
  620 + return ret;
  621 + }
  622 +}
  623 +
  624 +static inline double
  625 +float_value(VALUE v)
  626 +{
  627 + double x = RFLOAT_VALUE(v);
  628 + if (isinf(x) || isnan(x)) {
  629 + VALUE error = INT2FIX(EDOM);
  630 + rb_exc_raise(rb_class_new_instance(1, &error, rb_eSystemCallError));
  631 + }
  632 + return x;
  633 +}
  634 +
  635 +/*
  636 + * call-seq:
  637 + * prng.rand -> float
  638 + * prng.rand(limit) -> number
  639 + *
  640 + * When the argument is an +Integer+ or a +Bignum+, it returns a
  641 + * random integer greater than or equal to zero and less than the
  642 + * argument. Unlike Random.rand, when the argument is a negative
  643 + * integer or zero, it raises an ArgumentError.
  644 + *
  645 + * When the argument is a +Float+, it returns a random floating point
  646 + * number between 0.0 and _max_, including 0.0 and excluding _max_.
  647 + *
  648 + * When the argument _limit_ is a +Range+, it returns a random
  649 + * number where range.member?(number) == true.
  650 + * prng.rand(5..9) # => one of [5, 6, 7, 8, 9]
  651 + * prng.rand(5...9) # => one of [5, 6, 7, 8]
  652 + * prng.rand(5.0..9.0) # => between 5.0 and 9.0, including 9.0
  653 + * prng.rand(5.0...9.0) # => between 5.0 and 9.0, excluding 9.0
  654 + *
  655 + * +begin+/+end+ of the range have to have subtract and add methods.
  656 + *
  657 + * Otherwise, it raises an ArgumentError.
  658 + */
  659 +static VALUE
  660 +random_rand(VALUE obj, SEL sel, int argc, VALUE *argv)
  661 +{
  662 + rb_random_t *rnd = get_rnd(obj);
  663 + VALUE beg = Qundef, v;
  664 + int excl = 0;
  665 +
  666 + if (argc == 0) {
  667 +zero_arg:
  668 + return rb_float_new(genrand_real(&rnd->mt));
  669 + }
  670 + else if (argc != 1) {
  671 + rb_raise(rb_eArgError, "wrong number of arguments (%d for 0..1)", argc);
  672 + }
  673 + VALUE vmax = argv[0];
  674 + if (NIL_P(vmax)) {
  675 + goto zero_arg;
  676 + }
  677 + else if (TYPE(vmax) != T_FLOAT
  678 + && (v = rb_check_to_integer(vmax, "to_int"), !NIL_P(v))) {
  679 + v = rand_int(&rnd->mt, vmax = v, 1);
  680 + }
  681 + else if (v = rb_check_to_float(vmax), !NIL_P(v)) {
  682 + const double max = float_value(v);
  683 + if (max > 0.0) {
  684 + v = rb_float_new(max * genrand_real(&rnd->mt));
  685 + }
  686 + else {
  687 + v = Qnil;
  688 + }
  689 + }
  690 + else if ((v = range_values(vmax, &beg, &excl)) != Qfalse) {
  691 + vmax = v;
  692 + if (TYPE(vmax) != T_FLOAT
  693 + && (v = rb_check_to_integer(vmax, "to_int"), !NIL_P(v))) {
  694 + long max;
  695 + vmax = v;
  696 + v = Qnil;
  697 + if (FIXNUM_P(vmax)) {
  698 +fixnum:
  699 + if ((max = FIX2LONG(vmax) - excl) >= 0) {
  700 + unsigned long r = limited_rand(&rnd->mt, (unsigned long)max);
  701 + v = ULONG2NUM(r);
  702 + }
  703 + }
  704 + else if (BUILTIN_TYPE(vmax) == T_BIGNUM && RBIGNUM_SIGN(vmax)
  705 + && !rb_bigzero_p(vmax)) {
  706 + vmax = excl ? rb_big_minus(vmax, INT2FIX(1)) : rb_big_norm(vmax);
  707 + if (FIXNUM_P(vmax)) {
  708 + excl = 0;
  709 + goto fixnum;
  710 + }
  711 + v = limited_big_rand(&rnd->mt, RBIGNUM(vmax));
151 712 }
152   - break ;
153   - case T_FIXNUM:
154   - // In case we need to keep 'seed.to_i.abs'
155   - /*
156   - if (FIX2LONG(seed_int) < 0) {
157   - seed_int = rb_fix_uminus(seed_int);
  713 + }
  714 + else if (v = rb_check_to_float(vmax), !NIL_P(v)) {
  715 + double max = float_value(v), r;
  716 + v = Qnil;
  717 + if (max > 0.0) {
  718 + if (excl) {
  719 + r = genrand_real(&rnd->mt);
  720 + }
  721 + else {
  722 + r = genrand_real2(&rnd->mt);
  723 + }
  724 + v = rb_float_new(r * max);
  725 + }
  726 + else if (max == 0.0 && !excl) {
  727 + v = rb_float_new(0.0);
158 728 }
159   - */
160   - seed = (unsigned int)FIX2LONG(seed_int);
161   - break ;
162 729 }
163 730 }
164   - srandom(seed);
  731 + else {
  732 + v = Qnil;
  733 + NUM2LONG(vmax);
  734 + }
  735 + if (NIL_P(v)) {
  736 + VALUE mesg = rb_str_new2("invalid argument - ");
  737 + rb_str_append(mesg, rb_obj_as_string(argv[0]));
  738 + rb_exc_raise(rb_exc_new3(rb_eArgError, mesg));
  739 + }
  740 + if (beg == Qundef) {
  741 + return v;
  742 + }
  743 + if (FIXNUM_P(beg) && FIXNUM_P(v)) {
  744 + long x = FIX2LONG(beg) + FIX2LONG(v);
  745 + return LONG2NUM(x);
  746 + }
  747 + switch (TYPE(v)) {
  748 + case T_BIGNUM:
  749 + return rb_big_plus(v, beg);
  750 + case T_FLOAT:
  751 + {
  752 + double d = RFLOAT_VALUE(v) + RFLOAT_VALUE(rb_check_to_float(beg));
  753 + return DOUBLE2NUM(d);
  754 + }
  755 + default:
  756 + return rb_vm_call(v, selPLUS, 1, &beg, false);
  757 + }
  758 +}
165 759
166   - old_seed = rb_vm_rand_seed();
167   - // Ruby's behaviour is weird. It stores the 'seed.to_i' value, instead of
168   - // the 'seed.to_i.abs' value, or just 'seed'. Which one should we use?
169   - rb_vm_set_rand_seed(seed_int);
170   - return old_seed;
  760 +/*
  761 + * call-seq:
  762 + * prng1 == prng2 -> true or false
  763 + *
  764 + * Returns true if the generators' states equal.
  765 + */
  766 +static VALUE
  767 +random_equal(VALUE self, SEL sel, VALUE other)
  768 +{
  769 + if (rb_obj_class(self) != rb_obj_class(other)) {
  770 + return Qfalse;
  771 + }
  772 + rb_random_t *r1 = get_rnd(self);
  773 + rb_random_t *r2 = get_rnd(other);
  774 + if (rb_equal(r1->seed, r2->seed) != Qtrue) {
  775 + return Qfalse;
  776 + }
  777 + if (memcmp(r1->mt.state, r2->mt.state, sizeof(r1->mt.state))) {
  778 + return Qfalse;
  779 + }
  780 + if ((r1->mt.next - r1->mt.state) != (r2->mt.next - r2->mt.state)) {
  781 + return Qfalse;
  782 + }
  783 + if (r1->mt.left != r2->mt.left) {
  784 + return Qfalse;
  785 + }
  786 + return Qtrue;
171 787 }
172 788
173 789 /*
174 790 * call-seq:
175 791 * rand(max=0) => number
176   - *
  792 + *
177 793 * Converts <i>max</i> to an integer using max1 =
178 794 * max<code>.to_i.abs</code>. If the result is zero, returns a
179 795 * pseudorandom floating point number greater than or equal to 0.0 and
@@ -182,7 +798,7 @@ rb_f_srand(VALUE obj, SEL sel, int argc, VALUE *argv)
182 798 * may be used to ensure repeatable sequences of random numbers between
183 799 * different runs of the program. Ruby currently uses a modified
184 800 * Mersenne Twister with a period of 2**19937-1.
185   - *
  801 + *
186 802 * srand 1234 #=> 0
187 803 * [ rand, rand ] #=> [0.191519450163469, 0.49766366626136]
188 804 * [ rand(10), rand(1000) ] #=> [6, 817]
@@ -193,54 +809,68 @@ rb_f_srand(VALUE obj, SEL sel, int argc, VALUE *argv)
193 809 static VALUE
194 810 rb_f_rand(VALUE obj, SEL sel, int argc, VALUE *argv)
195 811 {
196   - VALUE arg_max;
197   - long max;
  812 + struct MT *mt = &default_rnd()->mt;
198 813
199   - rb_scan_args(argc, argv, "01", &arg_max);
200   - switch (TYPE(arg_max)) {
201   - case T_FLOAT:
202   - if (RFLOAT_VALUE(arg_max) <= LONG_MAX && RFLOAT_VALUE(arg_max) >= LONG_MIN) {
203   - max = (long)RFLOAT_VALUE(arg_max);
204   - break;
205   - }
206   - if (RFLOAT_VALUE(arg_max) < 0)
207   - arg_max = rb_dbl2big(-RFLOAT_VALUE(arg_max));
208   - else
209   - arg_max = rb_dbl2big(RFLOAT_VALUE(arg_max));
210   - /* fall through */
211   - case T_BIGNUM:
212   - bignum:
213   - {
214   - struct RBignum *limit = (struct RBignum *)arg_max;
215   - if (!RBIGNUM_SIGN(limit)) {
216   - limit = (struct RBignum *)rb_big_clone(arg_max);
217   - RBIGNUM_SET_SIGN(limit, 1);
218   - }
219   - limit = (struct RBignum *)rb_big_minus((VALUE)limit, INT2FIX(1));
220   - if (FIXNUM_P((VALUE)limit)) {
221   - max = FIX2LONG((VALUE)limit) + 1;
222   - break;
223   - }
224   - return random_number_with_bignum_limit(limit);
225   - }
226   - case T_NIL:
227   - max = 0;
228   - break;
229   - default:
230   - arg_max = rb_Integer(arg_max);
231   - if (TYPE(arg_max) == T_BIGNUM) goto bignum;
232   - case T_FIXNUM:
233   - max = FIX2LONG(arg_max);
234   - break;
  814 + if (!genrand_initialized(mt)) {
  815 + rand_init(mt, random_seed(0, 0));
  816 + }
  817 + if (argc == 0) {
  818 + goto zero_arg;
235 819 }
  820 + VALUE vmax;
  821 + rb_scan_args(argc, argv, "01", &vmax);
  822 + if (NIL_P(vmax)) {
  823 + goto zero_arg;
  824 + }
  825 + vmax = rb_to_int(vmax);
  826 + VALUE r;
  827 + if (vmax == INT2FIX(0) || NIL_P(r = rand_int(mt, vmax, 0))) {
  828 +zero_arg:
  829 + return DBL2NUM(genrand_real(mt));
  830 + }
  831 + return r;
  832 +}
236 833
237   - return random_number_with_limit(max);
  834 +static void
  835 +Init_RandomSeed(void)
  836 +{
  837 + VALUE random = random_alloc(0, 0);
  838 + unsigned int initial[DEFAULT_SEED_CNT];
  839 + GC_WB(&get_rnd(random)->seed, make_seed_value(initial));
  840 + rb_vm_set_default_random(random);
  841 +}
  842 +
  843 +void
  844 +rb_reset_random_seed(void)
  845 +{
  846 + rb_random_t *r = default_rnd();
  847 + uninit_genrand(&r->mt);
  848 + r->seed = INT2FIX(0);
238 849 }
239 850
240 851 void
241 852 Init_Random(void)
242 853 {
243   - init_random();
  854 + Init_RandomSeed();
244 855 rb_objc_define_module_function(rb_mKernel, "srand", rb_f_srand, -1);
245 856 rb_objc_define_module_function(rb_mKernel, "rand", rb_f_rand, -1);
  857 +
  858 + rb_cRandom = rb_define_class("Random", rb_cObject);
  859 + rb_objc_define_method(*(VALUE *)rb_cRandom, "alloc", random_alloc, 0);
  860 + rb_objc_define_method(rb_cRandom, "initialize", random_init, -1);
  861 + rb_objc_define_method(rb_cRandom, "rand", random_rand, -1);