Class: Random
- Defined in:
- 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 the Ruby system PRNG.
Random.new will create a new PRNG with a state independent of the Ruby system PRNG, 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. As this algorithm is not for cryptographical use, you must use SecureRandom for security purpose, instead of this PRNG.
See also Random::Formatter module that adds convenience methods to generate various forms of random data.
Defined Under Namespace
Modules: Formatter
Class Method Summary collapse
-
.bytes(size) ⇒ String
Returns a random binary string.
-
.new_seed ⇒ Integer
Returns an arbitrary seed value.
-
.rand(*args) ⇒ Object
Returns a random number using the Ruby system PRNG.
-
.seed ⇒ Integer
Returns the seed value used to initialize the Ruby system PRNG.
-
.srand(number = Random.new_seed) ⇒ Object
Seeds the system pseudo-random number generator, with
number
. -
.urandom(size) ⇒ String
Returns a string, using platform providing features.
Instance Method Summary collapse
-
#==(prng2) ⇒ Boolean
Returns true if the two generators have the same internal state, otherwise false.
-
#bytes(size) ⇒ String
Returns a random binary string containing
size
bytes. -
#new(seed = Random.new_seed) ⇒ Object
constructor
Creates a new PRNG using
seed
to set the initial state. -
#initialize_copy(orig) ⇒ Object
:nodoc:.
-
#left ⇒ Object
private
:nodoc:.
-
#marshal_dump ⇒ Object
private
:nodoc:.
-
#marshal_load(dump) ⇒ Object
private
:nodoc:.
-
#rand(*args) ⇒ Object
When
max
is an Integer,rand
returns a random integer greater than or equal to zero and less thanmax
. -
#seed ⇒ Integer
Returns the seed value used to initialize the generator.
-
#state ⇒ Object
private
:nodoc:.
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.
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 |
# File 'random.c', line 402
static VALUE
random_init(int argc, VALUE *argv, VALUE obj)
{
rb_random_t *rnd = try_get_rnd(obj);
const rb_random_interface_t *rng = rb_rand_if(obj);
if (!rng) {
rb_raise(rb_eTypeError, "undefined random interface: %s",
RTYPEDDATA_TYPE(obj)->wrap_struct_name);
}
unsigned int major = rng->version.major;
unsigned int minor = rng->version.minor;
if (major != RUBY_RANDOM_INTERFACE_VERSION_MAJOR) {
rb_raise(rb_eTypeError, "Random interface version "
STRINGIZE(RUBY_RANDOM_INTERFACE_VERSION_MAJOR) "."
STRINGIZE(RUBY_RANDOM_INTERFACE_VERSION_MINOR) " "
"expected: %d.%d", major, minor);
}
argc = rb_check_arity(argc, 0, 1);
rb_check_frozen(obj);
if (argc == 0) {
rnd->seed = rand_init_default(rng, rnd);
}
else {
rnd->seed = rand_init(rng, rnd, rb_to_int(argv[0]));
}
return obj;
}
|
Class Method Details
.bytes(size) ⇒ String
Returns a random binary string. The argument size
specifies the length of the returned string.
1316 1317 1318 1319 1320 1321 |
# File 'random.c', line 1316
static VALUE
random_s_bytes(VALUE obj, VALUE len)
{
rb_random_t *rnd = rand_start(default_rand());
return rand_bytes(&random_mt_if, rnd, NUM2LONG(rb_to_int(len)));
}
|
.new_seed ⇒ Integer
Returns an arbitrary seed value. This is used by Random.new when no seed value is specified as an argument.
Random.new_seed #=> 115032730400174366788466674494640623225
740 741 742 743 744 745 746 747 748 |
# File 'random.c', line 740
static VALUE
random_seed(VALUE _)
{
VALUE v;
with_random_seed(DEFAULT_SEED_CNT, 1) {
v = make_seed_value(seedbuf, DEFAULT_SEED_CNT);
}
return v;
}
|
.rand ⇒ Float .rand(max) ⇒ Numeric .rand(range) ⇒ Numeric
Returns a random number using the Ruby system PRNG.
See also Random#rand.
1695 1696 1697 1698 1699 1700 1701 |
# File 'random.c', line 1695
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;
}
|
.seed ⇒ Integer
Returns the seed value used to initialize the Ruby system PRNG. 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.
Random.seed #=> 1234
prng1 = Random.new(Random.seed)
prng1.seed #=> 1234
prng1.rand(100) #=> 47
Random.seed #=> 1234
Random.rand(100) #=> 47
1338 1339 1340 1341 1342 1343 |
# File 'random.c', line 1338
static VALUE
random_s_seed(VALUE obj)
{
rb_random_mt_t *rnd = rand_mt_start(default_rand());
return rnd->base.seed;
}
|
.srand(number = Random.new_seed) ⇒ Object
Seeds the system pseudo-random number generator, 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]
953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 |
# File 'random.c', line 953
static VALUE
rb_f_srand(int argc, VALUE *argv, VALUE obj)
{
VALUE seed, old;
rb_random_mt_t *r = rand_mt_start(default_rand());
if (rb_check_arity(argc, 0, 1) == 0) {
seed = random_seed(obj);
}
else {
seed = rb_to_int(argv[0]);
}
old = r->base.seed;
rand_init(&random_mt_if, &r->base, seed);
r->base.seed = seed;
return old;
}
|
.urandom(size) ⇒ String
Returns a string, using platform providing features. Returned value is expected to be a cryptographically secure pseudo-random number in binary form. This method raises a RuntimeError if the feature provided by platform failed to prepare the result.
In 2017, Linux manpage random(7) writes that “no cryptographic primitive available today can hope to promise more than 256 bits of security”. So it might be questionable to pass size > 32 to this method.
Random.urandom(8) #=> "\x78\x41\xBA\xAF\x7D\xEA\xD8\xEA"
766 767 768 769 770 771 772 773 774 775 |
# File 'random.c', line 766
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, TRUE))
rb_raise(rb_eRuntimeError, "failed to get urandom");
return buf;
}
|
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
1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 |
# File 'random.c', line 1623
static VALUE
rand_mt_equal(VALUE self, VALUE other)
{
rb_random_mt_t *r1, *r2;
if (rb_obj_class(self) != rb_obj_class(other)) return Qfalse;
r1 = get_rnd_mt(self);
r2 = get_rnd_mt(other);
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 rb_equal(r1->base.seed, r2->base.seed);
}
|
#bytes(size) ⇒ String
1270 1271 1272 1273 1274 1275 |
# File 'random.c', line 1270
static VALUE
random_bytes(VALUE obj, VALUE len)
{
rb_random_t *rnd = try_get_rnd(obj);
return rand_bytes(rb_rand_if(obj), rnd, NUM2LONG(rb_to_int(len)));
}
|
#initialize_copy(orig) ⇒ Object
:nodoc:
798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 |
# File 'random.c', line 798
static VALUE
rand_mt_copy(VALUE obj, VALUE orig)
{
rb_random_mt_t *rnd1, *rnd2;
struct MT *mt;
if (!OBJ_INIT_COPY(obj, orig)) return obj;
rnd1 = get_rnd_mt(obj);
rnd2 = get_rnd_mt(orig);
mt = &rnd1->mt;
*rnd1 = *rnd2;
mt->next = mt->state + numberof(mt->state) - mt->left + 1;
return obj;
}
|
#left ⇒ Object (private)
:nodoc:
839 840 841 842 843 844 |
# File 'random.c', line 839
static VALUE
rand_mt_left(VALUE obj)
{
rb_random_mt_t *rnd = get_rnd_mt(obj);
return INT2FIX(rnd->mt.left);
}
|
#marshal_dump ⇒ Object (private)
:nodoc:
854 855 856 857 858 859 860 861 862 863 864 865 |
# File 'random.c', line 854
static VALUE
rand_mt_dump(VALUE obj)
{
rb_random_mt_t *rnd = rb_check_typeddata(obj, &random_mt_type);
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->base.seed);
return dump;
}
|
#marshal_load(dump) ⇒ Object (private)
:nodoc:
868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 |
# File 'random.c', line 868
static VALUE
rand_mt_load(VALUE obj, VALUE dump)
{
rb_random_mt_t *rnd = rb_check_typeddata(obj, &random_mt_type);
struct MT *mt = &rnd->mt;
VALUE state, left = INT2FIX(1), seed = INT2FIX(0);
unsigned long x;
rb_check_copyable(obj, dump);
Check_Type(dump, T_ARRAY);
switch (RARRAY_LEN(dump)) {
case 3:
seed = RARRAY_AREF(dump, 2);
case 2:
left = RARRAY_AREF(dump, 1);
case 1:
state = RARRAY_AREF(dump, 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->base.seed = rb_to_int(seed);
return obj;
}
|
#rand ⇒ Float #rand(max) ⇒ Numeric #rand(range) ⇒ 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 range
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.
1540 1541 1542 1543 1544 1545 1546 |
# File 'random.c', line 1540
static VALUE
random_rand(int argc, VALUE *argv, VALUE obj)
{
VALUE v = rand_random(argc, argv, obj, try_get_rnd(obj));
check_random_number(v, argv);
return v;
}
|
#seed ⇒ Integer
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
791 792 793 794 795 |
# File 'random.c', line 791
static VALUE
random_get_seed(VALUE obj)
{
return get_rnd(obj)->seed;
}
|
#state ⇒ Object (private)
:nodoc:
824 825 826 827 828 829 |
# File 'random.c', line 824
static VALUE
rand_mt_state(VALUE obj)
{
rb_random_mt_t *rnd = get_rnd_mt(obj);
return mt_state(&rnd->mt);
}
|