【随机数生成算法系列】线性同余法和梅森旋转法

一般我们用到的随机算法都是伪随机算法,什么叫伪随机算法呢?伪随机算法意思是假如知道第一个随机种子和随机算法的话就可以推算出下一个随机数。通常我们程序里都是通过当前时间作为随机函数的第一个随机种子,然后将随机函数返回的值作为下一个种子,随机函数是一个公用函数,每个用户的请求都会触发一个新的随机种子,所以说是随机的。很多公司都有自己的一套随机算法。


常用的快速随机数产生算法是线性同余算法和梅森旋转算法。平均分布的伪随机算法都是周期性的,在一个周期内各个数字的分布概率相等。Windows和Linux的C运行库都采用线性同余算法,Window C运行库的随机序列周期是65536,Linux的C运行库是2^31,在一个周期内一个数字只出现一次。而设置随机数种子就相当于设置当前的a[n],下一个随机数从这里开始计算产生。


但是线性同余的周期太短了,后来出现了梅森旋转算法:请参考wiki,梅森旋转算法各项指标非常优秀,现在一般使用的是产生器有2^19937-1长的周期,而且在1-623维均匀分布的(映射到一维直线均匀分布,二维平面内均匀分布,三维空间内均匀分布...)。


不过上面这两种算法还都不适合用于加密,因为攻击者如果收集了足够长的一段序列,就可以从数学上猜解出整个序列。可以用于加密的随机数生成算法有RSA随机数生成算法等。而产生高斯分布的随机数产生算法,据我所知有box-mueller算法。


一、线性同余法

古老的LCG(linear congruential generator)代表了最好的伪随机数产生器算法。主要原因是容易理解,容易实现,而且速度快。这种算法数学上基于X(n+1) = (a * X(n) + c) % m这样的公式,其中:
模m, m > 0
系数a, 0 < a < m
增量c, 0 <= c < m
原始值(种子) 0 <= X(0) < m
其中参数c, m, a比较敏感,或者说直接影响了伪随机数产生的质量。

一般而言,高LCG的m是2的指数次幂(一般2^32或者2^64),因为这样取模操作截断最右的32或64位就可以了。

多数编译器的库中使用了该理论实现其伪随机数发生器rand()。下面是部分编译器使用的各个参数值:

Source                           m            a            c          rand() / Random(L)的种子位
Numerical Recipes                  
                                 2^32         1664525      1013904223    
Borland C/C++                      
                                 2^32         22695477     1          位30..16  in rand(), 30..0  in lrand()
glibc (used by GCC)                
                                 2^32         1103515245   12345      位30..0
ANSI C: Watcom, Digital Mars, CodeWarrior, IBM VisualAge C/C++
                                 2^32         1103515245   12345      位30..16
Borland Delphi, Virtual Pascal
                                 2^32         134775813    1          位63..32 of (seed * L)
Microsoft Visual/Quick C/C++
                                 2^32         214013       2531011    位30..16
Apple CarbonLib
                                 2^31-1       16807        0          见Park–Miller随机数发生器

LCG不能用于随机数要求高的场合,例如不能用于Monte Carlo模拟,不能用于加密应用。
LCG有一些严重的缺陷,例如如果LCG用做N维空间的点坐标,这些点最多位于m1/n超平面上(Marsaglia定理),这是由于产生的相继X(n)值的关联所致。
另外一个问题就是如果m设置为2的指数,产生的低位序列周期远远小于整体。
一般而言,输出序列的基数b中最低n位,bk = m (k是某个整数),最大周期bn.
有些场合LCG有很好的应用,例如内存很紧张的嵌入式中,电子游戏控制台用的小整数,使用高位可以胜任。

LCG的一种实现版本如下:

//  random.hpp
//  Copyright (C) 2008  Chipset
//
//  This program is free software: you can redistribute it and/or modify 
//  it under the terms of the GNU Affero General Public License as        
//  published by the Free Software Foundation, either version 3 of the     
//  License, or (at your option) any later version.  
//     
//  but WITHOUT ANY WARRANTY; without even the implied warranty of  
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
//  GNU Affero General Public License for more details. 
// 
//  You should have received a copy of the GNU Affero General Public License
//  along with this program. If not, see .    
//

