2010-01-25 2 views
4

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

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

+12

Можете ли вы опубликовать часть кода, который вы используете? – fbrereto

+4

Не rand() дает вам число от 0 до 1, поэтому вам нужно умножить его перед применением модуля? – slugster

+0

@slugster - rand() последовательно дает мне число выше 10000000. –

ответ

7

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

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

int main() 
{ 
    std::srand(time(0)); 
    std::cout<<(std::rand() % 1000)<<std::endl; 
    return 0; 
} 
+0

Проблема решена! Я не использовал #include , когда я засеял генератор случайных чисел! Большое спасибо! –

+7

@ Zachary: Вероятно, вы хотите включить предупреждения в свой компилятор. Это то, что вы можете заставить компилятор поймать. –

8

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

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

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

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

Например, в this manpage link, он говорит :

В Numerical Recipes в C: Искусство научных вычислений (William H. Press, Brian P. Flannery, Saul А. Teukolsky, Уильям T Веттерлинг, Нью-Йорк: Cambridge University Press, 1992 (2-е изд ., стр. 277)), сделаны следующие замечания:

«Если вы хотите, чтобы сгенерировать случайное число от 1 до 10, вы всегда должны сделать это с помощью битов высокого порядка, как и в

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

Это было бы не очень хорошо PNRG, если бы он всегда возвращал кратность N :-) – paxdiablo

+4

Пожалуйста, не слепо рекомендовать старшие биты. Это полностью зависит от используемого PRNG. Numericical Recipes - прекрасная книга, но особенно старые версии полны опасных советов. Это один из таких случаев. Кроме того, даже те реалии C/C++, которые используют LCG * do *, выбрасывают младшие биты. Люди узнали с 70-х годов. – Joey

+1

@paxdiablo, если * N * равно 1, тогда у меня не было бы проблем с этим ;-) – Joey

4

Похоже, что ваша непосредственная проблема была решена, но я думаю, что стоит упомянуть еще один момент. Использование остатка для фиксации выходов от rand до заданного диапазона обычно приводит к смещению результатов. Конкретно, если диапазон генератора (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; 
} 

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

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

+0

Java 'java.util.Random.nextInt (int)' также имеет очень интересную реализацию непредвзятого выбора случайного числа между 0 и * n *. Что касается битов высокого порядка ... см. Мой комментарий к ответу асвекау. Я действительно не видел libc в то время, когда раздавали реальные младшие биты слова состояния. И есть генераторы, которые имеют слабые старшие биты. C не гарантирует вам LCG для 'rand()'. – Joey

+0

@Johannes: C не гарантирует ничего о rand() - на самом деле, когда-то у него был действительно слабый генератор в качестве примера, и формулировка, которая, по-видимому, убедила хотя бы нескольких исполнителей, что лучший генератор не был " t разрешено. Тем не менее, младшие биты, которые хуже бит более высокого порядка, являются достаточно распространенными, что сохранение бит более высокого порядка является хорошим правилом. В то время как некоторые реализации rand() выкидывают несколько младших бит, 1) часто бывает недостаточно, а 2) некоторые из них до сих пор этого не делают. –

+0

И несколько генераторов имеют слабые старшие разряды. Где результаты будут хуже, чем вы начали. Лучшим советом для C, вероятно, будет избежать встроенного RNG полностью, поскольку он не указан нигде, и вы можете получить что угодно от WELL до RANDU. Тем не менее, многие люди ничего не понимают в отношении случайных чисел, и обобщения типа «Никогда не делай этого» вредны в этих случаях. В общем, вмешательство с генераторами без подсказки только усугубляет ситуацию, а не лучше. – Joey