Как масштабировать числа из rand ()?
следующий код выводит случайное число каждую секунду:
int main ()
{
srand(time(NULL)); // Seeds number generator with execution time.
while (true)
{
int rawRand = rand();
std::cout << rawRand << std::endl;
sleep(1);
}
}
Как я могу уменьшить эти числа, чтобы они всегда находились в диапазоне 0-100?
9 ответов
Если вы используете C++ и обеспокоены хорошим распределением, вы можете использовать TR1 C++11 <random>
.
#include <random>
std::random_device rseed;
std::mt19937 rgen(rseed()); // mersenne_twister
std::uniform_int_distribution<int> idist(0,100); // [0,100]
std::cout << idist(rgen) << std::endl;
все примеры, опубликованные до сих пор, фактически дают плохо распределенные результаты. Часто выполняйте код и создавайте статистику, чтобы увидеть, как значения искажаются.
лучший способ генерировать реальный униформа распределение случайных чисел в любом диапазоне [0, N] является следующим (предполагая, что rand
фактически следует равномерному распределению, что далеко не очевидно):
unsigned result;
do {
result = rand();
} while (result > N);
конечно, этот метод медленный, но это тут произвести хорошее распределение. Немного умнее способ сделать это, чтобы найти наибольшее кратное N меньше RAND_MAX
и используя его в качестве верхней границы. После этого, можно смело брать result % (N + 1)
.
объяснение почему наивный метод модуля плох и почему выше лучше,обратитесь к превосходной статье Жюльен на используя rand
.
int rawRand = rand() % 101;
см. (для более подробной информации):
Рэнд - Справочник по языку C++
другие также указали, что это не даст вам наилучшее распределение случайных чисел. Если это важно в вашем коде, вам нужно будет сделать:
int rawRand = (rand() * 1.0 / RAND_MAX) * 100;
редактировать
три года спустя, я делаю правки. Как упоминали другие,rand()
имеет большой дело в вопросах. Очевидно, я не могу рекомендовать его использование, когда есть лучшие альтернативы. Вы можете прочитать все подробности и рекомендации здесь:
посмотреть man 3 rand
-- вам нужно масштабировать, деля на RAND_MAX
получить диапазон [0, 1] после чего вы можете умножать на 100 для вашего целевого диапазона.
можно сделать
cout << rawRand % 100 << endl; // Outputs between 0 and 99
cout << rawRand % 101 << endl; // outputs between 0 and 100
для людей downvoting; Примечание через минуту после того, как это было первоначально опубликовано, я оставил комментарий:
от http://www.cplusplus.com/reference/clibrary/cstdlib/rand "обратите внимание, что эта операция по модулю не генерирует действительно равномерно распределенное случайное число в промежутке (так как в большинстве случаев более низкие числа немного более вероятны), но это, как правило, хорошее приближение для коротких промежутков."
С 64-битными ints и с использованием 100 чисел в качестве выходных данных, числа 0-16 представлены с 1.00000000000000000455 % чисел (относительная точность к одинаково распределенным 1% около 10-18), в то время как числа 17-99 представлены с 0.99999999999999999913% чисел. Да, не идеально распределены, но очень хорошее приближение для небольших пролетов.
Также обратите внимание, где OP запрашивает одинаково распределенные числа? Насколько нам известно, они используются для целей, где небольшие отклонения не имеют значения (например, ничего, кроме криптографии, и если они используют числа для криптографии, этот вопрос слишком наивен для них, чтобы писать свою собственную криптографию).
редактировать - для людей, которые действительно заинтересованы в равномерном распределении случайных чисел, работает следующий код. Обратите внимание, что это не обязательно оптимально, как с 64-битными случайными входами, это будет требуется два вызова rand()
раз в 10^18 звонков.
unsigned N = 100; // want numbers 0-99
unsigned long randTruncation = (RAND_MAX / N) * N;
// include every number the N times by ensuring rawRand is between 0 and randTruncation - 1 or regenerate.
unsigned long rawRand = rand();
while (rawRand >= randTruncation) {
rawRand = rand();
// with 64-bit int and range of 0-99 will need to generate two random numbers
// about 1 in every (2^63)/16 ~ 10^18 times (1 million million times)
// with 32-bit int and range of 0-99 will need to generate two random numbers
// once every 46 million times.
}
cout << rawRand % N << stdl::endl;
для диапазона от min до max (включительно) используйте: int result = rand() % (max - min + 1) + min;
Как долго ответ вы хотели.
простейшим является преобразование с использованием остатка при делении на 101:
int value = rawRand % 101;
полупурист будет масштабировать с помощью двойников:
double dbl = 100 * ((double)rawRand / RAND_MAX);
int ivalue = (int)(dbl + 0.5); // round up for above 0.5
и пурист сказал бы, что Рэнд не производит случайных чисел.
для вашей информации качество случайных чисел измеряется путем взятия последовательности чисел, а затем вычисления математической вероятности того, что источник этой последовательности был случайным. Этот простой хак с использованием остатка-очень плохой выбор, если вы после случайности.
некоторые люди опубликовали следующий код в качестве примера:
int rawRand = (rand() / RAND_MAX) * 100;
это недопустимый способ решения проблемы, так как rand() и RAND_MAX являются целыми числами. В C++ это приводит к интегральному делению, которое будет усекать десятичные точки результатов. Как RAND_MAX >= rand (), результатом этой операции является либо 1, либо 0, то есть rawRand может быть только 0 или 100. Правильный способ сделать это будет следующим:
int rawRand = (rand() / static_cast<double>(RAND_MAX)) * 100;
поскольку один из операндов теперь является используется двойное деление с плавающей запятой, которое возвращает правильное значение от 0 до 1.