Random
provides an interface to Ruby’s pseudo-random number generator, or PRNG. The PRNG produces a deterministic sequence of bits which approximate true randomness. The sequence may be represented by integers, floats, or binary strings.
The generator may be initialized with either a system-generated or user-supplied seed value by using Random.srand
.
The class method Random.rand
provides the base functionality of Kernel.rand
along with better handling of floating point values. These are both interfaces to Random::DEFAULT
, the Ruby system PRNG.
Random.new
will create a new PRNG with a state independent of Random::DEFAULT
, allowing multiple generators with different seed values or sequence positions to exist simultaneously. Random
objects can be marshaled, allowing sequences to be saved and resumed.
PRNGs are currently implemented as a modified Mersenne Twister with a period of 2**19937-1.
static VALUE
random_init(int argc, VALUE *argv, VALUE obj)
{
VALUE vseed;
rb_random_t *rnd = get_rnd(obj);
if (argc == 0) {
rb_check_frozen(obj);
vseed = random_seed();
}
else {
rb_scan_args(argc, argv, "01", &vseed);
rb_check_copyable(obj, vseed);
}
rnd->seed = rand_init(&rnd->mt, vseed);
return obj;
}
Creates a new PRNG using seed
to set the initial state. If seed
is omitted, the generator is initialized with Random.new_seed
.
See Random.srand
for more information on the use of seed values.
static VALUE
random_seed(void)
{
uint32_t buf[DEFAULT_SEED_CNT];
fill_random_seed(buf);
return make_seed_value(buf);
}
Returns an arbitrary seed value. This is used by Random.new
when no seed value is specified as an argument.
Random.new_seed #=> 115032730400174366788466674494640623225
static VALUE
random_s_rand(int argc, VALUE *argv, VALUE obj)
{
VALUE v = rand_random(argc, argv, Qnil, rand_start(&default_rand));
check_random_number(v, argv);
return v;
}
Alias of Random::DEFAULT.rand.
static VALUE
random_raw_seed(VALUE self, VALUE size)
{
long n = NUM2ULONG(size);
VALUE buf = rb_str_new(0, n);
if (n == 0) return buf;
if (fill_random_bytes(RSTRING_PTR(buf), n, FALSE)) return Qnil;
return buf;
}
Returns a raw seed string, using platform providing features.
Random.raw_seed(8) #=> "\x78\x41\xBA\xAF\x7D\xEA\xD8\xEA"
static VALUE
rb_f_srand(int argc, VALUE *argv, VALUE obj)
{
VALUE seed, old;
rb_random_t *r = &default_rand;
if (argc == 0) {
seed = random_seed();
}
else {
rb_scan_args(argc, argv, "01", &seed);
}
old = r->seed;
r->seed = rand_init(&r->mt, seed);
return old;
}
Seeds the system pseudo-random number generator, Random::DEFAULT
, with number
. The previous seed value is returned.
If number
is omitted, seeds the generator using a source of entropy provided by the operating system, if available (/dev/urandom on Unix systems or the RSA cryptographic provider on Windows), which is then combined with the time, the process id, and a sequence number.
srand may be used to ensure repeatable sequences of pseudo-random numbers between different runs of the program. By setting the seed to a known value, programs can be made deterministic during testing.
srand 1234 # => 268519324636777531569100071560086917274 [ rand, rand ] # => [0.1915194503788923, 0.6221087710398319] [ rand(10), rand(1000) ] # => [4, 664] srand 1234 # => 1234 [ rand, rand ] # => [0.1915194503788923, 0.6221087710398319]
static VALUE
random_equal(VALUE self, VALUE other)
{
rb_random_t *r1, *r2;
if (rb_obj_class(self) != rb_obj_class(other)) return Qfalse;
r1 = get_rnd(self);
r2 = get_rnd(other);
if (!RTEST(rb_funcall2(r1->seed, rb_intern("=="), 1, &r2->seed))) return Qfalse;
if (memcmp(r1->mt.state, r2->mt.state, sizeof(r1->mt.state))) return Qfalse;
if ((r1->mt.next - r1->mt.state) != (r2->mt.next - r2->mt.state)) return Qfalse;
if (r1->mt.left != r2->mt.left) return Qfalse;
return Qtrue;
}
Returns true if the two generators have the same internal state, otherwise false. Equivalent generators will return the same sequence of pseudo-random numbers. Two generators will generally have the same state only if they were initialized with the same seed
Random.new == Random.new # => false Random.new(1234) == Random.new(1234) # => true
and have the same invocation history.
prng1 = Random.new(1234) prng2 = Random.new(1234) prng1 == prng2 # => true prng1.rand # => 0.1915194503788923 prng1 == prng2 # => false prng2.rand # => 0.1915194503788923 prng1 == prng2 # => true
static VALUE
random_bytes(VALUE obj, VALUE len)
{
return genrand_bytes(get_rnd(obj), NUM2LONG(rb_to_int(len)));
}
Returns a random binary string containing size
bytes.
random_string = Random.new.bytes(10) # => "\xD7:R\xAB?\x83\xCE\xFAkO" random_string.size # => 10
static VALUE
random_rand(int argc, VALUE *argv, VALUE obj)
{
VALUE v = rand_random(argc, argv, obj, get_rnd(obj));
check_random_number(v, argv);
return v;
}
When max
is an Integer
, rand
returns a random integer greater than or equal to zero and less than max
. Unlike Kernel.rand
, when max
is a negative integer or zero, rand
raises an ArgumentError
.
prng = Random.new prng.rand(100) # => 42
When max
is a Float
, rand
returns a random floating point number between 0.0 and max
, including 0.0 and excluding max
.
prng.rand(1.5) # => 1.4600282860034115
When max
is a Range
, rand
returns a random number where range.member?(number) == true.
prng.rand(5..9) # => one of [5, 6, 7, 8, 9] prng.rand(5...9) # => one of [5, 6, 7, 8] prng.rand(5.0..9.0) # => between 5.0 and 9.0, including 9.0 prng.rand(5.0...9.0) # => between 5.0 and 9.0, excluding 9.0
Both the beginning and ending values of the range must respond to subtract (-
) and add (+
)methods, or rand will raise an ArgumentError
.
static VALUE
random_get_seed(VALUE obj)
{
return get_rnd(obj)->seed;
}
Returns the seed value used to initialize the generator. This may be used to initialize another generator with the same state at a later time, causing it to produce the same sequence of numbers.
prng1 = Random.new(1234) prng1.seed #=> 1234 prng1.rand(100) #=> 47 prng2 = Random.new(prng1.seed) prng2.rand(100) #=> 47