#ifndef RANDOM_HPP_
#define RANDOM_HPP_
#include 

class random
{
public:
  explicit random(unsigned long s = 0) : seed(s)
  {
    if (0 == seed) seed = std::time(0);
    randomize();
  }
  void reset(unsigned long s = 0)
  {
    seed = s;
    if (0 == seed) seed = std::time(0);
    randomize();
  }
  unsigned long rand()
  {
  //returns a random integer in the range [0, -1UL)
    randomize();
    return seed;
  }
  double real()
  {
  //returns a random real number in the range [0.0, 1.0)
    randomize();
    return double(seed) / -1UL;
  }
private:
  unsigned long seed;
  void randomize() { seed = 1103515245UL * seed + 12345UL; }
};

class rand_help
{
  static random r;
public:
  rand_help() {}
  void operator()(unsigned long s) { r.reset(s); }
  unsigned long operator()() const { return r.rand(); }
  double operator()(double) { return r.real(); }
};
random rand_help:: r;

extern void srandom(unsigned long ns = 0) { rand_help()(ns); } //reset seed
extern unsigned long irand() { return rand_help()(); }         //negative numbers disallowed
extern double drand() { return rand_help()(1.0); }             //for real numbers

#endif  // RANDOM_HPP_

//以上随机数产生器产生的随机数比rand()产生的随机数更加随机(可以用数学方法检验),
//范围更大(一目了然),速度更快(测试一下便知,稍加修改我还可以让它再快一些,如果有必要)。

