Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 247 lines (219 sloc) 6.469 kB
9c1d230 committing experimental branch content
Laurent Sansonetti authored
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 **********************************************************************/
11
12 #include "ruby/ruby.h"
13
14 #ifdef HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
17 #include <limits.h>
18 #include <math.h>
9c1d230 committing experimental branch content
Laurent Sansonetti authored
19 #include <time.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #ifdef HAVE_FCNTL_H
23 #include <fcntl.h>
24 #endif
25
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
26 #include "ruby/node.h"
27 #include "vm.h"
28
29
30 static void
31 init_random(void)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
32 {
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
33 srandomdev();
9c1d230 committing experimental branch content
Laurent Sansonetti authored
34 }
35
36 static VALUE
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
37 random_number_with_limit(long limit)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
38 {
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
39 long val;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
40
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
41 if (limit == 0) {
26eb749 Fixed Kernel#rand(nil) random float generation (patch by nagachika00 …
Laurent Sansonetti authored
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 */
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
46 val = random();
26eb749 Fixed Kernel#rand(nil) random float generation (patch by nagachika00 …
Laurent Sansonetti authored
47 return DOUBLE2NUM((double)val / ((unsigned long)RAND_MAX+1));
9c1d230 committing experimental branch content
Laurent Sansonetti authored
48 }
49 else {
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
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);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
59 }
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
60 return Qnil;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
61 }
62
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
63 unsigned long rb_genrand_int32(void);
64
9c1d230 committing experimental branch content
Laurent Sansonetti authored
65 static VALUE
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
66 random_number_with_bignum_limit(struct RBignum *bignum_limit)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
67 {
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
68 long nb_long_in_bignum;
69 long nb_loops;
70 struct RBignum *div_result;
71 struct RBignum *result;
72 int idx;
73
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");
9c1d230 committing experimental branch content
Laurent Sansonetti authored
78 }
79
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
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)));
86 }
87 return ((VALUE)result);
88 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
89
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
90 unsigned long
91 rb_genrand_int32(void)
92 {
93 unsigned long result;
94 short nb_loops;
95 int idx;
96
97 result = 0;
98 nb_loops = 1 + (random() % 2);
99 for (idx = 0; idx < nb_loops; idx++) {
100 result += random();
101 }
102 return result;
103 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
104
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
105 double
106 rb_genrand_real(void)
107 {
108 return NUM2DBL(random_number_with_limit(0));
9c1d230 committing experimental branch content
Laurent Sansonetti authored
109 }
110
111 /*
112 * call-seq:
113 * srand(number=0) => old_seed
114 *
115 * Seeds the pseudorandom number generator to the value of
116 * <i>number</i>.<code>to_i.abs</code>. If <i>number</i> is omitted
117 * or zero, seeds the generator using a combination of the time, the
118 * process id, and a sequence number. (This is also the behavior if
119 * <code>Kernel::rand</code> is called without previously calling
120 * <code>srand</code>, but without the sequence.) By setting the seed
121 * to a known value, scripts can be made deterministic during testing.
122 * The previous seed value is returned. Also see <code>Kernel::rand</code>.
123 */
124
125 static VALUE
349dd2b ported the random.c apis to the new runtime
Laurent Sansonetti authored
126 rb_f_srand(VALUE obj, SEL sel, int argc, VALUE *argv)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
127 {
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
128 VALUE old_seed;
129 VALUE seed_param;
130 VALUE seed_int;
131 unsigned seed = 0;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
132
133 if (argc == 0) {
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
134 srandomdev();
135 seed = (unsigned)random();
136 seed_int = UINT2NUM(seed);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
137 }
138 else {
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
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);
147 }
148 */
149 for (int i = 0; i < RBIGNUM_LEN(seed_int); i++) {
150 seed += (unsigned int)RBIGNUM_DIGITS(seed_int)[i];
151 }
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);
158 }
159 */
160 seed = (unsigned int)FIX2LONG(seed_int);
161 break ;
162 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
163 }
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
164 srandom(seed);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
165
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
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;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
171 }
172
173 /*
174 * call-seq:
175 * rand(max=0) => number
176 *
177 * Converts <i>max</i> to an integer using max1 =
178 * max<code>.to_i.abs</code>. If the result is zero, returns a
179 * pseudorandom floating point number greater than or equal to 0.0 and
180 * less than 1.0. Otherwise, returns a pseudorandom integer greater
181 * than or equal to zero and less than max1. <code>Kernel::srand</code>
182 * may be used to ensure repeatable sequences of random numbers between
183 * different runs of the program. Ruby currently uses a modified
184 * Mersenne Twister with a period of 2**19937-1.
185 *
186 * srand 1234 #=> 0
187 * [ rand, rand ] #=> [0.191519450163469, 0.49766366626136]
188 * [ rand(10), rand(1000) ] #=> [6, 817]
189 * srand 1234 #=> 1234
190 * [ rand, rand ] #=> [0.191519450163469, 0.49766366626136]
191 */
192
193 static VALUE
349dd2b ported the random.c apis to the new runtime
Laurent Sansonetti authored
194 rb_f_rand(VALUE obj, SEL sel, int argc, VALUE *argv)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
195 {
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
196 VALUE arg_max;
197 long max;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
198
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
199 rb_scan_args(argc, argv, "01", &arg_max);
200 switch (TYPE(arg_max)) {
9c1d230 committing experimental branch content
Laurent Sansonetti authored
201 case T_FLOAT:
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
202 if (RFLOAT_VALUE(arg_max) <= LONG_MAX && RFLOAT_VALUE(arg_max) >= LONG_MIN) {
203 max = (long)RFLOAT_VALUE(arg_max);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
204 break;
205 }
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
206 if (RFLOAT_VALUE(arg_max) < 0)
207 arg_max = rb_dbl2big(-RFLOAT_VALUE(arg_max));
9c1d230 committing experimental branch content
Laurent Sansonetti authored
208 else
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
209 arg_max = rb_dbl2big(RFLOAT_VALUE(arg_max));
9c1d230 committing experimental branch content
Laurent Sansonetti authored
210 /* fall through */
211 case T_BIGNUM:
212 bignum:
213 {
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
214 struct RBignum *limit = (struct RBignum *)arg_max;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
215 if (!RBIGNUM_SIGN(limit)) {
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
216 limit = (struct RBignum *)rb_big_clone(arg_max);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
217 RBIGNUM_SET_SIGN(limit, 1);
218 }
219 limit = (struct RBignum *)rb_big_minus((VALUE)limit, INT2FIX(1));
220 if (FIXNUM_P((VALUE)limit)) {
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
221 max = FIX2LONG((VALUE)limit) + 1;
222 break;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
223 }
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
224 return random_number_with_bignum_limit(limit);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
225 }
226 case T_NIL:
227 max = 0;
228 break;
229 default:
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
230 arg_max = rb_Integer(arg_max);
231 if (TYPE(arg_max) == T_BIGNUM) goto bignum;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
232 case T_FIXNUM:
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
233 max = FIX2LONG(arg_max);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
234 break;
235 }
236
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
237 return random_number_with_limit(max);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
238 }
239
240 void
241 Init_Random(void)
242 {
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
243 init_random();
cbe906e introduce rb_objc_define_module_function() which mimics the ruby spec
Laurent Sansonetti authored
244 rb_objc_define_module_function(rb_mKernel, "srand", rb_f_srand, -1);
245 rb_objc_define_module_function(rb_mKernel, "rand", rb_f_rand, -1);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
246 }
Something went wrong with that request. Please try again.