Использование qsrand, случайный метод, который не является случайным

У меня здесь странная проблема, и я не могу найти для этого хорошего объяснения, поэтому я подумал спросить вас, ребята:

Рассмотрим следующий метод:

int MathUtility::randomize(int Min, int Max)
{
    qsrand(QTime::currentTime().msec());

    if (Min > Max)
    {
        int Temp = Min;
        Min = Max;
        Max = Temp;
    }
    return ((rand()%(Max-Min+1))+Min);
}

Я не буду объяснять вам, гуру, что этот метод на самом деле делает, я объясню свою проблему:

Я понял, что когда я вызываю этот метод в цикле, иногда, я получаю одно и то же случайное число снова и снова... Например, этот фрагмент...

for(int i=0; i<10; ++i)
{
    int Index = MathUtility::randomize(0, 1000);
    qDebug() << Index;
}

... создаст что-то вроде:

567 567 567 567... и т.д....

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

Мой вопрос: Почему?

Ответы

Ответ 1

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

Генераторы случайных чисел предназначены только для посева. Выселение их несколько раз не делает вывод лишним случайным, и на самом деле (как вы нашли) может сделать его гораздо менее случайным.

Ответ 2

Если вы сделаете вызов достаточно быстрым, значение QTime::currentTime().msec() не изменится, и вы в основном повторно сеяете qsrand с тем же семенем, в результате чего следующий случайный номер будет сгенерирован таким же, как предыдущий.

Ответ 3

Если вы вызываете функцию qsrand Qt для инициализации семпла, вы должны вызвать функцию qrand Qt для генерации случайного числа, а не функции rand из стандартной библиотеки. инициализация семени для функции rand является srand. Извините за выкапывание.

Ответ 4

То, что вы видите, - это эффект псевдослучайности. Вы засеваете его одним раз, и он генерирует последовательность чисел. Так как вы быстро перемещаете ряд случайных чисел друг за другом, вы повторно выбираете рандомизатор с тем же номером до следующей миллисекунды. И хотя миллисекунда кажется короткой, подумайте о количестве вычислений, которые вы делаете в это время.

Ответ 5

Две проблемы:

1 Как указывали другие, генератор является семенем несколько раз.

2 Это не очень хороший способ генерации случайных чисел в заданном диапазоне. (На самом деле это очень плохо для большинства генераторов)

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

Используя остаток после делений, вы фактически выбрасываете случайность.

Вы должны масштабировать, используя умножение и деление. Не использовать оператор modulo. например,

my_number = start_required + (generator_output * range_required)/generator_maximum;

если generator_output находится в [0, generator_maximum] my_number будет в [start_required, start_required + range_required]

Ответ 6

Я нашел то же действие и решил его, используя rand() вместо srand().

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

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

Ответ 7

современный Qt c++ 11

#include <random>
#include "QDateTime"

int getRand(int min, int max){
    unsigned int ms = static_cast<unsigned>(QDateTime::currentMSecsSinceEpoch());
    std::mt19937 gen(ms);
    std::uniform_int_distribution<> uid(min, max);    
    return uid(gen);
}