2015-10-08 6 views
10

У меня возникли проблемы с определением, какой вариант Mersenne Twister C++ 11 обеспечивает. Глядя на статью Matsumoto и Nishimura ACM по адресу Mersenne twister: A 623 Dimensionally Equidistributed Uniform Pseudorandom Number Generator, авторы предоставляют алгоритм, реализацию алгоритма и называют его MT19937.Какой Mersenne Twister делает C++ 11?

Однако, когда я тестирую одноименный генератор C++ 11 с небольшой программой ниже, я не могу воспроизвести поток, созданный Matsumoto и Nisimura MT19937. Потоки отличаются от самого первого 32-битного слова.

Какой Mersenne Twister предлагает C++ 11?


Программа ниже был запущен на Fedora 22 с использованием GCC, -std=c++11 и ГНУ stdlibc++.

std::mt19937 prng(102013); 
for (unsigned int i = 0; i <= 625; i++) 
{ 
    cout << std::hex << prng(); 

    if(i+1 != 625) 
     cout << ","; 

    if(i && i%8 == 0) 
     cout << endl; 
} 
+0

Если вы посмотрите на [заголовок] (http://www.boost.org/doc/libs/release/boost/random/mersenne_twister.hpp) в Boost.Random, они заявляют * Посев из целого числа был изменен в апреле 2005 года для устранения [слабости] (http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html) *.Может быть, вы сравниваете результаты публикации, опубликованной до этого изменения? – Praetorian

+0

@Praetorian - Ну, я не уверен, но я не верю в это. Я не использую Boost; скорее, я использую реализацию GNU через libstdC++. – jww

+0

Он использует http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c. IOW, с которым связан @Praetorian. –

ответ

4

Глядя на MT19937 от вашего связанного с бумагой и MT19937 определяется стандартом, похоже, они одинаковы, но дополнительный слой темперирования был добавлен и инициализация мультипликатор

Если мы посмотрим при значениях, определяемых [rand.predef] 26.5.5 (3) в зависимости от параметров, определенных бумаги мы имеем

32,624,397,31,0x9908b0df,11,0xffffffff,7,0x9d2c5680,15,0xefc60000,18,1812433253 <- standard 
w ,n ,m ,r ,a   ,u ,d   ,s,b   ,t ,c   ,l ,f 
32,624,397,31,0x9908b0df,11,   ,7,0x9d2c5680,15,0xefc60000,18,   <- paper 

Это где разница откуда. Кроме того, согласно Стандартно десятитысячной итерация std::mt19937 является 399268537

+0

Для 32-разрядной версии значение '0xffffffff' для' d' означает, что никаких изменений на самом деле не происходит. –

+0

Исходная бумага, используемая в качестве множителя 69069 (1812433253, является частью ревизии AR и стандартом). – jww

+0

Я не могу не чувствовать, что C++ должен * не * использовать имя 'MT19937', потому что его * not * использует исходные параметры. 'EMT19937',' MT19937ar', 'eMT19937ar' и т. Д. Были бы лучшим выбором. На самом деле это выглядит так: [«AR» (для «Array») - это то, что авторы используют для дифференциации этого изменения] (http://www.math.sci.hiroshima-u.ac.jp/~m-mat/ MT/MT2002/emt19937ar.html) от оригинала. – jww

1

Кажется C++ 11 предоставляет Mersenne Twister with improved initialization

Я только что извлеченный оригинальная реализация C, и по сравнению с C++.

#include <iostream> 
#include <cstdio> 
#include <random> 

#define N 624 
#define M 397 
#define MATRIX_A 0x9908b0dfUL /* constant vector a */ 
#define UPPER_MASK 0x80000000UL /* most significant w-r bits */ 
#define LOWER_MASK 0x7fffffffUL /* least significant r bits */ 

static unsigned long mt[N]; /* the array for the state vector */ 
static int mti=N+1; /* mti==N+1 means mt[N] is not initialized */ 

void init_genrand(unsigned long s) 
{ 
    mt[0]= s & 0xffffffffUL; 
    for (mti=1; mti<N; mti++) { 
     mt[mti] = 
     (1812433253UL * (mt[mti-1]^(mt[mti-1] >> 30)) + mti); 
     mt[mti] &= 0xffffffffUL; 
    } 
} 

unsigned long genrand_int32() 
{ 
    unsigned long y; 
    static unsigned long mag01[2]={0x0UL, MATRIX_A}; 

    if (mti >= N) { /* generate N words at one time */ 
     int kk; 

     if (mti == N+1) /* if init_genrand() has not been called, */ 
      init_genrand(5489UL); /* a default initial seed is used */ 

     for (kk=0;kk<N-M;kk++) { 
      y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); 
      mt[kk] = mt[kk+M]^(y >> 1)^mag01[y & 0x1UL]; 
     } 
     for (;kk<N-1;kk++) { 
      y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); 
      mt[kk] = mt[kk+(M-N)]^(y >> 1)^mag01[y & 0x1UL]; 
     } 
     y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); 
     mt[N-1] = mt[M-1]^(y >> 1)^mag01[y & 0x1UL]; 

     mti = 0; 
    } 

    y = mt[mti++]; 

    y ^= (y >> 11); 
    y ^= (y << 7) & 0x9d2c5680UL; 
    y ^= (y << 15) & 0xefc60000UL; 
    y ^= (y >> 18); 

    return y; 
} 

