class Random
Random 提供了 Ruby 伪随机数生成器 (PRNG) 的接口。PRNG 生成确定性比特序列,用于近似真实随机性。该序列可以用整数、浮点数或二进制字符串表示。
可以使用 Random.srand 使用系统生成或用户提供的种子值来初始化生成器。
类方法 Random.rand 提供了 Kernel.rand 的基本功能,并能更好地处理浮点数值。这两者都是 Ruby 系统 PRNG 的接口。
Random.new 将创建一个新的 PRNG,其状态独立于 Ruby 系统 PRNG,允许多个具有不同种子值或序列位置的生成器同时存在。 Random 对象可以被 marshaled,从而允许保存和恢复序列。
PRNG 目前实现为修改版的梅森旋转算法,周期为 2**19937-1。由于该算法不适用于加密用途,出于安全目的,您必须使用 SecureRandom,而不是此 PRNG。
另见 Random::Formatter 模块,该模块添加了生成各种形式随机数据的便捷方法。
Public Class Methods
Source
static VALUE
random_s_bytes(VALUE obj, VALUE len)
{
rb_random_t *rnd = default_rand_start();
return rand_bytes(&random_mt_if, rnd, NUM2LONG(rb_to_int(len)));
}
返回一个随机二进制字符串。参数 size 指定返回字符串的长度。
Source
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) {
RB_OBJ_WRITE(obj, &rnd->seed, rand_init_default(rng, rnd));
}
else {
RB_OBJ_WRITE(obj, &rnd->seed, rand_init(rng, rnd, rb_to_int(argv[0])));
}
return obj;
}
创建一个新的 PRNG,使用 seed 设置初始状态。如果省略 seed,则使用 Random.new_seed 初始化生成器。
有关种子值用法的更多信息,请参阅 Random.srand。
Source
static VALUE
random_seed(VALUE _)
{
VALUE v;
with_random_seed(DEFAULT_SEED_CNT, 1, true) {
v = make_seed_value(seedbuf, DEFAULT_SEED_CNT);
}
return v;
}
返回一个任意的种子值。当 Random.new 作为参数未指定种子值时,它会使用此值进行初始化。
Random.new_seed #=> 115032730400174366788466674494640623225
Source
static VALUE
random_s_rand(int argc, VALUE *argv, VALUE obj)
{
VALUE v = rand_random(argc, argv, Qnil, default_rand_start());
check_random_number(v, argv);
return v;
}
使用 Ruby 系统 PRNG 返回一个随机数。
另见 Random#rand。
Source
static VALUE
random_s_seed(VALUE obj)
{
rb_random_mt_t *rnd = default_mt();
return rnd->base.seed;
}
返回用于初始化 Ruby 系统 PRNG 的种子值。这可以用于稍后用相同状态初始化另一个生成器,使其产生相同的数字序列。
Random.seed #=> 1234 prng1 = Random.new(Random.seed) prng1.seed #=> 1234 prng1.rand(100) #=> 47 Random.seed #=> 1234 Random.rand(100) #=> 47
Source
static VALUE
rb_f_srand(int argc, VALUE *argv, VALUE obj)
{
VALUE seed, old;
rb_random_mt_t *r = default_mt();
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;
}
使用 number 为系统伪随机数生成器设置种子。返回前一个种子值。
如果省略 number,则使用操作系统提供的熵源(如果可用,Unix 系统上为 /dev/urandom,Windows 上为 RSA 加密提供程序)为生成器设置种子,然后与时间、进程 ID 和序列号结合。
srand 可用于确保程序不同运行之间可重复的伪随机数序列。通过将种子设置为已知值,可以在测试期间使程序确定性。
srand 1234 # => 268519324636777531569100071560086917274 [ rand, rand ] # => [0.1915194503788923, 0.6221087710398319] [ rand(10), rand(1000) ] # => [4, 664] srand 1234 # => 1234 [ rand, rand ] # => [0.1915194503788923, 0.6221087710398319]
Source
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;
}
返回一个字符串,使用平台提供的功能。返回的值应为二进制形式的加密安全伪随机数。如果平台提供的功能未能准备好结果,此方法将引发 RuntimeError。
2017 年,Linux manpage random(7) 曾写道:“当今没有任何加密原语可以承诺超过 256 位的安全性”。因此,将 size > 32 传递给此方法可能值得商榷。
Random.urandom(8) #=> "\x78\x41\xBA\xAF\x7D\xEA\xD8\xEA"
Public Instance Methods
Source
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);
}
如果两个生成器具有相同的内部状态,则返回 true,否则返回 false。等效的生成器将返回相同的伪随机数序列。两个生成器通常只有在用相同的种子初始化
Random.new == Random.new # => false Random.new(1234) == Random.new(1234) # => true
并具有相同的调用历史记录时才具有相同的状态。
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
Source
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)));
}
返回一个包含 size 字节的随机二进制字符串。
random_string = Random.new.bytes(10) # => "\xD7:R\xAB?\x83\xCE\xFAkO" random_string.size # => 10
Source
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;
}
当 max 是 Integer 时,rand 返回一个大于等于零且小于 max 的随机整数。与 Kernel.rand 不同,当 max 是负整数或零时,rand 会引发 ArgumentError。
prng = Random.new prng.rand(100) # => 42
当 max 是 Float 时,rand 返回一个介于 0.0(包含)和 max(不包含)之间的随机浮点数。请注意,其行为与 Kernel.rand 不同。
prng.rand(1.5) # => 1.4600282860034115 rand(1.5) # => 0
当 range 是 Range 时,rand 返回一个随机数,其中 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
范围的开始值和结束值都必须响应减法 (-) 和加法 (+) 方法,否则 rand 会引发 ArgumentError。
Source
static VALUE
random_get_seed(VALUE obj)
{
return get_rnd(obj)->seed;
}
返回用于初始化生成器的种子值。这可以用于稍后用相同状态初始化另一个生成器,使其产生相同的数字序列。
prng1 = Random.new(1234) prng1.seed #=> 1234 prng1.rand(100) #=> 47 prng2 = Random.new(prng1.seed) prng2.rand(100) #=> 47