Почему (rand ()% что-нибудь) всегда 0 в C ++? - PullRequest
3 голосов
/ 25 января 2010

У меня проблемы с тем, чтобы заставить rand () работать на C ++. rand () обычно дает мне очень большое число. Когда я пытаюсь использовать оператор по модулю (%), чтобы задать диапазон, он всегда возвращает 0, несмотря ни на что.

Также не помогает заполнение генератора случайных чисел в начале программы.

Ответы [ 3 ]

8 голосов
/ 25 января 2010

Я думаю, что это обычное явление, если алгоритм случайного генератора оставляет определенный набор битов равным нулю. (Например, если младшие биты равны нулю, число mod некоторая младшая константа всегда будет равно нулю.)

Может быть, вы должны попробовать что-то вроде:

const int desired_maximum = /* ... */;

int r = (((double)rand()) / RAND_MAX) * desired_maximum;

Например, в этой ссылке на страницу руководства написано:

В «Числовых рецептах на языке С: Искусство научных вычислений» (Уильям Х. Пресс, Брайан П. Фланнери, Сол А. Теукольский, Уильям Т. Веттерлинг; Нью-Йорк: издательство Кембриджского университета, 1992 (2-е изд., С. 277)), сделаны следующие комментарии:

"Если вы хотите сгенерировать случайное целое число от 1 до 10, вы всегда должны делать это, используя старшие биты, как в

j = 1 + (int) (10.0 * (rand() / (RAND_MAX + 1.0)));
и никогда ничем не напоминающим
j = 1 + (rand() % 10);
(который использует младшие биты). "
7 голосов
/ 25 января 2010

Следующий код прекрасно работает (при каждом запуске генерируется случайное число от 0 до 1000, исключаемое):

#include <cstdlib>
#include <ctime>
#include <iostream>

int main()
{
    std::srand(time(0));
    std::cout<<(std::rand() % 1000)<<std::endl;
    return 0;
}
4 голосов
/ 25 января 2010

Похоже, что ваша непосредственная проблема решена, но я думаю, что все же стоит упомянуть еще один момент. Использование остатка для фиксации выходов из ранда в указанный диапазон обычно вызывает смещение результатов. В частности, если диапазон генератора (RAND_MAX в случае C или C ++) не кратен диапазону, к которому вы привязываетесь, некоторые выходы будут происходить чаще, чем другие. Для сравнения рассмотрим попытку равномерно разделить 11 конфет между 3 детьми (не разбивая их на части). Единственный способ, которым вы можете это сделать, - НЕ раздавать некоторые конфеты. Аналогично, для генератора случайных чисел единственный способ получить равномерное распределение в выходных данных - не использовать некоторые входные данные.

int rand_lim(int limit) {
/* return a random number between 0 and limit inclusive.
 */
    int divisor = RAND_MAX/(limit+1);
    int retval;

    do { 
        retval = rand() / divisor;
    } while (retval > limit);

    return retval;
}

Как указал Асвейкау в своем посте, вы обычно хотите использовать верхние биты типичного линейного конгруэнтного генератора. Младшие биты обычно более предсказуемы. Деление вместо взятия остатка позволяет сохранить верхние биты. Хотя в нем есть цикл while, он часто выполняется только один раз и редко более двух раз, поэтому его влияние на производительность довольно минимально.

Стоит ли это делать, зависит от того, как вы используете числа, которые вы генерируете, - если вы хотите, чтобы в игру, в которую ваши дети играли пару раз, играли в кости или играли, остаток обычно не повредит вещь. Если вы пытаетесь выполнить какую-то симуляцию Монте-Карло (например), вы, вероятно, хотите быть немного более осторожным, хотя ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...