Энциклопедия Turbo Pascal. Главы 5-8
Страница 25. Генераторы случайных чисел


Генераторы случайных чисел

     Технически термин  "генератор случайных чисел" - это абсурд;
числа само по себе не являются случайными.  Например,  100 -  это
случайное число?  А 25? Что в действительности означает этот тер-
мин, так это то, что создается последовательность чисел, появляю-
щихся случайным образом.  Это порождает более сложный вопрос: что
такое последовательность случайных чисел?  Единственно правильный
ответ:  последовательность  случайных  чисел _ это последователь-
ность,  в которой все элементы являются несвязанными. Это опреде-
ление  приводит к такому парадоксу,  что любая последовательность
может быть как случайной,  так и неслучайной в зависимости от то-
го,  как  эта  последовательность получена.  Например,  следующая
строка чисел
    1 2 3 4 5 6 7 8 9 0
была получена печатанием верхней строки  клавиатуры  по  порядку,
таким образом последовательность конечно не может рассматриваться
как сгенерированная случайным образом. Но как быть, если вы полу-
чите ту же самую последовательность, вынимая пронумерованный тен-
нисные шары из боченка. В данном случае это уже случайным образом
сгенерированная последовательность. Данный пример показывает, что
случайность последовательности зависит от того,  как она была по-
лучена, а не от нее самой.
     Помните, что   последовательность   чисел,   сгенерированная
компьютером, является детерминированной: каждое число, кроме пер-
вого,  зависит от предшествующих чисел.  Технически это означает,
что  компьютером  может  быть сгенерирована только квазислучайная
последовательность чисел.  Однако, этого достаточно для большинс-
тва  задач и в данной книге такие последовательности для простоты
будут называться случайными.
     В общем  случае  считается хорошо,  когда числа в последова-
тельности случайных чисел распределены равномерно (не путайте это
с  нормальным  распределением  или колоколообразной кривой).  При
равномерном распределении все события равновероятны так,  что ди-
аграмма  равномерного  распределения  стремится к прямой горизон-
тальной линии, а не к кривой.
     До широкого  распространения  компьютеров всякий раз,  когда
необходимы были случайные числа,  они получались  либо  бросанием
игральных костей, либо выниманием пронумерованных шаров из ящика.
В 1955 году фирма RAND опубликовала таблицу из 1 миллиона случай-
ных чисел,  полученных с помощью вычислительной машины. На ранней
стадии развития вычислительной техники было разработано много ме-
тодов  генерации случайных чисел,  но большинство из них не нашло
применения.
     Один очень интересный метод был разработан Джоном фон Нейма-
ном;  его часто называют среднеквадратичным. В данном методе пре-
дыдущее случайное число возводится в квадрат,  а затем из резуль-
тата выделяются средние цифры.  Например,  если вы создаете числа
из трех цифр,  а предыдущее число было 121, то возведение в квад-
рат дает результат 14641. Выделение трех средних цифр дает следу-
ющее случайное число 464. Недостатком данного метода является то,
что он имеет очень короткий период повторения, называемый циклом.
По данной причине данный метод сегодня не используется.
     В настоящий момент наиболее часто применяется метод  генера-
ции случайных чисел, основывающийся на использовании уравнения
       R    = (aR +c)modm
        n+1         n
при выполнении следующих условий

    R>0
    a>0
    c>0
    m>R , a и c

     Отметим, что R - это предыдущее число, а R - следующее. Дан-
ный метод иногда называют линейным сравнительным методом. Формула
так  проста,  что вы можете подумать,  что генерировать случайные
числа просто. Однако, это ловушка: насколько хорошо работает дан-
ная  формула,  очень сильно зависит от значения а,  с и m.  Выбор
значений иногда в большей степени искусство,  нежели  наука.  Су-
ществуют сложные правила, которые могут помочь вам выбрать значе-
ния; однако, мы рассмотрим лишь несколько простых правил и приме-
ров.

     Модуль (m) должен быть довольно большим,  так как он опреде-
ляет область случайных чисел. Операция взятия по модулю порождает
остаток от деления числа на модуль. Следовательно, 10 по модулю 4
равно 2.  Таким образом, если модуль равен 12, то формулой порож-
даются числа от 0 до 11, а если модуль равен 21425, то порождают-
ся числа от 0 до 21424. Выбор множителя а и приращения с является
очень  сложной  задачей.  В общем случае множитель может быть до-
вольно большим,  а приращение - маленьким.  Множество  попыток  и
проверок необходимо, чтобы создать хороший генератор.

     В качестве первого примера здесь приведен один  из  наиболее
часто используемых генераторов случайных чисел.  Уравнение, пока-
занное в Rаn1 используется как основа  для  генератора  случайных
чисел в ряде популярных языков.
    var
      a1: integer; { установка до первого вызова Ran1 }

    function Ran1: real;
    var
      t: real;
    begin
      t := (a1*32749+3) mod 32749;
      a1 := Trunc(t);
      Ran1 := Abs(t/32749);
    end; {Rea1}

     Данная функция имеет  три  главные  особенности.  Во-первых,
случайные числа в действительности являются целыми,  хотя функция
возвращает действительные числа.  Данный метод работает с  целыми
числами,  но генераторы случайных чисел,  как это принято, должны
возвращать числа в пределах от 0 до  1,  что  означает,  что  это
должны быть числа с плавающей запятой.
     Во-вторых, начальное значение задается через глобальную  пе-
ременную а1. До первого вызова Ran1 переменная а1 должна быть ус-
тановлена в 1.
     В-третьих, в  Ran1 случайные числа делятся на модуль прежде,
чем они будут возвращены функцией, для того, чтобы числа лежали в
области  от 0 до 1.  Если вы поинтересуетесь значением глобальной
переменной а1 до возврата строки,  то оно должно лежать в области
от 0 до 32748. Следовательно, когда а1 делится на 32749, получен-
ное число будет больше или равно 0 и меньше 1.
     Многие генераторы случайных чисел не применимы,  так как они
порождают не равномерное распределение или  имеют  короткий  цикл
повторения. Даже когда эти недостатки не очень бросаются в глаза,
они могут породить смешанный результат,  если такой генератор ис-
пользуется снова и снова.  Решение заключается в том,  чтобы соз-
дать различные генераторы и применять их индивидуально  или  сов-
местно   для  получения  более  качественных  последовательностей
случайных чисел. Применение нескольких генераторов может сгладить
распределение  последовательности за счет уменьшения малых смеше-
ний отдельных генераторов.  Далее приведена функция генерирования
случайных чисел, называемая Ran2, которая порождает хорошее расп-
ределение:
    var
      a2:integer; { установить в значение 203 до первого вызова
                    Ran2 }
    function Ran2: real;
    var
      t: real;
    begin
      t := (a2*10001+3) mod 17417;
      a2 := Trunc(t);
      Ran2 := Abc(t/17417);
    end; {Ran2}

     Оба этих генератора случайных чисел порождают хорошие после-
довательности случайных чисел.  Тем не  менее  остаются  вопросы:
достаточно ли "случайной" является последовательность?  Хороши ли
данные генераторы?

 
« Предыдущая статья   Следующая статья »