class Random

Random 提供了一个 Ruby 伪随机数生成器 (PRNG) 的接口。PRNG 生成一个确定性的比特序列,该序列近似于真正的随机性。该序列可以用整数、浮点数或二进制字符串表示。

可以通过使用 Random.srand,使用系统生成的或用户提供的种子值来初始化生成器。

类方法 Random.rand 提供了 Kernel.rand 的基本功能,并更好地处理浮点数值。它们都是 Ruby 系统 PRNG 的接口。

Random.new 将创建一个新的 PRNG,其状态独立于 Ruby 系统 PRNG,允许同时存在具有不同种子值或序列位置的多个生成器。Random 对象可以被序列化,允许保存和恢复序列。

PRNG 目前被实现为修改后的梅森旋转算法,其周期为 2**19937-1。由于该算法适用于密码学用途,因此出于安全目的,您必须使用 SecureRandom,而不是此 PRNG。

另请参阅 Random::Formatter 模块,该模块添加了方便的方法来生成各种形式的随机数据。

公共类方法

bytes(size) → string 点击以切换源代码

返回一个随机二进制字符串。参数 size 指定返回字符串的长度。

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 = Random.new_seed) → prng 点击以切换源代码

创建一个新的 PRNG,使用 seed 设置初始状态。如果省略 seed,则使用 Random.new_seed 初始化生成器。

有关种子值的使用,请参阅 Random.srand

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;
}
new_seed → integer 点击以切换源代码

返回任意种子值。当没有指定种子值作为参数时,Random.new 使用此值。

Random.new_seed  #=> 115032730400174366788466674494640623225
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;
}
rand → float 点击以切换源代码
rand(max) → number
rand(range) → number

使用 Ruby 系统 PRNG 返回一个随机数。

另请参阅 Random#rand

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 点击以切换源代码

返回用于初始化 Ruby 系统 PRNG 的种子值。这可以用于稍后使用相同的状态初始化另一个生成器,使其生成相同的数字序列。

Random.seed      #=> 1234
prng1 = Random.new(Random.seed)
prng1.seed       #=> 1234
prng1.rand(100)  #=> 47
Random.seed      #=> 1234
Random.rand(100) #=> 47
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) → old_seed 点击以切换源代码

使用 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]
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 点击以切换源代码

使用平台提供的功能返回字符串。返回值预期为二进制形式的密码安全伪随机数。如果平台提供的功能未能准备结果,则此方法会引发 RuntimeError

2017 年,Linux 手册页 random(7) 中写道,“今天没有可用的加密原语可以期望保证超过 256 位的安全性”。因此,将 size > 32 传递给此方法可能会有问题。

Random.urandom(8)  #=> "\x78\x41\xBA\xAF\x7D\xEA\xD8\xEA"
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;
}

公共实例方法

prng1 == prng2 → true or false 点击以切换源代码

如果两个生成器具有相同的内部状态,则返回 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
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 点击以切换源代码

返回一个包含 size 字节的随机二进制字符串。

random_string = Random.new.bytes(10) # => "\xD7:R\xAB?\x83\xCE\xFAkO"
random_string.size                   # => 10
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)));
}
rand → float 点击以切换源代码
rand(max) → number
rand(range) → number

max 是一个 Integer 时,rand 返回一个大于或等于零且小于 max 的随机整数。与 Kernel.rand 不同,当 max 是负整数或零时,rand 会引发 ArgumentError

prng = Random.new
prng.rand(100)       # => 42

max 是一个 Float 时,rand 返回一个介于 0.0 和 max 之间的随机浮点数,包括 0.0 但不包括 max

prng.rand(1.5)       # => 1.4600282860034115

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

范围的开始值和结束值都必须响应 subtract (-) 和 add (+) 方法,否则 rand 会引发 ArgumentError

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 点击以切换源代码

返回用于初始化生成器的种子值。这可以用于稍后使用相同的状态初始化另一个生成器,使其生成相同的数字序列。

prng1 = Random.new(1234)
prng1.seed       #=> 1234
prng1.rand(100)  #=> 47

prng2 = Random.new(prng1.seed)
prng2.rand(100)  #=> 47
static VALUE
random_get_seed(VALUE obj)
{
    return get_rnd(obj)->seed;
}