2 ** random.c - Random module
4 ** See Copyright Notice in mruby.h
8 #include <mruby/variable.h>
9 #include <mruby/class.h>
10 #include <mruby/data.h>
11 #include <mruby/array.h>
12 #include <mruby/istruct.h>
13 #if INT32_MAX <= INTPTR_MAX
19 #define LASTSEED (NSEEDS-1)
23 typedef struct rand_state {
24 uint32_t seed[NSEEDS];
28 rand_init(rand_state *t)
30 t->seed[0] = 123456789;
31 t->seed[1] = 362436069;
32 t->seed[2] = 521288629;
34 t->seed[3] = 88675123;
39 rand_seed(rand_state *t, uint32_t seed)
41 uint32_t old_seed = t->seed[LASTSEED];
43 t->seed[LASTSEED] = seed;
49 rand_uint32(rand_state *state)
51 uint32_t *seed = state->seed;
57 t = (x ^ (x << 3)) ^ (y ^ (y >> 19)) ^ (z ^ (z << 6));
65 #else /* XORSHIFT96 */
67 rand_uint32(rand_state *state)
69 uint32_t *seed = state->seed;
78 w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
86 #endif /* XORSHIFT96 */
88 #ifndef MRB_WITHOUT_FLOAT
90 rand_real(rand_state *t)
92 uint32_t x = rand_uint32(t);
93 return x*(1.0/4294967295.0);
98 random_rand(mrb_state *mrb, rand_state *t, mrb_value max)
102 if (mrb_fixnum(max) == 0) {
103 #ifndef MRB_WITHOUT_FLOAT
104 value = mrb_float_value(mrb, rand_real(t));
106 mrb_raise(mrb, E_ARGUMENT_ERROR, "Float not supported");
110 value = mrb_fixnum_value(rand_uint32(t) % mrb_fixnum(max));
117 get_opt(mrb_state* mrb)
121 arg = mrb_nil_value();
122 mrb_get_args(mrb, "|o", &arg);
124 if (!mrb_nil_p(arg)) {
127 arg = mrb_to_int(mrb, arg);
130 arg = mrb_fixnum_value(0 - i);
137 random_check(mrb_state *mrb, mrb_value random) {
138 struct RClass *c = mrb_class_get(mrb, "Random");
139 if (!mrb_obj_is_kind_of(mrb, random, c) || !mrb_istruct_p(random)) {
140 mrb_raise(mrb, E_TYPE_ERROR, "Random instance required");
145 random_default(mrb_state *mrb) {
146 struct RClass *c = mrb_class_get(mrb, "Random");
147 mrb_value d = mrb_const_get(mrb, mrb_obj_value(c), mrb_intern_lit(mrb, "DEFAULT"));
148 if (!mrb_obj_is_kind_of(mrb, d, c)) {
149 mrb_raise(mrb, E_TYPE_ERROR, "Random::DEFAULT replaced");
154 #define random_ptr(v) (rand_state*)mrb_istruct_ptr(v)
155 #define random_default_state(mrb) random_ptr(random_default(mrb))
158 random_m_init(mrb_state *mrb, mrb_value self)
164 /* avoid memory leaks */
165 t = random_ptr(self);
166 if (mrb_nil_p(seed)) {
170 rand_seed(t, (uint32_t)mrb_fixnum(seed));
177 random_m_rand(mrb_state *mrb, mrb_value self)
180 rand_state *t = random_ptr(self);
183 return random_rand(mrb, t, max);
187 random_m_srand(mrb_state *mrb, mrb_value self)
192 rand_state *t = random_ptr(self);
196 seed = (uint32_t)time(NULL) + rand_uint32(t);
199 seed = (uint32_t)mrb_fixnum(sv);
201 old_seed = rand_seed(t, seed);
203 return mrb_fixnum_value((mrb_int)old_seed);
208 * ary.shuffle! -> ary
210 * Shuffles elements in self in place.
214 mrb_ary_shuffle_bang(mrb_state *mrb, mrb_value ary)
218 mrb_value r = mrb_nil_value();
221 if (RARRAY_LEN(ary) > 1) {
222 mrb_get_args(mrb, "|o", &r);
225 random = random_default_state(mrb);
228 random_check(mrb, r);
229 random = random_ptr(r);
231 mrb_ary_modify(mrb, mrb_ary_ptr(ary));
232 max = mrb_fixnum_value(RARRAY_LEN(ary));
233 for (i = RARRAY_LEN(ary) - 1; i > 0; i--) {
235 mrb_value *ptr = RARRAY_PTR(ary);
238 j = mrb_fixnum(random_rand(mrb, random, max));
251 * ary.shuffle -> new_ary
253 * Returns a new array with elements of self shuffled.
257 mrb_ary_shuffle(mrb_state *mrb, mrb_value ary)
259 mrb_value new_ary = mrb_ary_new_from_values(mrb, RARRAY_LEN(ary), RARRAY_PTR(ary));
260 mrb_ary_shuffle_bang(mrb, new_ary);
268 * ary.sample(n) -> new_ary
270 * Choose a random element or +n+ random elements from the array.
272 * The elements are chosen by using random and unique indices into the array
273 * in order to ensure that an element doesn't repeat itself unless the array
274 * already contained duplicate elements.
276 * If the array is empty the first form returns +nil+ and the second form
277 * returns an empty array.
281 mrb_ary_sample(mrb_state *mrb, mrb_value ary)
285 mrb_value r = mrb_nil_value();
289 mrb_get_args(mrb, "|i?o", &n, &given, &r);
291 random = random_default_state(mrb);
294 random_check(mrb, r);
295 random = random_ptr(r);
297 len = RARRAY_LEN(ary);
298 if (!given) { /* pick one element */
301 return mrb_nil_value();
303 return RARRAY_PTR(ary)[0];
305 return RARRAY_PTR(ary)[rand_uint32(random) % len];
312 if (n < 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "negative sample number");
313 if (n > len) n = len;
314 result = mrb_ary_new_capa(mrb, n);
315 for (i=0; i<n; i++) {
320 r = (mrb_int)(rand_uint32(random) % len);
322 for (j=0; j<i; j++) {
323 if (mrb_fixnum(RARRAY_PTR(result)[j]) == r) {
324 goto retry; /* retry if duplicate */
329 mrb_ary_push(mrb, result, mrb_fixnum_value(r));
331 for (i=0; i<n; i++) {
332 mrb_ary_set(mrb, result, i, RARRAY_PTR(ary)[mrb_fixnum(RARRAY_PTR(result)[i])]);
339 random_f_rand(mrb_state *mrb, mrb_value self)
341 rand_state *t = random_default_state(mrb);
342 return random_rand(mrb, t, get_opt(mrb));
346 random_f_srand(mrb_state *mrb, mrb_value self)
348 mrb_value random = random_default(mrb);
349 return random_m_srand(mrb, random);
353 void mrb_mruby_random_gem_init(mrb_state *mrb)
355 struct RClass *random;
356 struct RClass *array = mrb->array_class;
358 mrb_assert(sizeof(rand_state) <= ISTRUCT_DATA_SIZE);
360 mrb_define_method(mrb, mrb->kernel_module, "rand", random_f_rand, MRB_ARGS_OPT(1));
361 mrb_define_method(mrb, mrb->kernel_module, "srand", random_f_srand, MRB_ARGS_OPT(1));
363 random = mrb_define_class(mrb, "Random", mrb->object_class);
364 MRB_SET_INSTANCE_TT(random, MRB_TT_ISTRUCT);
365 mrb_define_class_method(mrb, random, "rand", random_f_rand, MRB_ARGS_OPT(1));
366 mrb_define_class_method(mrb, random, "srand", random_f_srand, MRB_ARGS_OPT(1));
368 mrb_define_method(mrb, random, "initialize", random_m_init, MRB_ARGS_OPT(1));
369 mrb_define_method(mrb, random, "rand", random_m_rand, MRB_ARGS_OPT(1));
370 mrb_define_method(mrb, random, "srand", random_m_srand, MRB_ARGS_OPT(1));
372 mrb_define_method(mrb, array, "shuffle", mrb_ary_shuffle, MRB_ARGS_OPT(1));
373 mrb_define_method(mrb, array, "shuffle!", mrb_ary_shuffle_bang, MRB_ARGS_OPT(1));
374 mrb_define_method(mrb, array, "sample", mrb_ary_sample, MRB_ARGS_OPT(2));
376 mrb_const_set(mrb, mrb_obj_value(random), mrb_intern_lit(mrb, "DEFAULT"),
377 mrb_obj_new(mrb, random, 0, NULL));
380 void mrb_mruby_random_gem_final(mrb_state *mrb)