Внедрение генератора случайных чисел

Возможный дубликат:
Как работает генератор случайных чисел?

Я ищу внутреннюю реализацию генератора случайных чисел в C/С++. В основном мне интересно знать, что именно происходит, когда вызывается rand(). Ведь машина следует определенному набору инструкций, как это может быть случайным!
Изменить: хотите знать, как я могу реализовать его в C/С++.

Ответ 1

Это генераторы псевдослучайных чисел, а не действительно случайные. Это часто хорошо, так как позволяет вам легче воспроизводить ошибки, когда речь идет о "случайных" числах.

Вы можете получить генераторы случайных чисел, такие как чтение /dev/random в Linux, но обычные генераторы, которые поставляются с библиотеками C, обычно не работают.

Самый простой - линейные конгруэнтные генераторы, где:

n(x+1) = n(x) * A + C modulo M

с подходящим образом выбранными значениями A, C и M

На странице Википедии о LCG приведены примеры значений, используемых различными реализациями. Например, перечисленный здесь glibc имеет a = 1103515245, c = 12345, m = 2^31 так что это простая вещь, такая как:

static unsigned int seed = 1;
void srand (int newseed) {
    seed = (unsigned)newseed & 0x7fffffffU;
}
int rand (void) {
    seed = (seed * 1103515245U + 12345U) & 0x7fffffffU;
    return (int)seed;
}

Кроме того: в реализации glibc по-прежнему есть этот генератор (называемый генератором типа 0), но также есть и более удобный триномиальный генератор, который (предположительно) лучше.

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

Любой действительно случайный генератор должен использовать действительно случайный входной источник, поэтому /dev/random иногда будет блокировать ("ожидание энтропии"), а /dev/urandom - нет.

"Истинно" случайные источники могут зависеть от времени между нажатиями клавиш, данных, вводимых пользователями, содержимого сетевых пакетов, шаблонов дискового ввода-вывода, времени, необходимого для ответа ICMP, чтобы вернуться по сети, и всех других удивительных, главным образом недетерминированные вещи.

Если вы не сильно разбираетесь в криптографии, обычные генераторы случайных чисел будут в порядке.

Ответ 2

Как я уже сказал в комментариях, случайные генераторы ОЗУ не являются случайными, они псевдослучайные.

Вы всегда можете посмотреть на источник java java.util.Random.

В частности - метод next(int bits) - это то, что вы ищете.

protected int next(int bits) {
      long oldseed, nextseed;
      AtomicLong seed = this.seed;
      do {
            oldseed = seed.get();
            nextseed = (oldseed * multiplier + addend) & mask;
      } while (!seed.compareAndSet(oldseed, nextseed));
      return (int)(nextseed >>> (48 - bits));
}

(*) Этот ответ подходит для предыдущей версии вопроса, которая была помечена как java и не запрашивала специально для С++.

Ответ 3

Вот простой псевдослучайный алгоритм:

//generates pseudo random series of numbers 0...RAND_MAX - 1 with uniform distribution, starting with 0

static const int A = 15342; // any number in (0, RAND_MAX)
static const int C = 45194; // any number in [0, RAND_MAX)
static const RAND_MAX = 100000;

int rand()
{
    static int prev = 0; //seed. any number in [0, RAND_MAX)
    prev = ( prev * A + C ) % RAND_MAX;
    return prev;
}

Вы можете прочитать больше здесь: http://en.wikipedia.org/wiki/Linear_congruential_generator