Вихрь Мерсенна был специально разработан для исправления большинства недостатков, обнаруженных в старых ГПСЧ.
Наиболее часто используемая версия алгоритма Mersenne Twister основана на простом числе Мерсенна . Стандартная реализация этого, MT19937, использует 32-битную длину слова. Существует другая реализация (с пятью вариантами [3] ), которая использует 64-битную длину слова, MT19937-64; она генерирует другую последовательность.
к-распределение
Псевдослучайная последовательность w -битных целых чисел периода P называется k-распределенной с точностью v -бит, если выполняется следующее.
Пусть trunc v ( x ) обозначает число, образованное ведущими v битами x , и рассмотрим P из k v -битных векторов
.
Тогда каждая из возможных комбинаций битов встречается одинаковое количество раз за период, за исключением комбинации, состоящей из одних нулей, которая встречается на один раз реже.
Алгоритмическая детализация
Для слова длиной w бит алгоритм Mersenne Twister генерирует целые числа в диапазоне .
Общий алгоритм характеризуется следующими величинами:
w : размер слова (в битах)
n : степень повторяемости
m : среднее слово, смещение, используемое в рекуррентном соотношении, определяющем ряд ,
r : точка разделения одного слова или количество бит нижней битовой маски,
a : коэффициенты матрицы скручивания рациональной нормальной формы
b , c : Битовые маски смягчения TGFSR(R)
s , t : TGFSR(R) закалка бит сдвиги
u , d , l : дополнительные смещения/маски закалочных бит Mersenne Twister
с ограничением, что является простым числом Мерсенна. Этот выбор упрощает тест примитивности и тест k -распределения , которые необходимы при поиске параметров.
Ряд определяется как ряд w -битных величин с рекуррентным соотношением:
где обозначает конкатенацию битовых векторов (со старшими битами слева), побитовое исключающее ИЛИ (XOR), означает старшие w − r битов , а означает младшие r битов .
Все индексы могут быть смещены на -n
где теперь левая ось, , является следующим сгенерированным значением в ряду с точки зрения значений, сгенерированных в прошлом, которые находятся в правой оси.
Преобразование скручивания A определяется в рациональной нормальной форме как:
с единичной матрицей. Рациональная нормальная форма имеет то преимущество, что умножение на A может быть эффективно выражено как: (помните, что здесь умножение матриц выполняется в , и поэтому побитовое XOR заменяет сложение) где — младший бит .
Как и TGFSR(R), Mersenne Twister каскадируется с темперирующим преобразованием для компенсации уменьшенной размерности равнораспределения (из-за выбора A в рациональной нормальной форме). Обратите внимание, что это эквивалентно использованию матрицы A , где для T — обратимая матрица, и, следовательно, анализ характеристического полинома, упомянутый ниже, по-прежнему остается в силе.
Как и в случае с A , мы выбираем преобразование закалки, которое легко вычисляется, и поэтому фактически не конструируем само T. Это закалка определяется в случае вихря Мерсенна как
где — следующее значение из ряда, — временное промежуточное значение, а — значение, возвращаемое алгоритмом, с и как побитовые сдвиги влево и вправо , и как побитовое И. Первое и последнее преобразования добавляются для улучшения равномерного распределения нижних бит. Из свойства TGFSR требуется достичь верхней границы равномерного распределения для верхних бит.
Коэффициенты для MT19937 следующие:
Обратите внимание, что 32-битные реализации Mersenne Twister обычно имеют d = FFFFFFFF 16. В результате d иногда опускается в описании алгоритма, поскольку побитовое and с d в этом случае не имеет никакого эффекта.
Коэффициенты для MT19937-64 следующие: [5]
Инициализация
Состояние, необходимое для реализации Mersenne Twister, представляет собой массив из n значений по w бит каждое. Для инициализации массива используется начальное значение w бит для подачи через установку начального значения и последующую установку
для с по .
Первое значение, которое генерирует алгоритм, основано на , а не на .
Константа f является еще одним параметром генератора, хотя и не является частью самого алгоритма.
Значение f для MT19937 равно 1812433253.
Значение f для MT19937-64 равно 6364136223846793005. [5]
код С
#include <stdint.h>#define n 624 #define m 397 #define w 32 #define r 31 #define UMASK (0xffffffffUL << r) #define LMASK (0xffffffffUL >> (wr)) #define a 0x9908b0dfUL #define u 11 #define s 7 #define t 15 #define l 18 #define b 0x9d2c5680UL #define c 0xefc60000UL #define f 1812433253ULtypedef struct { uint32_t state_array [ n ]; // массив для вектора состояния int state_index ; // индекс в массиве векторов состояния, 0 <= state_index <= n-1 всегда } mt_state ;void initialize_state ( mt_state * state , uint32_t seed ) { uint32_t * state_array = & ( state -> state_array [ 0 ]); state_array [ 0 ] = seed ; // предлагаемое начальное seed = 19650218UL for ( int i = 1 ; i < n ; i ++ ) { seed = f * ( seed ^ ( seed >> ( w -2 ))) + i ; // Knuth TAOCP Vol2. 3rd Ed. P.106 для множителя. state_array [ i ] = seed ; } state -> state_index = 0 ; }uint32_t random_uint32 ( mt_state * state ) { uint32_t * state_array = & ( state -> state_array [ 0 ]); int k = state -> state_index ; // указывает на текущее местоположение состояния // 0 <= state_index <= n-1 всегда // int k = k - n; // указывает на состояние за n итераций до // if (k < 0) k += n; // циклическая индексация по модулю n // предыдущие 2 строки на самом деле ничего не делают // только для иллюстрации int j = k - ( n -1 ); // указывает на состояние за n-1 итераций до if ( j < 0 ) j += n ; // циклическая индексация по модулю nuint32_t x = ( state_array [ k ] & UMASK ) | ( state_array [ j ] & LMASK ); uint32_t xA = x >> 1 ; if ( x & 0x00000001UL ) xA ^= a ; j = k - ( n - m ); // указать на состояние за nm итераций до этого if ( j < 0 ) j += n ; // циклическая индексация по модулю n x = state_array [ j ] ^ xA ; // вычислить следующее значение в состоянии state_array [ k ++ ] = x ; // обновить новое значение состояния if ( k >= n ) k = 0 ; // циклическая индексация по модулю n state -> state_index = k ; uint32_t y = x ^ ( x >> u ); // закалка y = y ^ (( y << s ) & b ); y = y ^ (( y << t ) & c ); uint32_t z = y ^ ( y >> l ); return z ; }
Трансформация кручения улучшает классический GFSR, придавая ему следующие ключевые свойства:
Период достигает теоретического верхнего предела (за исключением случая, когда он инициализирован значением 0)
Равномерное распределение в n измерениях (например, линейные конгруэнтные генераторы в лучшем случае могут обеспечить разумное распределение в пяти измерениях)
MTGP — это вариант Mersenne Twister, оптимизированный для графических процессоров , опубликованный Муцуо Сайто и Макото Мацумото. [8] Базовые линейные рекуррентные операции расширены из MT, а параметры выбраны так, чтобы позволить многим потокам вычислять рекурсию параллельно, при этом разделяя свое пространство состояний для снижения нагрузки на память. В статье утверждается улучшенное равнораспределение по сравнению с MT и производительность на старом (2008 года) GPU ( Nvidia GTX260 с 192 ядрами) 4,7 мс для 5×10 7 случайных 32-битных целых чисел.
SFMT ( SIMD -ориентированный Fast Mersenne Twister) — это вариант Mersenne Twister, представленный в 2006 году [9], разработанный для быстрой работы на 128-битной SIMD.
Он примерно в два раза быстрее, чем вихрь Мерсенна. [10]
Он быстрее восстанавливается из начального состояния с нулевым избытком, чем MT, но медленнее, чем WELL.
Поддерживает различные периоды от 2 607 − 1 до 2 216091 − 1.
Intel SSE2 и PowerPC AltiVec поддерживаются SFMT. Он также используется для игр с Cell BE в PlayStation 3. [ 11]
TinyMT — это вариант Mersenne Twister, предложенный Сайто и Мацумото в 2011 году. [12] TinyMT использует всего 127 бит пространства состояний, что значительно меньше по сравнению с 2,5 КБ состояния оригинала. Однако его период составляет , что намного короче оригинала, поэтому авторы рекомендуют его только в случаях, когда память в дефиците.
Проходит многочисленные тесты на статистическую случайность, включая тесты Diehard и большинство, но не все, тестов TestU01 . [13]
Очень долгий период . Обратите внимание, что хотя долгий период не является гарантией качества генератора случайных чисел, короткие периоды, такие как распространенные во многих старых пакетах программного обеспечения, могут быть проблематичными. [14]
k-распределенный с точностью 32 бита для каждого (определение k -распределенного см. ниже)
Реализации обычно создают случайные числа быстрее, чем аппаратно реализованные методы. Исследование показало, что Mersenne Twister создает 64-битные плавающие случайные числа примерно в двадцать раз быстрее, чем аппаратно реализованный процессорный набор инструкций RDRAND . [15]
Недостатки:
Относительно большой буфер состояний, почти 2,5 КБ , если не используется вариант TinyMT.
Посредственная пропускная способность по современным стандартам, если только не используется вариант SFMT (обсуждаемый ниже). [16]
Демонстрирует два явных провала (линейная сложность) в Crush и BigCrush в наборе TestU01. Тест, как и Mersenne Twister, основан на -алгебре . [13]
Несколько экземпляров, которые отличаются только начальным значением (но не другими параметрами), обычно не подходят для моделирования Монте-Карло , требующего независимых генераторов случайных чисел, хотя существует метод выбора нескольких наборов значений параметров. [17] [18]
Плохая диффузия: может потребоваться много времени, чтобы начать генерировать выходные данные, которые проходят тесты на случайность , если начальное состояние в высшей степени неслучайно — особенно если в начальном состоянии много нулей. Следствием этого является то, что два экземпляра генератора, запущенные с начальными состояниями, которые почти одинаковы, обычно выводят почти одну и ту же последовательность для многих итераций, прежде чем в конечном итоге расходятся. Обновление алгоритма MT 2002 года улучшило инициализацию, так что начало с такого состояния очень маловероятно. [19] Говорят, что версия GPU (MTGP) еще лучше. [20]
Содержит подпоследовательности с большим количеством нулей, чем единиц. Это усугубляет плохие свойства диффузии, затрудняя восстановление из состояний с множеством нулей.
Не является криптографически безопасным , если только не используется вариант CryptMT (обсуждаемый ниже). Причина в том, что наблюдение достаточного количества итераций (624 в случае MT19937, поскольку это размер вектора состояния, из которого производятся будущие итерации) позволяет предсказать все будущие итерации.
Приложения
Mersenne Twister используется в качестве ГПСЧ по умолчанию в следующем программном обеспечении:
Языки программирования: Dyalog APL , [21] IDL , [22] R , [23] Ruby , [24] Free Pascal , [25] PHP , [26] Python (также доступен в NumPy , однако с версии 1.17 значение по умолчанию было изменено на PCG64 [27] ), [28] [29] [30] CMU Common Lisp , [31] Embeddable Common Lisp , [32] Steel Bank Common Lisp , [33] Julia (до Julia 1.6 LTS, все еще доступен в более поздних версиях, но с версии 1.7 по умолчанию используется более качественный/быстрый ГСЧ) [34]
Mersenne Twister — один из двух PRNG в SPSS : другой генератор оставлен только для совместимости со старыми программами, а Mersenne Twister заявлен как «более надежный». [54] Mersenne Twister — это также один из PRNG в SAS : другие генераторы устарели и устарели. [55] Mersenne Twister — это PRNG по умолчанию в Stata , другой — KISS , для совместимости со старыми версиями Stata. [56]
Альтернативы
Альтернативный генератор WELL («Well Equidistributed Long-period Linear») обеспечивает более быстрое восстановление, равную случайность и почти равную скорость. [57]
64-битные MELG («64-битные максимально равнораспределенные линейные генераторы с простым периодом Мерсенна») полностью оптимизированы с точки зрения свойств k -распределения. [59]
Семейство ACORN (опубликовано в 1989 году) — это еще один k -распределенный PRNG, который показывает вычислительную скорость, схожую с MT, и лучшие статистические свойства, поскольку удовлетворяет всем текущим (2019) критериям TestU01; при использовании с соответствующим выбором параметров ACORN может иметь произвольно большой период и точность.
Семейство PCG представляет собой более современный генератор с большим периодом, с лучшей локализацией кэша и менее обнаруживаемым смещением при использовании современных методов анализа. [60]
Ссылки
^ Мацумото, М.; Нисимура, Т. (1998). «Вихрь Мерсенна: 623-мерно равнораспределенный равномерный генератор псевдослучайных чисел». Труды ACM по моделированию и компьютерному моделированию . 8 (1): 3–30. CiteSeerX 10.1.1.215.1141 . doi :10.1145/272991.272995. S2CID 3332028.
^ Например, Марсланд С. (2011) Машинное обучение ( CRC Press ), §4.1.1. Также см. раздел «Внедрение в программные системы».
^ Джон Савард. "Вихрь Мерсенна". Последующая статья, опубликованная в 2000 году, дала пять дополнительных форм вихря Мерсенна с периодом 2^19937-1. Все пять были разработаны для реализации с 64-битной арифметикой вместо 32-битной.
^ Мацумото, М.; Курита, И. (1992). «Скрученные генераторы GFSR». Труды ACM по моделированию и компьютерному моделированию . 2 (3): 179–194. doi :10.1145/146382.146383. S2CID 15246234.
^ ab "std::mersenne_twister_engine". Генерация псевдослучайных чисел . Получено 2015-07-20 .
^ ab "CryptMt and Fubuki". eCRYPT . Архивировано из оригинала 2012-07-01 . Получено 2017-11-12 .
^ "SIMD-ориентированный быстрый вихрь Мерсенна (SFMT)". hiroshima-u.ac.jp . Получено 4 октября 2015 г. .
^ "SFMT:Сравнение скорости". hiroshima-u.ac.jp . Получено 4 октября 2015 г. .
^ "PlayStation3 License". scei.co.jp . Получено 4 октября 2015 г. .
^ "Tiny Mersenne Twister (TinyMT)". hiroshima-u.ac.jp . Получено 4 октября 2015 г. .
^ ab P. L'Ecuyer и R. Simard, "TestU01: "Библиотека AC для эмпирического тестирования генераторов случайных чисел", ACM Transactions on Mathematical Software , 33, 4, статья 22 (август 2007 г.).
^ Примечание: 2 19937 приблизительно равно 4,3 × 10 6001 ; это на много порядков больше предполагаемого числа частиц в наблюдаемой Вселенной , которое составляет 10 87 .
↑ Route, Matthew (10 августа 2017 г.). «Синтез популяции сверххолодных карликов в радиоизлучении». The Astrophysical Journal . 845 (1): 66. arXiv : 1707.02212 . Bibcode : 2017ApJ...845...66R. doi : 10.3847/1538-4357/aa7ede . S2CID 118895524.
^ "SIMD-ориентированный быстрый вихрь Мерсенна (SFMT): в два раза быстрее, чем вихрь Мерсенна". Японское общество содействия науке . Получено 27 марта 2017 г.
^ Макото Мацумото; Такудзи Нисимура. «Динамическое создание генераторов псевдослучайных чисел» (PDF) . Получено 19 июля 2015 г.
^ Хироши Харамото; Макото Мацумото; Такудзи Нисимура; Франсуа Паннетон; Пьер Л'Экюйер. "Эффективный прыжок вперед для F2-линейных генераторов случайных чисел" (PDF) . Получено 12 ноября 2015 г.
^ "mt19937ar: Mersenne Twister с улучшенной инициализацией". hiroshima-u.ac.jp . Получено 4 октября 2015 г. .
^ Фог, Агнер (1 мая 2015 г.). «Генератор псевдослучайных чисел для векторных процессоров и многоядерных процессоров». Журнал современных прикладных статистических методов . 14 (1): 308–334. doi : 10.22237/jmasm/1430454120 .
^ "Случайная ссылка". Справочное руководство по языку Dyalog . Получено 04.06.2020 .
^ "RANDOMU (Справочник IDL)". Центр документов Exelis VIS . Получено 23.08.2013 .
^ "Генератор xorshift*/xorshift+ и перестрелка с PRNG".
^ Харасе, С.; Кимото, Т. (2018). «Реализация 64-битных максимально равнораспределенных F2-линейных генераторов с простым периодом Мерсенна». Труды ACM по математическому программному обеспечению . 44 (3): 30:1–30:11. arXiv : 1505.06582 . doi : 10.1145/3159444. S2CID 14923086.
^ "The PCG Paper". 27 июля 2017 г.
Дальнейшее чтение
Харас, С. (2014), «О -линейных отношениях генераторов псевдослучайных чисел Mersenne Twister», Математика и компьютеры в моделировании , 100 : 103–113, arXiv : 1301.5435 , doi : 10.1016/j.matcom.2014.02.002, S2CID 6984431.
Харас, С. (2019), «Преобразование вихря Мерсенна в числа с плавающей точкой двойной точности», Математика и компьютеры в моделировании , 161 : 76–83, arXiv : 1708.06018 , doi : 10.1016/j.matcom.2018.08.006, S2CID 19777310.
Внешние ссылки
Научная статья для MT и связанные с ней статьи Макото Мацумото
Домашняя страница Mersenne Twister с кодами на C, Fortran, Java, Lisp и некоторых других языках
Примеры Mersenne Twister — коллекция реализаций Mersenne Twister на нескольких языках программирования — на GitHub
SFMT в действии: Часть I – Создание DLL, включающей поддержку SSE2 – в Code Project