Использование 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);
}