2012-02-27 2 views
22

Каждый раз, когда я запускаю программу с rand(), она дает мне те же результаты.Почему rand() дает одну и ту же последовательность чисел в каждом прогоне?

Пример:

#include <iostream> 
#include <cstdlib> 

using namespace std; 

int random (int low, int high) { 
    if (low > high) return high; 
    return low + (rand() % (high - low + 1)); 
} 
int main (int argc, char* argv []) { 
    for (int i = 0; i < 5; i++) cout << random (2, 5) << endl; 
} 

Выход:

3 
5 
4 
2 
3 

Каждый раз, когда я запустить программу он выводит те же номера каждый раз. Есть ли способ обойти это?

ответ

33

Семена для генератора случайных чисел не установлены.

Если вы звоните srand (время (NULL)), то вы получите более случайные результаты:

#include <iostream> 
#include <cstdlib> 
#include <ctime> 
using namespace std; 

int main() { 
    srand(time(NULL)); 
    cout << rand() << endl; 
    return 0; 
} 

Причина заключается в том, что случайное число из функции рандов() на самом деле не случайно. Это просто трансформация.Википедия дает лучшее объяснение значения генератора псевдослучайных чисел: детерминированный генератор случайных бит. Каждый раз, когда вы вызываете rand(), он берет семя и/или последние случайные числа (с) (стандарт C не указывает используемый алгоритм, хотя C++ 11 имеет возможности для определения некоторых популярных алгоритмов), запускает математическая операция над этими числами и возвращает результат. Поэтому, если состояние семени одинаково каждый раз (так, как если бы вы не вызывали srand с действительно случайным числом), тогда вы всегда будете получать одинаковые «случайные» номера.

Если вы хотите узнать больше, вы можете прочитать следующее:

http://www.dreamincode.net/forums/topic/24225-random-number-generation-102/

http://www.dreamincode.net/forums/topic/29294-making-pseudo-random-number-generators-more-random/

1

Вам необходимо засеять генератор случайных чисел (см. Функцию 'srand'). Предполагая, что вы не выполняете криптографию, то посев его с выходом «времени», вероятно, достаточно хорош.

11

Если вы позвоните по номеру rand() без предварительного звонка srand(), он будет действовать так, как если бы вы позвонили srand(1) неявно. Соответствующий бит стандарта C99 7.20.2.2 The srand function (на котором основан cstdlib) гласит:

Если рэнд вызывается перед вызовом srand были сделаны, та же последовательность должна генерироваться при srand сначала вызывается с семенем значение 1.

другими словами, вы будет получить ту же самую последовательность каждый раз. Вы можете изменить ваш main в:

int main (int argc, char* argv []) { 
    srand (time (0)); // needs ctime header. 
    for (int i = 0; i < 5; i++) 
     cout << random (2, 5) << endl; 
    wait(); 
} 

, чтобы исправить это, если вы не запускать его более чем один раз в секунду.

Как уже упоминалось, для этого вам понадобится заголовок ctime. Вы также должны тянуть cstdlib, так как здесь rand и srand живут. Также обычно рекомендуется использовать заголовки cXXX, а не XXX.h (cmath, а не math.h, например).

Итак, сделав все эти изменения (и с использованием явных пространств имен, которые я предпочитаю, хотя другие не могут), я бы в конечном итоге с:

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

void wait() { 
    int e; 
    std::cin >> e; 
} 

int random (int low, int high) { 
    if (low > high) return high; 
    return low + (std::rand() % (high - low + 1)); 
} 

int main (int argc, char* argv []) { 
    std::srand (std::time (0)); 
    for (int i = 0; i < 5; i++) 
     std::cout << random (2, 5) << '\n'; 
    wait(); 
} 

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

0

Вы на самом деле получаете psuedo случайных чисел. Чтобы сделать их «более случайными», вы можете засеять генератор случайных чисел, используя что-то, что «изменяется» (чаще всего текущее время).

+1

Nit: Математически это не сделает их «более случайными». –

+0

Правда, но в контексте вопроса OP ... (плюс это в кавычках ;-) – John3136

2

Это особенность функции rand().

У вас нет генератора случайных чисел, но более строго "Pseudo Random Number Generator". Возможность воспроизведения одинаковых случайных последовательностей для одного и того же семени (вы используете с помощью функции srand(x)) может быть важна для воспроизведения ошибок или сохранения состояния в программах.

Лично я использую эту функцию, чтобы иметь возможность приостанавливать/останавливать процессы рендеринга в средстве рендеринга ландшафта monte carlo. Хорошим побочным эффектом является то, что вы можете гарантировать различные эксперименты с monte carlo на разных машинах и, следовательно, иметь возможность генерировать гарантированные разные результаты, которые затем могут быть уменьшены на последнем этапе до конечного результата более высокого качества (конечно, вы можете впоследствии использовать его повторно это более качественный конечный результат для получения еще более качественных результатов).

Обратите внимание, что ни C, ни C++ не определяют последовательность чисел из rand(). Поэтому, если вам нужны гарантированные последовательности на разных платформах, используйте один из новых генераторов случайных чисел C++ 11 (например, mersenne twister), сверните свой собственный (некоторые генераторы почти тривиальны для понимания, однако, поскольку большинство из них полагаются на специфическое поведение переполнения своих реализация может быть не тривиальной) или использовать сторонний компонент (например, boost :: random).

1

использовать randomize(). Он автоматически семениет значение. Или, если вы хотите использовать rand(), вы можете засеять его, используя srand (seedvalue); значение семени может быть любым, как системное время .., которое дает вам разные случайные числа каждый раз

+1

'randomize' не является стандартной функцией C++. На какой платформе вы говорите? –

Смежные вопросы