Как уменьшить число из rand ()? - PullRequest
34 голосов
/ 16 ноября 2010

Следующий код выводит случайное число каждую секунду:

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 ]

76 голосов
/ 16 ноября 2010

Если вы используете 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;
30 голосов
/ 16 ноября 2010

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

Лучший способ для генерации реального равномерного распределения случайных чисел в любом диапазоне [0, N ] заключается в следующем (при условии, что rand фактически следует равномерному распределению, которое далеко не очевидно):

unsigned result;
do {
    result = rand();
} while (result > N);

Конечно, этот метод медленный, но дает хорошее распределение. Немного более разумный способ сделать это - найти наибольшее значение, кратное N , которое меньше RAND_MAX, и использовать его в качестве верхней границы. После этого можно смело брать result % (N + 1).

Для объяснения почему метод наивного модуля плох и почему вышеупомянутое лучше, обратитесь к превосходной статье Жюльена по , используя rand.

26 голосов
/ 16 ноября 2010

int rawRand = rand() % 101;

См. (Для более подробной информации):

rand - C ++ Reference

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

int rawRand = (rand() * 1.0 / RAND_MAX) * 100;

РЕДАКТИРОВАТЬ

Три годаЯ делаю правку.Как уже упоминалось, у rand() много проблем.Очевидно, я не могу рекомендовать его использование, когда есть лучшие альтернативы в будущем.Вы можете прочитать все подробности и рекомендации здесь:

rand () Считается вредным |GoingNative 2013

4 голосов
/ 16 ноября 2010

Вы можете сделать

cout << rawRand % 100 << endl; // Outputs between 0 and 99

cout << rawRand % 101 << endl; // outputs between 0 and 100

Для людей, понижающих голосование;обратите внимание, что через минуту после того, как это было первоначально опубликовано, я оставил комментарий:

From http://www.cplusplus.com/reference/clibrary/cstdlib/rand "Обратите внимание, что эта операция по модулю не генерирует действительно равномерно распределенное случайное число в промежутке (так какв большинстве случаев более низкие значения немного более вероятны), но это, как правило, хорошее приближение для коротких отрезков ».

С 64-битными целыми числами и с использованием 100 чисел в качестве выходных данных числа 0-16 представлены с 1.00000000000000000455% чисел (относительная точность к одинаково распределенному 1% примерно на 10 -18 ), в то время как цифры 17-99 представлены 0,999999999999999999913% от числа.Да, не идеально распределено, но очень хорошее приближение для небольших промежутков.

Также обратите внимание, где ОП запрашивает идентично распределенные числа?Мы знаем, что они используются в целях, где небольшие отклонения не имеют значения (например, что-либо кроме криптографии - и если они используют числа для криптографии, этот вопрос слишком наивен, чтобы они могли писать свою собственную криптографию).).

РЕДАКТИРОВАТЬ - Для людей, которые действительно заинтересованы в равномерном распределении случайных чисел, работает следующий код.Обратите внимание, что это не обязательно оптимально, так как для 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;
4 голосов
/ 16 ноября 2010

См. man 3 rand - вам нужно масштабировать, разделив на RAND_MAX, чтобы получить диапазон [0, 1], после которого вы можете умножить на 100 для целевого диапазона.

0 голосов
/ 16 ноября 2010

Некоторые люди опубликовали следующий код в качестве примера:

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.

0 голосов
/ 16 ноября 2010

Как долго вы хотели бы получить ответ?

самое простое - преобразовать остаток от деления на 101:

int value = rawRand % 101;

Полупурист мог бы изменить масштаб, используя двойные числа:

double dbl = 100 * ((double)rawRand / RAND_MAX);
int ivalue = (int)(dbl + 0.5);   // round up for above 0.5

А пурист сказал бы, что ранд не производит случайных чисел.

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

0 голосов
/ 16 ноября 2010

Для диапазона от мин до макс (включительно) используйте: int result = rand() % (max - min + 1) + min;

0 голосов
/ 16 ноября 2010

rawRand% 101 даст [0-100] включительно.

...