Mersenne Twister in python

时间:2017-03-28 18:17:02

标签: python random hex code-translation

为了更好地理解Mersenne Twister(MT),我决定将其转换为python。 Here您可以运行代码并在底部查看注释的C源代码。

代码运行但我没有得到预期的输出。基于C输出here我应该得到的第一个数字是1067595299 955945823 477289528 4107218783 4228976476,但我得到了2594155707 3648022958 667752806 3967333545 3535325493

旁注:

我在SO上找到了另一个实现,说他们得到了与C here相同的输出,但当我在python2python3中运行它时(xrange->范围,十六进制没有L) )输出也不匹配预期的Cs,它给出0.817330 0.999061 0.510354 0.131533 0.035416而不是预期的0.76275443 0.99000644 0.98670464 0.10143112 0.27933125。 ...如果您想知道更改我的代码以在[0,1)间隔中给出结果,则0.6039989429991692 0.8493715333752334 0.15547331562265754 0.9237168228719383 0.823132110061124也会与这两个结果不同。

为什么这个python代码没有提供与C代码相同的输出?我错误地实施了什么吗?

代码:

class RandomGenerators:
  # period parameters
  N = 624
  M = 394
  MATRIX_A = 0x9908b0df    # constant vector a
  UPPER_MASK = 0x80000000  # most significant w-r bits
  LOWER_MASK = 0x7fffffff  # least significant r bits

  def __init__(self):
    self.mt = [None]
    self.mti = self.N + 1

  '''
  initialize by an array with array-length
  init_key is the array for initializing keys
  key_length is its length
  slight change for C++, 2004/2/26
  '''
  def init_by_array(self, init_key, key_length):
    #int i, j, k;
    self.init_genrand(19650218)
    i,j = 1,0
    k = self.N if self.N > key_length else key_length
    #k = (self.N > key_length ? self.N : key_length)
    #for (; k; k--) {
    while k > 0:
      self.mt[i] = (self.mt[i] ^ ((self.mt[i-1] ^ (self.mt[i-1] >> 30)) * 1664525)) + init_key[j] + j # non linear 
      self.mt[i] &= 0xffffffff # for WORDSIZE > 32 machines 
      i+=1
      j+=1
      if i >= self.N:
        self.mt[0] = self.mt[self.N-1]
        i = 1
      if j >= key_length:
        j = 0
      k-=1

    k = self.N-1
    #for (k=N-1; k; k--) {
    while k > 0:
      self.mt[i] = (self.mt[i] ^ ((self.mt[i-1] ^ (self.mt[i-1] >> 30)) * 1566083941)) - i # non linear 
      self.mt[i] &= 0xffffffff # for WORDSIZE > 32 machines 
      i += 1
      if i >= self.N:
        self.mt[0] = self.mt[self.N-1]
        i=1
      k-=1

    self.mt[0] = 0x80000000 # MSB is 1; assuring non-zero initial array

  # initializes mt[N] with a seed
  def init_genrand(self,s):
    self.mt[0] = s & 0xffffffff
    self.mti = 1
    while self.mti < self.N:
      self.mt.append(1812433253 * (self.mt[self.mti-1] ^ (self.mt[self.mti - 1] >> 30)) + self.mti)
      self.mt[self.mti] &= 0xffffffff
      self.mti += 1

  # generates a random number on [0,0xffffffff]-interval
  def genrand_int32(self):
    y = 0
    mag01=[0x0, self.MATRIX_A]
    if self.mti >= self.N: # generate N words at one time
      kk = 0
      if self.mti == self.N + 1: # if init_genrand() has not been called,
        self.init_genrand(5489) # a default initial seed is used

      while kk < self.N - self.M:
        y = (self.mt[kk] & self.UPPER_MASK) | (self.mt[kk+1] & self.LOWER_MASK)
        self.mt[kk] = self.mt[kk+self.M] ^ (y >> 1) ^ mag01[y & 0x1]
        kk += 1

      while kk < self.N - 1:
        y = (self.mt[kk] & self.UPPER_MASK) | (self.mt[kk+1] & self.LOWER_MASK)
        self.mt[kk] = self.mt[kk+(self.M-self.N)] ^ (y >> 1) ^ mag01[y & 0x1]
        kk += 1

      y = (self.mt[self.N-1] & self.UPPER_MASK) | (self.mt[0] & self.LOWER_MASK)
      self.mt[self.N-1] = self.mt[self.M-1] ^ (y >> 1) ^ mag01[y & 0x1]

      self.mti = 0

    y = self.mt[self.mti]
    self.mti += 1

    # Tempering 
    y ^= (y >> 11)
    y ^= (y << 7) & 0x9d2c5680
    y ^= (y << 15) & 0xefc60000
    y ^= (y >> 18)

    return y

  # generates a random number on [0,0x7fffffff]-interval 
  def genrand_int31(self):
    #return (long)(genrand_int32() >> 1)
    return (self.genrand_int32() >> 1)

  # generates a random number on [0,1]-real-interval 
  def genrand_real1(self):
    return self.genrand_int32() * (1.0 / 4294967295.0)
    # divided by 2^32-1 

  # generates a random number on [0,1)-real-interval 
  def genrand_real2(self):
    return self.genrand_int32() * (1.0 / 4294967296.0)
    # divided by 2^32 

  # generates a random number on (0,1)-real-interval 
  def genrand_real3(self):
    return ((self.genrand_int32()) + 0.5) * (1.0 / 4294967296.0)
    # divided by 2^32 

  # generates a random number on [0,1) with 53-bit resolution
  def genrand_res53(self):
    a, b = self.genrand_int32()>>5, self.genrand_int32()>>6 
    return(a * 67108864.0 + b) * (1.0 / 9007199254740992.0)

r = RandomGenerators()
init = [0x123, 0x234, 0x345, 0x456]
length = 4
r.init_by_array(init, length)
for i in range(10):
  print('mt: '+str(r.genrand_int32()))

- 编辑 -

mt[]值未正确初始化。调用init_by_array后,C中的前几个值是:

-2147483648
1827812183
1371430253
-735590895

在python中,前几个是:

2147483648
1827812183
1371430253
3559376401

所以似乎问题是正/负十六进制。我修改了init_by_array here下面的代码,但我猜测genrand_int32有类似的问题(我已尝试在最后添加类似的代码,而不是解决问题):

for i,num in enumerate(self.mt):
  if num>=2147483648: # (2**32)/2
    self.mt[i]-=4294967296 # 2**32

0 个答案:

没有答案