mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* 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
This commit is contained in:
parent
03697bc1f3
commit
2aeb3b47ee
3 changed files with 129 additions and 76 deletions
11
ChangeLog
11
ChangeLog
|
@ -1,3 +1,14 @@
|
|||
Mon Apr 25 07:18:00 2011 Kenta Murata <mrkn@mrkn.jp>
|
||||
|
||||
* 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
|
||||
|
||||
Mon Apr 25 03:31:06 2011 Tadayoshi Funaba <tadf@dotrb.org>
|
||||
|
||||
* lib/time.rb: require 'date'.
|
||||
|
|
176
random.c
176
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);
|
||||
|
|
|
@ -347,19 +347,33 @@ END
|
|||
end
|
||||
|
||||
def test_random_range
|
||||
srand(0)
|
||||
r = Random.new(0)
|
||||
%w(9 5 8).each {|w| assert_equal(w.to_i, r.rand(5..9)) }
|
||||
%w(-237 731 383).each {|w| assert_equal(w.to_i, r.rand(-1000..1000)) }
|
||||
%w(9 5 8).each {|w|
|
||||
assert_equal(w.to_i, rand(5..9))
|
||||
assert_equal(w.to_i, r.rand(5..9))
|
||||
}
|
||||
%w(-237 731 383).each {|w|
|
||||
assert_equal(w.to_i, rand(-1000..1000))
|
||||
assert_equal(w.to_i, r.rand(-1000..1000))
|
||||
}
|
||||
%w(1267650600228229401496703205382
|
||||
1267650600228229401496703205384
|
||||
1267650600228229401496703205383).each do |w|
|
||||
assert_equal(w.to_i, rand(2**100+5..2**100+9))
|
||||
assert_equal(w.to_i, r.rand(2**100+5..2**100+9))
|
||||
end
|
||||
|
||||
v = rand(3.1..4)
|
||||
assert_instance_of(Float, v, '[ruby-core:24679]')
|
||||
assert_include(3.1..4, v)
|
||||
|
||||
v = r.rand(3.1..4)
|
||||
assert_instance_of(Float, v, '[ruby-core:24679]')
|
||||
assert_include(3.1..4, v)
|
||||
|
||||
now = Time.now
|
||||
assert_equal(now, rand(now..now))
|
||||
assert_equal(now, r.rand(now..now))
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue