класс Random
Random предоставляет интерфейс к псевдослучайному генератору чисел Руби, или PRNG. PRNG генерирует детерминированную последовательность битов, которые приближают истинную случайность. Последовательность может быть представлена целыми числами, числами с плавающей запятой или двоичными строками.
Генератор может быть инициализирован либо системным, либо заданным пользователем значением семени, используя Random.srand.
Метод класса Random.rand предоставляет базовые функциональные возможности Kernel.rand вместе с лучшим обращением с числами с плавающей запятой. Оба метода являются интерфейсами к системному PRNG Руби.
Random.new создаст новый PRNG с состоянием, независимым от системного PRNG Руби, позволяя одновременно существовать нескольким генераторам с различными значениями семян или позициями в последовательности. Объекты Random могут быть сериализованы, позволяя сохранять и возобновлять последовательности.
PRNG в настоящее время реализованы как модифицированный генератор Мерсенна-Твистера с периодом 2**19937-1. Поскольку этот алгоритм не предназначен для криптографического использования, для целей безопасности вы должны использовать SecureRandom, а не этот PRNG.
Константы
- DEFAULT
Публичные методы класса
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)));
} Возвращает случайную двоичную строку. Аргумент size задает длину возвращаемой строки.
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);
}
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;
} Создаёт новый PRNG, используя seed для установки начального состояния. Если seed опущено, генератор инициализируется с помощью Random.new_seed.
См. Random.srand для получения дополнительной информации об использовании значений семян.
static VALUE
random_seed(VALUE _)
{
VALUE v;
with_random_seed(DEFAULT_SEED_CNT, 1) {
v = make_seed_value(seedbuf, DEFAULT_SEED_CNT);
}
return v;
} Возвращает произвольное значение семени. Оно используется методом Random.new, когда значение семени не указано в качестве аргумента.
Random.new_seed #=> 115032730400174366788466674494640623225
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;
} static VALUE
random_s_seed(VALUE obj)
{
rb_random_mt_t *rnd = rand_mt_start(default_rand());
return rnd->base.seed;
} 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;
} Инициализирует системный псевдослучайный генератор чисел, используя number. Возвращает предыдущее значение семени.
Если number опущено, генератор инициализируется, используя источник энтропии, предоставляемый операционной системой (если доступен — /dev/urandom на системах Unix или криптографический модуль RSA на Windows), который затем комбинируется с временем, идентификатором процесса и порядковым номером.
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
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 году в man-странице Linux random(7) было сказано, что «ни один криптографический примитив, доступный сегодня, не может гарантировать более чем 256 бит безопасности». Поэтому может быть сомнительно передавать размер > 32 в этот метод.
Random.urandom(8) #=> "\x78\x41\xBA\xAF\x7D\xEA\xD8\xEA"
Публичные методы экземпляров
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
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
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, включая 0.0 и исключая max.
prng.rand(1.5) # => 1.4600282860034115
Когда max является 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.
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
Ruby Core © 1993–2020 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.