C ++ нужен хороший метод для заполнения rand (), который не использует time () - PullRequest
0 голосов
/ 03 июня 2018

У меня есть скрипт bash, который запускает множество клиентских процессов.Это игроки ИИ, которые я использую для тестирования игры со многими игроками, порядка 400 соединений.

Проблема, с которой я столкнулся, заключается в том, что игрок ИИ использует

srand( time(nullptr) );

Но если все игроки начинают примерно в одно и то же время, они часто получают одно и то же значение time (), что будет означать, что все они находятся в одной последовательности rand ().

Часть тестированияпроцесс заключается в том, чтобы убедиться, что если множество клиентов пытаются подключиться примерно в одно и то же время, сервер может справиться с этим.

Я рассмотрел использование чего-то вроде

srand( (int) this );

или подобного, делая ставку наидея, что каждый экземпляр имеет уникальный адрес памяти.

Есть ли другой лучший способ?

Ответы [ 3 ]

0 голосов
/ 03 июня 2018

Использование случайного начального числа для псевдослучайного генератора.

std::random_device - это дорогие случайные данные.(дорого как медленно) Вы используете это, чтобы заполнить алгоритм prng.mt19937 - это последний алгоритм prng, который вам когда-либо понадобится.

При желании вы можете выполнить его, передав его через дистрибутив, если вам это нужно.т.е. если вам нужны значения в определенном диапазоне, отличном от того, что обеспечивает генератор.

std::random_device rd;
std::mt19937 generator(rd());
0 голосов
/ 03 июня 2018

В наши дни rand() и srand() устарели.

Общепринятым методом является создание генератора псевдослучайных чисел из std::random_device.На платформах, которые предоставляют недетерминированные случайные источники, std::random_device требуется использовать их для обеспечения высококачественных случайных чисел.

Однако это может быть медленным или даже блокировать при наборе достаточной энтропии.По этой причине он обычно используется только для получения начального числа.

Высококачественный, но эффективный случайный двигатель - это mersenne twister , предоставляемый стандартной библиотекой:

inline
std::mt19937& random_generator()
{
    thread_local static std::mt19937 mt{std::random_device{}()};
    return mt;
}

template<typename Number>
Number random_number(Number from, Number to)
{
    static_assert(std::is_integral<Number>::value||std::is_floating_point<Number>::value,
        "Parameters must be integer or floating point numbers");

    using Distribution = typename std::conditional
    <
        std::is_integral<Number>::value,
        std::uniform_int_distribution<Number>,
        std::uniform_real_distribution<Number>
    >::type;

    thread_local static Distribution dist;

    return dist(random_generator(), typename Distribution::param_type{from, to});
}
0 голосов
/ 03 июня 2018

Вы используете случайное число семян, если и только , если хотите получить воспроизводимые результаты.Это может быть удобно для таких вещей, как генерация карты, когда вы хотите, чтобы карта была рандомизированной, но вы хотите, чтобы она была предсказуемо случайной на основе начального числа.

В большинстве случаев вы этого не хотите, вы хотите на самом делеслучайные числа, и лучший способ сделать это с помощью функций генератора стандартной библиотеки:

#include <random>

std::random_device rd;
std::map<int, int> hist;
std::uniform_int_distribution<int> dist(0, 5);

int random_die_roll = dist(rd);

В этом случае начальное число не требуется и не рекомендуется.«Случайное устройство» - это правильное заполнение PRNG (генератора псевдослучайных чисел) для обеспечения непредсказуемых результатов.

Опять же, НЕ использует srand(time(NULL)), потому что он очень старый, очень плохойметод для инициализации случайных чисел, и это очень предсказуемо.На современных компьютерах пробиться через миллион возможных начальных чисел, чтобы найти совпадающие выходные данные, тривиально.

...