class Backports::Random::MT19937
An implementation of Mersenne Twister MT19937
in Ruby
Supplement the MT19937
class with methods to do conversions the same way as MRI. No argument checking is done here either.
Constants
- FLOAT_FACTOR
- LAST_31_BITS
- LAST_STATE
- MASK_BY
- OFFSET
- PAD_32_BITS
- STATE_SIZE
Public Class Methods
[](seed)
click to toggle source
# File lib/backports/random/bits_and_bytes.rb, line 79 def self.[](seed) new(convert_seed(seed)) end
convert_seed(seed)
click to toggle source
Convert an Integer
seed of arbitrary size to either a single 32 bit integer, or an Array
of 32 bit integers
# File lib/backports/random/bits_and_bytes.rb, line 66 def self.convert_seed(seed) seed = seed.abs long_values = [] begin long_values << (seed & PAD_32_BITS) seed >>= 32 end until seed == 0 long_values.pop if long_values[-1] == 1 && long_values.size > 1 # Done to allow any kind of sequence of integers long_values.size > 1 ? long_values : long_values.first end
new(seed)
click to toggle source
See seed=
# File lib/backports/random/MT19937.rb, line 10 def initialize(seed) self.seed = seed end
Public Instance Methods
left()
click to toggle source
# File lib/backports/random/bits_and_bytes.rb, line 47 def left # It's actually the number of words left + 1, as per MRI... MT19937::STATE_SIZE - @last_read end
marshal_dump()
click to toggle source
# File lib/backports/random/bits_and_bytes.rb, line 51 def marshal_dump [state_as_bignum, left] end
marshal_load(ary)
click to toggle source
# File lib/backports/random/bits_and_bytes.rb, line 55 def marshal_load(ary) b, left = ary @last_read = MT19937::STATE_SIZE - left @state = Array.new(STATE_SIZE) STATE_SIZE.times do |i| @state[i] = b & PAD_32_BITS b >>= 32 end end
next_state()
click to toggle source
Generates a completely new state out of the previous one.
# File lib/backports/random/MT19937.rb, line 18 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
random_32_bits()
click to toggle source
Returns a random Integer
from the range 0 … (1 << 32)
# File lib/backports/random/MT19937.rb, line 66 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
random_bytes(nb)
click to toggle source
# File lib/backports/random/bits_and_bytes.rb, line 33 def random_bytes(nb) nb_32_bits = (nb + 3) / 4 random = nb_32_bits.times.map { random_32_bits } random.pack("L" * nb_32_bits)[0, nb] end
random_float()
click to toggle source
generates a random number on [0,1) with 53-bit resolution
# File lib/backports/random/bits_and_bytes.rb, line 10 def random_float ((random_32_bits >> 5) * 67108864.0 + (random_32_bits >> 6)) * FLOAT_FACTOR; end
random_integer(upto)
click to toggle source
Returns an integer within 0…upto
# File lib/backports/random/bits_and_bytes.rb, line 15 def random_integer(upto) n = upto - 1 nb_full_32 = 0 while n > PAD_32_BITS n >>= 32 nb_full_32 += 1 end mask = mask_32_bits(n) begin rand = random_32_bits & mask nb_full_32.times do rand <<= 32 rand |= random_32_bits end end until rand < upto rand end
seed=(seed)
click to toggle source
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
# File lib/backports/random/MT19937.rb, line 31 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
state_as_bignum()
click to toggle source
# File lib/backports/random/bits_and_bytes.rb, line 39 def state_as_bignum b = 0 @state.each_with_index do |val, i| b |= val << (32 * i) end b end
Private Instance Methods
mask_32_bits(n)
click to toggle source
# File lib/backports/random/bits_and_bytes.rb, line 85 def mask_32_bits(n) MASK_BY.each do |shift| n |= n >> shift end n end