Class: Random

Inherits:
Object show all
Defined in:
random.c,
random.c

Overview

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.

Constant Summary collapse

DEFAULT =

Direct access to Ruby’s Pseudorandom number generator (PRNG).

rand_default

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#new(seed = Random.new_seed) ⇒ Object

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.



411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
# File 'random.c', line 411

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;
}

Class Method Details

.new_seedInteger

Returns an arbitrary seed value. This is used by Random.new when no seed value is specified as an argument.

Random.new_seed  #=> 115032730400174366788466674494640623225

Returns:



520
521
522
523
524
525
526
# File 'random.c', line 520

static VALUE
random_seed(void)
{
    uint32_t buf[DEFAULT_SEED_CNT];
    fill_random_seed(buf);
    return make_seed_value(buf);
}

.randFloat .rand(max) ⇒ Numeric

Alias of Random::DEFAULT.rand.

Overloads:



1225
1226
1227
1228
1229
# File 'random.c', line 1225

static VALUE
random_s_rand(int argc, VALUE *argv, VALUE obj)
{
    return rand_random(argc, argv, rand_start(&default_rand));
}

.srand(number = Random.new_seed) ⇒ Object

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]


679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
# File 'random.c', line 679

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;
}

Instance Method Details

#==(prng2) ⇒ Boolean

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

Returns:

  • (Boolean)


1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
# File 'random.c', line 1152

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;
}

#bytes(size) ⇒ String

Returns a random binary string containing size bytes.

random_string = Random.new.bytes(10) # => "\xD7:R\xAB?\x83\xCE\xFAkO"
random_string.size                   # => 10

Returns:



870
871
872
873
874
# File 'random.c', line 870

static VALUE
random_bytes(VALUE obj, VALUE len)
{
    return rb_random_bytes(obj, NUM2LONG(rb_to_int(len)));
}

#initialize_copyObject

:nodoc:



549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
# File 'random.c', line 549

static VALUE
random_copy(VALUE obj, VALUE orig)
{
    rb_random_t *rnd1, *rnd2;
    struct MT *mt;

    if (!OBJ_INIT_COPY(obj, orig)) return obj;

    rnd1 = get_rnd(obj);
    rnd2 = get_rnd(orig);
    mt = &rnd1->mt;

    *rnd1 = *rnd2;
    mt->next = mt->state + numberof(mt->state) - mt->left + 1;
    return obj;
}

#leftObject (private)

:nodoc:



590
591
592
593
594
595
# File 'random.c', line 590

static VALUE
random_left(VALUE obj)
{
    rb_random_t *rnd = get_rnd(obj);
    return INT2FIX(rnd->mt.left);
}

#marshal_dumpObject (private)

:nodoc:



605
606
607
608
609
610
611
612
613
614
615
616
# File 'random.c', line 605

static VALUE
random_dump(VALUE obj)
{
    rb_random_t *rnd = get_rnd(obj);
    VALUE dump = rb_ary_new2(3);

    rb_ary_push(dump, mt_state(&rnd->mt));
    rb_ary_push(dump, INT2FIX(rnd->mt.left));
    rb_ary_push(dump, rnd->seed);

    return dump;
}

#marshal_loadObject (private)

:nodoc:



619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
# File 'random.c', line 619

static VALUE
random_load(VALUE obj, VALUE dump)
{
    rb_random_t *rnd = get_rnd(obj);
    struct MT *mt = &rnd->mt;
    VALUE state, left = INT2FIX(1), seed = INT2FIX(0);
    const VALUE *ary;
    unsigned long x;

    rb_check_copyable(obj, dump);
    Check_Type(dump, T_ARRAY);
    ary = RARRAY_CONST_PTR(dump);
    switch (RARRAY_LEN(dump)) {
      case 3:
	seed = ary[2];
      case 2:
	left = ary[1];
      case 1:
	state = ary[0];
	break;
      default:
	rb_raise(rb_eArgError, "wrong dump data");
    }
    rb_integer_pack(state, mt->state, numberof(mt->state),
        sizeof(*mt->state), 0,
        INTEGER_PACK_LSWORD_FIRST|INTEGER_PACK_NATIVE_BYTE_ORDER);
    x = NUM2ULONG(left);
    if (x > numberof(mt->state)) {
	rb_raise(rb_eArgError, "wrong value");
    }
    mt->left = (unsigned int)x;
    mt->next = mt->state + numberof(mt->state) - x + 1;
    rnd->seed = rb_to_int(seed);

    return obj;
}

#randFloat #rand(max) ⇒ Numeric

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.

Overloads:



1081
1082
1083
1084
1085
# File 'random.c', line 1081

static VALUE
random_rand(int argc, VALUE *argv, VALUE obj)
{
    return rand_random(argc, argv, get_rnd(obj));
}

#seedInteger

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

Returns:



542
543
544
545
546
# File 'random.c', line 542

static VALUE
random_get_seed(VALUE obj)
{
    return get_rnd(obj)->seed;
}

#stateObject (private)

:nodoc:



575
576
577
578
579
580
# File 'random.c', line 575

static VALUE
random_state(VALUE obj)
{
    rb_random_t *rnd = get_rnd(obj);
    return mt_state(&rnd->mt);
}