int main() 
{ 
    init_genrand(102013); 

    std::mt19937 prng(102013); 

    for (size_t i = 0; i < 10000; ++i) { 
     if (genrand_int32() != prng()) { 
      std::cout << "ERROR" << std::endl; 
      return 1; 
     } 
    } 

    std::cout << "OK" << std::endl; 
    return 0; 
} 
+0

. Похоже, что они предоставляют 'MT19937ar', а не' MT19937'. Это верно? – jww

+0

@jww Нет, правильное имя 'MT19937'. Кажется, что «MT19937ar» - это просто имя файла, где они добавили инициализацию массива. – Stas

+0

@jww Также см. Список реализаций C: http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/C-LANG/c-lang.html Были две версии (1998 и 1999), устаревшие сейчас. – Stas

1

Я должен отметить, что C++ 11 фактически обеспечивает много Вихрь Мерсенна через шаблон класса:

template <class UIntType, 
      size_t word_size, 
      size_t state_size, 
      size_t shift_size, 
      size_t mask_bits, 
      UIntType xor_mask, 
      size_t tempering_u, 
      UIntType tempering_d, 
      size_t tempering_s, 
      UIntType tempering_b, 
      size_t tempering_t, 
      UIntType tempering_c, 
      size_t tempering_l, 
      UIntType initialization_multiplier> 
    class mersenne_twister_engine; 

Если кто имеет мужество, чтобы исследовать эти рычаги и ручки .. . Конечно, существуют два стандартных экземпляра:

using mt19937 
    = mersenne_twister_engine<uint_fast32_t, 
          32, 
          624, 
          397, 
          31, 
          0x9908b0df, 
          11, 
          0xffffffff, 
          7, 
          0x9d2c5680, 
          15, 
          0xefc60000, 
          18, 
          1812433253>; 

и 64-разрядная версия:

using mt19937_64 
    = mersenne_twister_engine<uint_fast64_t, 
          64, 
          312, 
          156, 
          31, 
          0xb5026f5aa96619e9, 
          29, 
          0x5555555555555555, 
          17, 
          0x71d67fffeda60000, 
          37, 
          0xfff7eee000000000, 
          43, 
          6364136223846793005>; 

Я думал, что было бы неплохо, чтобы обеспечить набор инструментов для проверки качества ГСЧА, чтобы люди могли попробовать новую инстанциацию.

Вот сравнение шаблона Parms:

32,624,397,31,  0x9908b0df,11,  0xffffffff,7 ,  0x9d2c5680,15,  0xefc60000,18,1812433253   <- std::mt19937 
64,312,156,31,0xb5026f5aa96619e9,29,0x5555555555555555,17,0x71d67fffeda60000,37,0xfff7eee000000000,43,6364136223846793005 <- std::mt19937_64 
w ,n ,m ,r ,a     ,u ,d     ,s ,b     ,t ,c     ,l ,f 
32,624,397,31,  0x9908b0df,11,     ,7 ,  0x9d2c5680,15,  0xefc60000,18,     <- paper 

С благодарностью @NathanOliver.