Class: Random

Inherits:
Object show all
Includes:
Formatter
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.

Defined Under Namespace

Modules: Formatter

Constant Summary collapse

DEFAULT =
rand_default

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Formatter

#random_number

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.


429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
# File 'random.c', line 429

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

617
618
619
620
621
622
623
# File 'random.c', line 617

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.


1425
1426
1427
1428
1429
1430
1431
# File 'random.c', line 1425

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

.raw_seed(size) ⇒ String

Returns a raw seed string, using platform providing features.

Random.raw_seed(8)  #=> "\x78\x41\xBA\xAF\x7D\xEA\xD8\xEA"

632
633
634
635
636
637
638
639
640
# File 'random.c', line 632

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

.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]

793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
# File 'random.c', line 793

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

1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
# File 'random.c', line 1352

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

1027
1028
1029
1030
1031
# File 'random.c', line 1027

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

#initialize_copy(orig) ⇒ Object

:nodoc:


663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
# File 'random.c', line 663

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:


704
705
706
707
708
709
# File 'random.c', line 704

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

#marshal_dumpObject (private)

:nodoc:


719
720
721
722
723
724
725
726
727
728
729
730
# File 'random.c', line 719

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_load(dump) ⇒ Object (private)

:nodoc:


733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
# File 'random.c', line 733

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.


1265
1266
1267
1268
1269
1270
1271
# File 'random.c', line 1265

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

#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

656
657
658
659
660
# File 'random.c', line 656

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

#stateObject (private)

:nodoc:


689
690
691
692
693
694
# File 'random.c', line 689

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