У меня есть функция, которая использует случайность
void fun() {
random_device rd;
mt19937 gen(rd());
uniform_real_distribution<double> dis(0.0, 1.0);
// ...
}
И, как я подозреваю, я получу плохой рандом, если он будет вызываться повторно, и каждый раз будут создаваться и rd
, и gen
. Не лучше ли сделать эти переменные глобальными/приватными полями класса, чтобы они не переопределялись несколько раз?
Вам нужно только сохранить mt19937
, так как вы используете random_device
только один раз во время инициализации.
Создайте генератор один раз в main, передайте ссылку на весь код, который в нем нуждается. (Избегает использования глобальных переменных/внедрения зависимостей). Вы, вероятно, также захотите сделать то же самое для дистрибутива, который также не должен постоянно пересоздаваться. Вы также можете поместить оба в структуру в качестве членов и передать их (как случайный контекст)
@PepijnKramer Не могли бы вы объяснить, чем «передача ссылки на код, который в ней нуждается», отличается от внедрения зависимостей?
@wtz это инъекция зависимостей :) Теперь я вижу, что мой текст немного не тот :/
Вы можете использовать random_device
для создания начального числа для инициализации mt19937
. Поскольку random_device
— затратная операция, ее не нужно вызывать каждый раз при вызове функции, и нет необходимости сохранять random_device
.
mt19937
не является потокобезопасным. Если ваше приложение является однопоточным, вы можете сохранить его как закрытый элемент данных вашего класса. Однако, если ваше приложение работает в многопоточном режиме, вам лучше сделать его локальной переменной потока метода.
void func() {
thread_local mt19937(random_device{}());
}
Генератор случайных чисел должен быть глобальным объектом. Но нет ничего плохого в том, чтобы похоронить его в функции доступа:
template <typename RealType>
RealType random_real_in_range( RealType min = 0., RealType max = 1. )
{
thread_local std::mt19937 rng( std::random_device{}() );
return std::uniform_real_distribution<RealType>( min, max )( rng );
}
Недостаток здесь в том, что МТ действительно нужно «разогреть» звонком .discard( 1000 )
или около того...
Эм, почему бы тебе просто не сделать это?