summaryrefslogtreecommitdiff
path: root/random.c
diff options
context:
space:
mode:
authormrkn <mrkn@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2011-04-24 22:27:39 +0000
committermrkn <mrkn@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2011-04-24 22:27:39 +0000
commit2aeb3b47ee47443fa5531bfce856aa1df269a740 (patch)
tree298e51d5e62572f849b62444d706f22728a9abbc /random.c
parent03697bc1f3112b7a57ab016c98cd745f5af6b0e9 (diff)
* 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
Diffstat (limited to 'random.c')
-rw-r--r--random.c176
1 files changed, 102 insertions, 74 deletions
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);