From 2aeb3b47ee47443fa5531bfce856aa1df269a740 Mon Sep 17 00:00:00 2001 From: mrkn Date: Sun, 24 Apr 2011 22:27:39 +0000 Subject: * random.c (random_s_rand, Init_Random): Random.rand should behave as Random::DEFAULT.rand rather than Kernel#rand. * random.c (rand_range, random_rand): rand_range function extracted from random_rand function. * random.c (rb_f_rand): accept a Range argument as Random#rand [ruby-dev:43427] #4605 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@31340 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- random.c | 176 ++++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 102 insertions(+), 74 deletions(-) (limited to 'random.c') diff --git a/random.c b/random.c index 15a7f51a06..a5fedaaa0f 100644 --- a/random.c +++ b/random.c @@ -324,6 +324,7 @@ int_pair_to_real_inclusive(unsigned int a, unsigned int b) } VALUE rb_cRandom; +static VALUE rb_Random_DEFAULT; #define id_minus '-' #define id_plus '+' static ID id_rand, id_bytes; @@ -1025,6 +1026,88 @@ float_value(VALUE v) return x; } +static inline VALUE +rand_range(struct MT* mt, VALUE range) +{ + VALUE beg = Qundef, end = Qundef, vmax, v; + int excl = 0; + + if ((v = vmax = range_values(range, &beg, &end, &excl)) == Qfalse) + return Qfalse; + if (TYPE(vmax) != T_FLOAT && (v = rb_check_to_integer(vmax, "to_int"), !NIL_P(v))) { + long max; + vmax = v; + v = Qnil; + if (FIXNUM_P(vmax)) { + fixnum: + if ((max = FIX2LONG(vmax) - excl) >= 0) { + unsigned long r = limited_rand(mt, (unsigned long)max); + v = ULONG2NUM(r); + } + } + else if (BUILTIN_TYPE(vmax) == T_BIGNUM && RBIGNUM_SIGN(vmax) && !rb_bigzero_p(vmax)) { + vmax = excl ? rb_big_minus(vmax, INT2FIX(1)) : rb_big_norm(vmax); + if (FIXNUM_P(vmax)) { + excl = 0; + goto fixnum; + } + v = limited_big_rand(mt, RBIGNUM(vmax)); + } + } + else if (v = rb_check_to_float(vmax), !NIL_P(v)) { + int scale = 1; + double max = RFLOAT_VALUE(v), mid = 0.5, r; + if (isinf(max)) { + double min = float_value(rb_to_float(beg)) / 2.0; + max = float_value(rb_to_float(end)) / 2.0; + scale = 2; + mid = max + min; + max -= min; + } + else { + float_value(v); + } + v = Qnil; + if (max > 0.0) { + if (excl) { + r = genrand_real(mt); + } + else { + r = genrand_real2(mt); + } + if (scale > 1) { + return rb_float_new(+(+(+(r - 0.5) * max) * scale) + mid); + } + v = rb_float_new(r * max); + } + else if (max == 0.0 && !excl) { + v = rb_float_new(0.0); + } + } + + if (FIXNUM_P(beg) && FIXNUM_P(v)) { + long x = FIX2LONG(beg) + FIX2LONG(v); + return LONG2NUM(x); + } + switch (TYPE(v)) { + case T_NIL: + break; + case T_BIGNUM: + return rb_big_plus(v, beg); + case T_FLOAT: { + VALUE f = rb_check_to_float(beg); + if (!NIL_P(f)) { + RFLOAT_VALUE(v) += RFLOAT_VALUE(f); + return v; + } + } + default: + return rb_funcall2(beg, id_plus, 1, &v); + } + + return v; +} + /* * call-seq: * prng.rand -> float @@ -1076,58 +1159,8 @@ random_rand(int argc, VALUE *argv, VALUE obj) else v = Qnil; } - else if ((v = range_values(vmax, &beg, &end, &excl)) != Qfalse) { - vmax = v; - if (TYPE(vmax) != T_FLOAT && (v = rb_check_to_integer(vmax, "to_int"), !NIL_P(v))) { - long max; - vmax = v; - v = Qnil; - if (FIXNUM_P(vmax)) { - fixnum: - if ((max = FIX2LONG(vmax) - excl) >= 0) { - unsigned long r = limited_rand(&rnd->mt, (unsigned long)max); - v = ULONG2NUM(r); - } - } - else if (BUILTIN_TYPE(vmax) == T_BIGNUM && RBIGNUM_SIGN(vmax) && !rb_bigzero_p(vmax)) { - vmax = excl ? rb_big_minus(vmax, INT2FIX(1)) : rb_big_norm(vmax); - if (FIXNUM_P(vmax)) { - excl = 0; - goto fixnum; - } - v = limited_big_rand(&rnd->mt, RBIGNUM(vmax)); - } - } - else if (v = rb_check_to_float(vmax), !NIL_P(v)) { - int scale = 1; - double max = RFLOAT_VALUE(v), mid = 0.5, r; - if (isinf(max)) { - double min = float_value(rb_to_float(beg)) / 2.0; - max = float_value(rb_to_float(end)) / 2.0; - scale = 2; - mid = max + min; - max -= min; - } - else { - float_value(v); - } - v = Qnil; - if (max > 0.0) { - if (excl) { - r = genrand_real(&rnd->mt); - } - else { - r = genrand_real2(&rnd->mt); - } - if (scale > 1) { - return rb_float_new(+(+(+(r - 0.5) * max) * scale) + mid); - } - v = rb_float_new(r * max); - } - else if (max == 0.0 && !excl) { - v = rb_float_new(0.0); - } - } + else if ((v = rand_range(&rnd->mt, vmax)) != Qfalse) { + /* nothing to do */ } else { v = Qnil; @@ -1138,24 +1171,8 @@ random_rand(int argc, VALUE *argv, VALUE obj) rb_str_append(mesg, rb_obj_as_string(argv[0])); rb_exc_raise(rb_exc_new3(rb_eArgError, mesg)); } - if (beg == Qundef) return v; - if (FIXNUM_P(beg) && FIXNUM_P(v)) { - long x = FIX2LONG(beg) + FIX2LONG(v); - return LONG2NUM(x); - } - switch (TYPE(v)) { - case T_BIGNUM: - return rb_big_plus(v, beg); - case T_FLOAT: { - VALUE f = rb_check_to_float(beg); - if (!NIL_P(f)) { - RFLOAT_VALUE(v) += RFLOAT_VALUE(f); - return v; - } - } - default: - return rb_funcall2(beg, id_plus, 1, &v); - } + + return v; } /* @@ -1201,12 +1218,15 @@ random_equal(VALUE self, VALUE other) static VALUE rb_f_rand(int argc, VALUE *argv, VALUE obj) { - VALUE vmax, r; + VALUE v, vmax, r; struct MT *mt = default_mt(); if (argc == 0) goto zero_arg; rb_scan_args(argc, argv, "01", &vmax); if (NIL_P(vmax)) goto zero_arg; + if ((v = rand_range(mt, vmax)) != Qfalse) { + return v; + } vmax = rb_to_int(vmax); if (vmax == INT2FIX(0) || NIL_P(r = rand_int(mt, vmax, 0))) { zero_arg: @@ -1215,6 +1235,12 @@ rb_f_rand(int argc, VALUE *argv, VALUE obj) return r; } +static VALUE +random_s_rand(int argc, VALUE *argv, VALUE obj) +{ + return random_rand(argc, argv, rb_Random_DEFAULT); +} + static st_index_t hashseed; static VALUE @@ -1297,11 +1323,13 @@ Init_Random(void) rb_define_private_method(rb_cRandom, "state", random_state, 0); rb_define_private_method(rb_cRandom, "left", random_left, 0); rb_define_method(rb_cRandom, "==", random_equal, 1); - rb_define_const(rb_cRandom, "DEFAULT", - TypedData_Wrap_Struct(rb_cRandom, &random_data_type, &default_rand)); + + rb_Random_DEFAULT = TypedData_Wrap_Struct(rb_cRandom, &random_data_type, &default_rand); + rb_global_variable(&rb_Random_DEFAULT); + rb_define_const(rb_cRandom, "DEFAULT", rb_Random_DEFAULT); rb_define_singleton_method(rb_cRandom, "srand", rb_f_srand, -1); - rb_define_singleton_method(rb_cRandom, "rand", rb_f_rand, -1); + rb_define_singleton_method(rb_cRandom, "rand", random_s_rand, -1); rb_define_singleton_method(rb_cRandom, "new_seed", random_seed, 0); rb_define_private_method(CLASS_OF(rb_cRandom), "state", random_s_state, 0); rb_define_private_method(CLASS_OF(rb_cRandom), "left", random_s_left, 0); -- cgit v1.2.3