/*假设随机数均匀分布为理想分布, 粗略估计随机性*/
#include 
< iostream >
#include 
< vector >
#include 
< iomanip >
#include 
" random.hpp "
int  main()
{
  srand(time(
0 ));
  
//SZ分别取值2^3, 2^4,  , 2^15进行测试
   const  size_t SZ  =   1   <<   15 ;
  std::vector
< unsigned >  v1(SZ), v3(SZ);
  std::vector
< unsigned >  v2(SZ), v4(SZ);
  
for (size_t i  =   0 ; i  <  SZ;  ++ i)
  {
    
++ v1[rand()  %  SZ];//对应元素计数 ,理论上v1[0] ~ v1[SZ - 1]之间每个都应该是1
     ++ v2[irand()  %  SZ];
  }

  
for (size_t i  =   0 ; i  <  SZ;  ++ i)
  {
    
++ v3[v1[i]]; //统计频度
     ++ v4[v2[i]];
  }
  
//假设[0, SSZ)之间不存在间断点, (即使有间断点也无所谓,我们只做粗略模糊统计,因为没有必要那么精确)
  //最理想的显示结果应该是0:    0,   1:   SZ,    2:    0,   3:    0,   4:    0,   other:    0
  //0:表示间断,1:表示均匀,2:, 3:, 4:, other: 都表示不同程度的重复
   const  size_t SSZ  =   5 ;
  std::cout.fill(
'   ' );
  
for (size_t i  =   0 ; i  <  SSZ;  ++ i)
    std::cout 
<<  i  <<   " "   <<  std::setw(SSZ)  <<  v3[i]  <<   " ,    " ;
  std::cout 
<<   " other:  "   <<  std::setw(SSZ)
            
<<  v3.size()  -  v3[ 0 -  v3[ 1 -  v3[ 2 -  v3[ 3 -  v3[ 4 <<   ' \n ' ;
  
for (size_t i  =   0 ; i  <  SSZ;  ++ i)
    std::cout 
<<  i  <<   " "   <<  std::setw(SSZ)  <<  v4[i]  <<   " ,    " ;
  std::cout 
<<   " other:  "   <<  std::setw(SSZ)
            
<<  v4.size()  -  v4[ 0 -  v4[ 1 -  v4[ 2 -  v4[ 3 -  v4[ 4 <<   ' \n ' ;
  system(
" pause " );
}


// 做速度测试
#include 
#include 
#include 
#include 
#include "random.hpp"

int main()
{
   const size_t SZ = 1 << 27;
  std::cout << "generating random numbers in progress  \n";
  std::cout << SZ << " random numbers generated.\n";
  std::cout << "random used: ";
  Sleep(1000);
  std::clock_t time = clock();
   for(size_t i = 0; i < SZ; ++i)
    irand();
  std::cout << clock() - time << "ms, ";

  std::cout << "rand() used: ";
  Sleep(1000);
  std::srand(std::time(0));
  std::clock_t t = clock();
   for(size_t i = 0; i < SZ; ++i)
    std::rand();
  std::cout << clock() - t << "ms\n";

  std::system("PAUSE");
   return 0;
}

二、梅森旋转法

如果需要高质量的伪随机数,内存充足(约2kb),Mersenne twister算法是个不错的选择。Mersenne twister产生随机数的质量几乎超过任何LCG。不过一般Mersenne twister的实现使用LCG产生种子。
Mersenne twister是Makoto Matsumoto (松本)和Takuji Nishimura (西村)于1997年开发的伪随机数产生器,基于有限二进制字段上的矩阵线性再生。可以快速产生高质量的伪随机数,修正了古老随机数产生算法的很多缺陷。Mersenne twister这个名字来自周期长度通常取Mersenne质数这样一个事实。常见的有两个变种Mersenne Twister MT19937和Mersenne Twister MT19937-64。
Mersenne Twister有很多长处,例如:周期2^19937 - 1对于一般的应用来说,足够大了,序列关联比较小,能通过很多随机性测试。
关于Mersenne Twister比较详细的论述请参阅http://www.cppblog.com/Chipset/archive/2009/01/19/72330.html

梅森旋转算法(Mersenne twister)是一个伪随机数发生算法。由松本真和西村拓士[1]在1997年开发,基于有限二进制字段上的矩阵线性递归F_{2}。可以快速产生高质量的伪随机数, 修正了古典随机数发生算法的很多缺陷。

 

梅森旋转算法是R,Python,Ruby,IDL,Free Pascal,PHP,Maple,Matlab,GMP和GSL的默认伪随机数产生器。从C++11开始,C++也可以使用这种算法。在Boost C++,Glib和NAG数值库中,作为插件提供。 在SPSS中,梅森选旋转算法是两个PRNG中的一个:另一个是产生器仅仅为保证旧程序的兼容性,梅森旋转被描述为”更加可靠“。梅森旋转在SAS中同样是PRNG中的一个,另一个产生器是旧时的且已经被弃用。

 

最为广泛使用Mersenne Twister的一种变体是MT19937,可以产生32位整数序列。具有以下的优点:

有219937 − 1的非常长的周期。在许多软件包中的短周期—232 随机数产生器在一个长周期中不能保证生成随机数的质量。[2]
在1 ≤ k ≤ 623的维度之间都可以均等分布(参见定义).
除了在统计学意义上的不正确的随机数生成器以外, 在所有伪随机数生成器法中是最快的(当时)[3]


一种实现版本如下:
  1  // ************************************************************************
  2  //   This is a slightly modified version of Equamen mersenne twister.
  3  //
  4  //   Copyright (C) 2009 Chipset
  5  //
  6  //   This program is free software: you can redistribute it and/or modify
  7  //   it under the terms of the GNU Affero General Public License as
  8  //   published by the Free Software Foundation, either version 3 of the
  9  //   License, or (at your option) any later version.
 10  //
 11  //   but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 13  //   GNU Affero General Public License for more details.
 14  //
 15  //   You should have received a copy of the GNU Affero General Public License
 16  //   along with this program. If not, see < http://www.gnu.org/licenses/ >.
 17  // ************************************************************************
 18 
 19  //  Original Coyright (c) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura
 20  //
 21  //  Functions for MT19937, with initialization improved 2002/2/10.
 22  //  Coded by Takuji Nishimura and Makoto Matsumoto.
 23  //  This is a faster version by taking Shawn Cokus's optimization,
 24  //  Matthe Bellew's simplification, Isaku Wada's real version.
 25  //  C++ version by Lyell Haynes (Equamen)
 26  //
 27  //  Redistribution and use in source and binary forms, with or without
 28  //  modification, are permitted provided that the following conditions
 29  //  are met:
 30  //
 31  //  1. Redistributions of source code must retain the above copyright
 32  //     notice, this list of conditions and the following disclaimer.
 33  //
 34  //  2. Redistributions in binary form must reproduce the above copyright
 35  //     notice, this list of conditions and the following disclaimer in the
 36  //     documentation and/or other materials provided with the distribution.
 37  //
 38  //  3. The names of its contributors may not be used to endorse or promote
 39  //     products derived from this software without specific prior written
 40  //     permission.
 41  //
 42  //  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 43  //  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 44  //  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 45  //  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 46  //  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 47  //  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 48  //  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 49  //  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 50  //  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 51  //  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 52  //  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 53  //
 54 
 55 #ifndef mtrandom_HPP_
 56  #define mtrandom_HPP_
 57 
 58 #include 
 59 
 60  class mtrandom
 61 {
 62  public:
 63     mtrandom() : left(1) { init(); }
 64 
 65      explicit mtrandom(size_t seed) : left(1) {    init(seed);    }
 66 
 67     mtrandom(size_t* init_key,  int key_length) : left(1)
 68     {
 69          int i = 1, j = 0;
 70          int k = N > key_length ? N : key_length;
 71         init();
 72          for(; k; --k)
 73         {
 74             state[i]  =  (state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1664525UL))+ init_key[j] + j;  //  non linear
 75              state[i] &=  4294967295UL;  //  for WORDSIZE > 32 machines
 76              ++i;
 77             ++j;
 78              if(i >= N)
 79             {
 80                 state[0] = state[N - 1];
 81                 i = 1;
 82             }
 83              if(j >= key_length)
 84                 j = 0;
 85         }
 86 
 87          for(k = N - 1; k; --k)
 88         {
 89             state[i] = (state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1566083941UL)) - i;  //  non linear
 90              state[i] &= 4294967295UL;  //  for WORDSIZE > 32 machines
 91              ++i;
 92              if(i >= N)
 93             {
 94                 state[0] = state[N - 1];
 95                 i = 1;
 96             }
 97         }
 98 
 99         state[0]  =  2147483648UL;  //  MSB is 1; assuring non-zero initial array
100      }
101 
102      void reset(size_t rs)
103     {
104         init(rs);
105         next_state();
106     }
107 
108     size_t rand()
109     {
110         size_t y;
111          if(0 == --left)
112             next_state();
113         y  = *next++;
114          //  Tempering
115          y ^= (y >> 11);
116         y ^= (y << 7) & 0x9d2c5680UL;
117         y ^= (y << 15) & 0xefc60000UL;
118         y ^= (y >> 18);
119          return y;
120     }
121 
122      double real()    {     return ( double)rand() / -1UL;    }
123 
124          //  generates a random number on [0,1) with 53-bit resolution
125       double res53()
126     {
127         size_t a = rand() >> 5, b = rand() >> 6;
128          return (a * 67108864.0 + b) / 9007199254740992.0;
129     }
130 
131  private:
132      void init(size_t seed = 19650218UL)
133     {
134         state[0] =  seed & 4294967295UL;
135          for( int j = 1; j < N; ++j)
136         {
137             state[j]  =  (1812433253UL * (state[j - 1] ^ (state[j - 1]  >>  30)) + j);
138              //  See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier.
139               //  In the previous versions, MSBs of the seed affect
140               //  only MSBs of the array state[].
141               //  2002/01/09 modified by Makoto Matsumoto
142              state[j] &=  4294967295UL;   //  for >32 bit machines
143          }
144     }
145 
146      void next_state()
147     {
148         size_t* p = state;
149          int i;
150 
151          for(i = N - M + 1; --i; ++p)
152             *p = (p[M] ^ twist(p[0], p[1]));
153 
154          for(i = M; --i; ++p)
155             *p = (p[M - N] ^ twist(p[0], p[1]));
156         *p = p[M - N] ^ twist(p[0], state[0]);
157         left = N;
158         next = state;
159     }
160 
161     size_t mixbits(size_t u, size_t v)  const
162     {
163          return (u & 2147483648UL) | (v & 2147483647UL);
164     }
165 
166     size_t twist(size_t u, size_t v)  const
167     {
168          return ((mixbits(u, v)  >>  1) ^ (v & 1UL ? 2567483615UL : 0UL));
169     }
170 
171      static  const  int N = 624, M = 397;
172     size_t state[N];
173     size_t left;
174     size_t* next;
175 };
176 
177  class mtrand_help
178 {
179    static mtrandom r;
180  public:
181   mtrand_help() {}
182    void  operator()(size_t s) { r.reset(s); }
183   size_t  operator()()  const {  return r.rand(); }
184    double  operator()( double) {  return r.real(); }
185 };
186 mtrandom mtrand_help:: r;
187 
188  extern  void mtsrand(size_t s) { mtrand_help()(s); }
189  extern size_t mtirand() {  return mtrand_help()(); }
190  extern  double mtdrand() {  return mtrand_help()(1.0); }
191 
192  #endif  //  mtrandom_HPP_
193 


  1  // ************************************************************************
  2  //   This is a slightly modified version of Equamen mersenne twister.
  3  //
  4  //   Copyright (C) 2009 Chipset
  5  //
  6  //   This program is free software: you can redistribute it and/or modify
  7  //   it under the terms of the GNU Affero General Public License as
  8  //   published by the Free Software Foundation, either version 3 of the
  9  //   License, or (at your option) any later version.
 10  //
 11  //   but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 13  //   GNU Affero General Public License for more details.
 14  //
 15  //   You should have received a copy of the GNU Affero General Public License
 16  //   along with this program. If not, see < http://www.gnu.org/licenses/ >.
 17  // ************************************************************************
 18 
 19  //  Original Coyright (c) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura
 20  //
 21  //  Functions for MT19937, with initialization improved 2002/2/10.
 22  //  Coded by Takuji Nishimura and Makoto Matsumoto.
 23  //  This is a faster version by taking Shawn Cokus's optimization,
 24  //  Matthe Bellew's simplification, Isaku Wada's real version.
 25  //  C++ version by Lyell Haynes (Equamen)
 26  //
 27  //  Redistribution and use in source and binary forms, with or without
 28  //  modification, are permitted provided that the following conditions
 29  //  are met:
 30  //
 31  //  1. Redistributions of source code must retain the above copyright
 32  //     notice, this list of conditions and the following disclaimer.
 33  //
 34  //  2. Redistributions in binary form must reproduce the above copyright
 35  //     notice, this list of conditions and the following disclaimer in the
 36  //     documentation and/or other materials provided with the distribution.
 37  //
 38  //  3. The names of its contributors may not be used to endorse or promote
 39  //     products derived from this software without specific prior written
 40  //     permission.
 41  //
 42  //  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 43  //  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 44  //  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 45  //  A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 46  //  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 47  //  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 48  //  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 49  //  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 50  //  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 51  //  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 52  //  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 53  //
 54 
 55 #ifndef mtrandom_HPP_
 56  #define mtrandom_HPP_
 57 
 58 #include 
 59 
 60  class mtrandom
 61 {
 62  public:
 63     mtrandom() : left(1) { init(); }
 64 
 65      explicit mtrandom(size_t seed) : left(1) {    init(seed);    }
 66 
 67     mtrandom(size_t* init_key,  int key_length) : left(1)
 68     {
 69          int i = 1, j = 0;
 70          int k = N > key_length ? N : key_length;
 71         init();
 72          for(; k; --k)
 73         {
 74             state[i]  =  (state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1664525UL))+ init_key[j] + j;  //  non linear
 75              state[i] &=  4294967295UL;  //  for WORDSIZE > 32 machines
 76              ++i;
 77             ++j;
 78              if(i >= N)
 79             {
 80                 state[0] = state[N - 1];
 81                 i = 1;
 82             }
 83              if(j >= key_length)
 84                 j = 0;
 85         }
 86 
 87          for(k = N - 1; k; --k)
 88         {
 89             state[i] = (state[i] ^ ((state[i - 1] ^ (state[i - 1] >> 30)) * 1566083941UL)) - i;  //  non linear
 90              state[i] &= 4294967295UL;  //  for WORDSIZE > 32 machines
 91              ++i;
 92              if(i >= N)
 93             {
 94                 state[0] = state[N - 1];
 95                 i = 1;
 96             }
 97         }
 98 
 99         state[0]  =  2147483648UL;  //  MSB is 1; assuring non-zero initial array
100      }
101 
102      void reset(size_t rs)
103     {
104         init(rs);
105         next_state();
106     }
107 
108     size_t rand()
109     {
110         size_t y;
111          if(0 == --left)
112             next_state();
113         y  = *next++;
114          //  Tempering
115          y ^= (y >> 11);
116         y ^= (y << 7) & 0x9d2c5680UL;
117         y ^= (y << 15) & 0xefc60000UL;
118         y ^= (y >> 18);
119          return y;
120     }
121 
122      double real()    {     return ( double)rand() / -1UL;    }
123 
124          //  generates a random number on [0,1) with 53-bit resolution
125       double res53()
126     {
127         size_t a = rand() >> 5, b = rand() >> 6;
128          return (a * 67108864.0 + b) / 9007199254740992.0;
129     }
130 
131  private:
132      void init(size_t seed = 19650218UL)
133     {
134         state[0] =  seed & 4294967295UL;
135          for( int j = 1; j < N; ++j)
136         {
137             state[j]  =  (1812433253UL * (state[j - 1] ^ (state[j - 1]  >>  30)) + j);
138              //  See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier.
139               //  In the previous versions, MSBs of the seed affect
140               //  only MSBs of the array state[].
141               //  2002/01/09 modified by Makoto Matsumoto
142              state[j] &=  4294967295UL;   //  for >32 bit machines
143          }
144     }
145 
146      void next_state()
147     {
148         size_t* p = state;
149          int i;
150 
151          for(i = N - M + 1; --i; ++p)
152             *p = (p[M] ^ twist(p[0], p[1]));
153 
154          for(i = M; --i; ++p)
155             *p = (p[M - N] ^ twist(p[0], p[1]));
156         *p = p[M - N] ^ twist(p[0], state[0]);
157         left = N;
158         next = state;
159     }
160 
161     size_t mixbits(size_t u, size_t v)  const
162     {
163          return (u & 2147483648UL) | (v & 2147483647UL);
164     }
165 
166     size_t twist(size_t u, size_t v)  const
167     {
168          return ((mixbits(u, v)  >>  1) ^ (v & 1UL ? 2567483615UL : 0UL));
169     }
170 
171      static  const  int N = 624, M = 397;
172     size_t state[N];
173     size_t left;
174     size_t* next;
175 };
176 
177  class mtrand_help
178 {
179    static mtrandom r;
180  public:
181   mtrand_help() {}
182    void  operator()(size_t s) { r.reset(s); }
183   size_t  operator()()  const {  return r.rand(); }
184    double  operator()( double) {  return r.real(); }
185 };
186 mtrandom mtrand_help:: r;
187 
188  extern  void mtsrand(size_t s) { mtrand_help()(s); }
189  extern size_t mtirand() {  return mtrand_help()(); }
190  extern  double mtdrand() {  return mtrand_help()(1.0); }
191 
192  #endif  //  mtrandom_HPP_
193 

你可能感兴趣的:(算法)