2015-10-08 129 views
10

我無法確定Mersenne Twister C++ 11提供了哪種變體。查看松本和西村的ACM論文Mersenne twister: A 623 Dimensionally Equidistributed Uniform Pseudorandom Number Generator,作者提供算法,該算法的一個實現,並稱之爲MT19937C++ 11提供哪些Mersenne Twister?

但是,當我用下面的小程序測試C++ 11的同名發生器時,我無法再現由松本和西村的MT19937創建的流。這些流與產生的第一個32位字不同。

C++ 11提供哪些Mersenne Twister?


下面的程序是用GCC,-std=c++11和GNU的stdlibc++在Fedora 22上運行。

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

如果您看看Boost.Random中的[header](http://www.boost.org/doc/libs/release/boost/random/mersenne_twister.hpp),它們表示*整數的播種是在2005年4月更改爲解決[弱點](http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html)*。難道你是在比較改變之前發表的論文的結果嗎? – Praetorian

+0

@Praetorian - 呃,我不確定,但我不這麼認爲。我沒有使用Boost;相反,我通過'libstdC++'使用GNU的實現。 – 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第10000迭代399268537

+0

對於32位版本,「d」的「0xffffffff」值表示實際上沒有變化。 –

+0

原文使用69069作爲乘數(1812433253是AR修訂和標準的一部分)。 – jww

+0

我不禁感到C++不應該使用'MT19937'這個名字,因爲它*不*使用原始參數。 'EMT19937','MT19937ar','eMT19937ar'等將是更好的選擇。事實上,它看起來像[「AR」(對於「數組」)是作者用來區分這種變化](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>; 

我認爲這將是很好的用於檢查的RNG的質量,使人們可以嘗試新的實例提供了一個工具箱。

這裏是模板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。