1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
|
module Backports
class Random
# An implementation of Mersenne Twister MT19937 in Ruby
class MT19937
STATE_SIZE = 624
LAST_STATE = STATE_SIZE - 1
PAD_32_BITS = 0xffffffff
# See seed=
def initialize(seed)
self.seed = seed
end
LAST_31_BITS = 0x7fffffff
OFFSET = 397
# Generates a completely new state out of the previous one.
def next_state
STATE_SIZE.times do |i|
mix = @state[i] & 0x80000000 | @state[i+1 - STATE_SIZE] & 0x7fffffff
@state[i] = @state[i+OFFSET - STATE_SIZE] ^ (mix >> 1)
@state[i] ^= 0x9908b0df if mix.odd?
end
@last_read = -1
end
# Seed must be either an Integer (only the first 32 bits will be used)
# or an Array of Integers (of which only the first 32 bits will be used)
#
# No conversion or type checking is done at this level
def seed=(seed)
case seed
when Integer
@state = Array.new(STATE_SIZE)
@state[0] = seed & PAD_32_BITS
(1..LAST_STATE).each do |i|
@state[i] = (1812433253 * (@state[i-1] ^ @state[i-1]>>30) + i)& PAD_32_BITS
end
@last_read = LAST_STATE
when Array
self.seed = 19650218
i=1
j=0
[STATE_SIZE, seed.size].max.times do
@state[i] = (@state[i] ^ (@state[i-1] ^ @state[i-1]>>30) * 1664525) + j + seed[j] & PAD_32_BITS
if (i+=1) >= STATE_SIZE
@state[0] = @state[-1]
i = 1
end
j = 0 if (j+=1) >= seed.size
end
(STATE_SIZE-1).times do
@state[i] = (@state[i] ^ (@state[i-1] ^ @state[i-1]>>30) * 1566083941) - i & PAD_32_BITS
if (i+=1) >= STATE_SIZE
@state[0] = @state[-1]
i = 1
end
end
@state[0] = 0x80000000
else
raise ArgumentError, "Seed must be an Integer or an Array"
end
end
# Returns a random Integer from the range 0 ... (1 << 32)
def random_32_bits
next_state if @last_read >= LAST_STATE
@last_read += 1
y = @state[@last_read]
# Tempering
y ^= (y >> 11)
y ^= (y << 7) & 0x9d2c5680
y ^= (y << 15) & 0xefc60000
y ^= (y >> 18)
end
end
end
end
|