| 
 
| 赞 | 3 |  
| VIP | 4 |  
| 好人卡 | 4 |  
| 积分 | 1 |  
| 经验 | 8941 |  
| 最后登录 | 2015-8-17 |  
| 在线时间 | 182 小时 |  
 Lv1.梦旅人 
	梦石0 星屑50 在线时间182 小时注册时间2012-2-11帖子233 | 
| 
本帖最后由 viktor 于 2012-11-8 14:29 编辑
x
加入我们,或者,欢迎回来。您需要 登录 才可以下载或查看,没有帐号?注册会员  
 嗯……其实ruby1.7以上的srand/rand函数本身就是用的mersenne twister产生的强随机数
 其实ruby1.9自带了Random类,但是XP用的ruby1.81没有
 
 总之 反正照着标准C程序mt19937ar.c抄了一份ruby的,可以制定随机数种子 和初始向量的随机数产生器。
 用法
 mt = MT19937.new(seed)    # seed是随机数种子
 iv = [123, 456, 789, 1234, 5678] ¥ iv是初始向量,想填几个数字都行,自由发挥
 mt.init_array iv # 可以在用种子初始化的基础上,再定义初始向量,增强随机性
 
 随机数:
 mt.randi
 
 另外底下的常数除了birthday是原作者的生日(作者自重)以外其他都不要改了。后果貌似很严重……
 复制代码
#============
# rpg.blue
# Mersenne Twister copycat version.
# original: mt19937ar.c
# author: viktor
#============
class MT19937
  N = 624
  M = 397
  A = 0x9908b0df
  MASK_S32 = 0x7fffffff
  MASK_U32 = 0xffffffff
  PRIMITIVE = 1812433253
  BIRTHDAY = 19650218
  MAGIC = [166_4525, 156_608_3941, 0x9d2c5680, 0xefc60000]
  
  attr_reader :seed
  attr_reader :iv
  def init_mt(s)
    @mt[0] = s & MASK_U32
    N.times{|i|@mt[i+1]=(PRIMITIVE * (@mt[i] ^ (@mt[i] >> 30))+i+1) & MASK_U32}
    @life = N
  end
  
  def init_array(iv)
    @iv = iv    
    i, j = 1, 0
    [iv.length, N].max.times {
      @mt[i] = (@mt[i] ^ (( @mt[i-1] ^ (@mt[i-1] >> 30 )) * MAGIC[0]))
      @mt[i] =(@mt[i]+iv[j]+j) & MASK_U32
      i+=1; j=(j+1) % iv.length
      if i>=N 
        @mt[0] = @mt[N-1] # 折叠数组
        i=1
      end      
    }
    (N-1).times {
      @mt[i] = (@mt[i] ^ (( @mt[i-1] ^ (@mt[i-1] >> 30 )) * MAGIC[1]))
      @mt[i] =(@mt[i]-i) & MASK_U32
      i+=1; if i>=N
        @mt[0] = @mt[N-1]
        i=1
      end
    }
    @mt[0] = 0x80000000
  end
  
  def randi
    if @life >= N
      # start a new round, update table mt
      N.times {|k|
        tmp = (@mt[k] & 0x80000000) | (@mt[(k+1)%N] & MASK_S32)
        @mt[k] = @mt[(k+M)%N] ^ (tmp>>1) ^ (tmp[0]*A)
      }
      @life=0
    end
    ret = @mt[@life]
    ret ^= (ret >> 11);
    ret ^= (ret << 7) & MAGIC[2];
    ret ^= (ret << 15) & MAGIC[3];
    ret ^= (ret >> 18);
    @life+=1
    ret
  end
  
  def initialize(seed=nil)
    @mt=[]
    srand(seed)
  end
  
  def srand(seed=nil)
    last_seed = @seed
    seed = rand(1<<32) if seed==nil
    @seed = seed
    init_mt(@seed)
    return last_seed
  end
end
# test
mt = MT19937.new(MT19937::BIRTHDAY)
iv = [0x123, 0x234, 0x345, 0x456]
mt.init_array iv
out = []
1000.times {out << mt.randi}
p out
 | 
 |