Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 265 lines (235 sloc) 6.902 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
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
36 /*
37 * #rand(0) needs to generate a float x, such as 0.0 <= x <= 1.0. However,
38 * srandom() returns a long. We want to convert that long by dividing it until
39 * it is <= 1.0 using its 10th power.
40 * For performance reasons, long_to_float_divider() returns the 10th power of
41 * the number, without calculating the number length and using pow().
42 */
43 static inline unsigned long
44 long_to_float_divider(long val)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
45 {
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
46 unsigned long divider = 1;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
47
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
48 while (divider <= val) {
49 divider *= 10;
50 }
51 return divider;
52 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
53
54 static VALUE
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
55 random_number_with_limit(long limit)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
56 {
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
57 long val;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
58
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
59 if (limit == 0) {
60 #if __LP64__
61 val = random();
62 #else
63 val = random() % (ULONG_MAX / 10);
64 #endif /* !__LP64__ */
65 return DOUBLE2NUM((double)val / long_to_float_divider(val));
9c1d230 committing experimental branch content
Laurent Sansonetti authored
66 }
67 else {
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
68 if (limit < 0) {
69 /* -LONG_MIN = LONG_MIN, let's avoid that */
70 if (limit == LONG_MIN) {
71 limit += 1;
72 }
73 limit = -limit;
74 }
75 val = random() % limit;
76 return LONG2NUM(val);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
77 }
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
78 return Qnil;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
79 }
80
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
81 unsigned long rb_genrand_int32(void);
82
9c1d230 committing experimental branch content
Laurent Sansonetti authored
83 static VALUE
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
84 random_number_with_bignum_limit(struct RBignum *bignum_limit)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
85 {
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
86 long nb_long_in_bignum;
87 long nb_loops;
88 struct RBignum *div_result;
89 struct RBignum *result;
90 int idx;
91
92 div_result = RBIGNUM(rb_big_div((VALUE)bignum_limit, LONG2NUM(LONG_MAX)));
93 // FIXME: Shouldn't use !, what value should I check?
94 if (!FIXNUM_P((VALUE)div_result)) {
95 rb_raise(rb_eArgError, "max is too huge");
9c1d230 committing experimental branch content
Laurent Sansonetti authored
96 }
97
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
98 nb_long_in_bignum = FIX2LONG((VALUE)div_result);
99 nb_loops = 1 + FIX2LONG(random_number_with_limit(nb_long_in_bignum));
100 result = RBIGNUM(rb_int2big(0));
101 for (idx = 0; idx < nb_loops; idx++) {
102 // This creates a bignum on each iteration... Not really good :-/
103 result = RBIGNUM(rb_big_plus((VALUE)result, random_number_with_limit(LONG_MAX)));
104 }
105 return ((VALUE)result);
106 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
107
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
108 unsigned long
109 rb_genrand_int32(void)
110 {
111 unsigned long result;
112 short nb_loops;
113 int idx;
114
115 result = 0;
116 nb_loops = 1 + (random() % 2);
117 for (idx = 0; idx < nb_loops; idx++) {
118 result += random();
119 }
120 return result;
121 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
122
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
123 double
124 rb_genrand_real(void)
125 {
126 return NUM2DBL(random_number_with_limit(0));
9c1d230 committing experimental branch content
Laurent Sansonetti authored
127 }
128
129 /*
130 * call-seq:
131 * srand(number=0) => old_seed
132 *
133 * Seeds the pseudorandom number generator to the value of
134 * <i>number</i>.<code>to_i.abs</code>. If <i>number</i> is omitted
135 * or zero, seeds the generator using a combination of the time, the
136 * process id, and a sequence number. (This is also the behavior if
137 * <code>Kernel::rand</code> is called without previously calling
138 * <code>srand</code>, but without the sequence.) By setting the seed
139 * to a known value, scripts can be made deterministic during testing.
140 * The previous seed value is returned. Also see <code>Kernel::rand</code>.
141 */
142
143 static VALUE
349dd2b ported the random.c apis to the new runtime
Laurent Sansonetti authored
144 rb_f_srand(VALUE obj, SEL sel, int argc, VALUE *argv)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
145 {
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
146 VALUE old_seed;
147 VALUE seed_param;
148 VALUE seed_int;
149 unsigned seed = 0;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
150
151 if (argc == 0) {
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
152 srandomdev();
153 seed = (unsigned)random();
154 seed_int = UINT2NUM(seed);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
155 }
156 else {
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
157 rb_scan_args(argc, argv, "01", &seed_param);
158 seed_int = rb_to_int(seed_param);
159 switch (TYPE(seed_int)) {
160 case T_BIGNUM:
161 // In case we need to keep 'seed.to_i.abs'
162 /*
163 if (RBIGNUM_NEGATIVE_P(seed_int)) {
164 seed_int = rb_big_uminus(seed_int);
165 }
166 */
167 for (int i = 0; i < RBIGNUM_LEN(seed_int); i++) {
168 seed += (unsigned int)RBIGNUM_DIGITS(seed_int)[i];
169 }
170 break ;
171 case T_FIXNUM:
172 // In case we need to keep 'seed.to_i.abs'
173 /*
174 if (FIX2LONG(seed_int) < 0) {
175 seed_int = rb_fix_uminus(seed_int);
176 }
177 */
178 seed = (unsigned int)FIX2LONG(seed_int);
179 break ;
180 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
181 }
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
182 srandom(seed);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
183
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
184 old_seed = rb_vm_rand_seed();
185 // Ruby's behaviour is weird. It stores the 'seed.to_i' value, instead of
186 // the 'seed.to_i.abs' value, or just 'seed'. Which one should we use?
187 rb_vm_set_rand_seed(seed_int);
188 return old_seed;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
189 }
190
191 /*
192 * call-seq:
193 * rand(max=0) => number
194 *
195 * Converts <i>max</i> to an integer using max1 =
196 * max<code>.to_i.abs</code>. If the result is zero, returns a
197 * pseudorandom floating point number greater than or equal to 0.0 and
198 * less than 1.0. Otherwise, returns a pseudorandom integer greater
199 * than or equal to zero and less than max1. <code>Kernel::srand</code>
200 * may be used to ensure repeatable sequences of random numbers between
201 * different runs of the program. Ruby currently uses a modified
202 * Mersenne Twister with a period of 2**19937-1.
203 *
204 * srand 1234 #=> 0
205 * [ rand, rand ] #=> [0.191519450163469, 0.49766366626136]
206 * [ rand(10), rand(1000) ] #=> [6, 817]
207 * srand 1234 #=> 1234
208 * [ rand, rand ] #=> [0.191519450163469, 0.49766366626136]
209 */
210
211 static VALUE
349dd2b ported the random.c apis to the new runtime
Laurent Sansonetti authored
212 rb_f_rand(VALUE obj, SEL sel, int argc, VALUE *argv)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
213 {
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
214 VALUE arg_max;
215 long max;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
216
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
217 rb_scan_args(argc, argv, "01", &arg_max);
218 switch (TYPE(arg_max)) {
9c1d230 committing experimental branch content
Laurent Sansonetti authored
219 case T_FLOAT:
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
220 if (RFLOAT_VALUE(arg_max) <= LONG_MAX && RFLOAT_VALUE(arg_max) >= LONG_MIN) {
221 max = (long)RFLOAT_VALUE(arg_max);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
222 break;
223 }
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
224 if (RFLOAT_VALUE(arg_max) < 0)
225 arg_max = rb_dbl2big(-RFLOAT_VALUE(arg_max));
9c1d230 committing experimental branch content
Laurent Sansonetti authored
226 else
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
227 arg_max = rb_dbl2big(RFLOAT_VALUE(arg_max));
9c1d230 committing experimental branch content
Laurent Sansonetti authored
228 /* fall through */
229 case T_BIGNUM:
230 bignum:
231 {
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
232 struct RBignum *limit = (struct RBignum *)arg_max;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
233 if (!RBIGNUM_SIGN(limit)) {
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
234 limit = (struct RBignum *)rb_big_clone(arg_max);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
235 RBIGNUM_SET_SIGN(limit, 1);
236 }
237 limit = (struct RBignum *)rb_big_minus((VALUE)limit, INT2FIX(1));
238 if (FIXNUM_P((VALUE)limit)) {
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
239 max = FIX2LONG((VALUE)limit) + 1;
240 break;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
241 }
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
242 return random_number_with_bignum_limit(limit);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
243 }
244 case T_NIL:
245 max = 0;
246 break;
247 default:
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
248 arg_max = rb_Integer(arg_max);
249 if (TYPE(arg_max) == T_BIGNUM) goto bignum;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
250 case T_FIXNUM:
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
251 max = FIX2LONG(arg_max);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
252 break;
253 }
254
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
255 return random_number_with_limit(max);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
256 }
257
258 void
259 Init_Random(void)
260 {
8f9d863 re-implemented #rand and #srand to use random(3) and srandom(3), fast…
Laurent Sansonetti authored
261 init_random();
cbe906e introduce rb_objc_define_module_function() which mimics the ruby spec
Laurent Sansonetti authored
262 rb_objc_define_module_function(rb_mKernel, "srand", rb_f_srand, -1);
263 rb_objc_define_module_function(rb_mKernel, "rand", rb_f_rand, -1);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
264 }
Something went wrong with that request. Please try again.