Supplement the MT19937 class with methods to do conversions the same way as MRI. No argument checking is done here either.
An implementation of Mersenne Twister MT19937 in Ruby
# File lib/backports/1.9.2/random/bits_and_bytes.rb, line 78 def self.[](seed) new(convert_seed(seed)) end
Convert an Integer seed of arbitrary size to either a single 32 bit integer, or an Array of 32 bit integers
# File lib/backports/1.9.2/random/bits_and_bytes.rb, line 65 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
See seed=
# File lib/backports/1.9.2/random/MT19937.rb, line 9 def initialize(seed) self.seed = seed end
# File lib/backports/1.9.2/random/bits_and_bytes.rb, line 46 def left # It's actually the number of words left + 1, as per MRI... MT19937::STATE_SIZE - @last_read end
# File lib/backports/1.9.2/random/bits_and_bytes.rb, line 50 def marshal_dump [state_as_bignum, left] end
# File lib/backports/1.9.2/random/bits_and_bytes.rb, line 54 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
Generates a completely new state out of the previous one.
# File lib/backports/1.9.2/random/MT19937.rb, line 17 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
Returns a random Integer from the range 0 ... (1 << 32)
# File lib/backports/1.9.2/random/MT19937.rb, line 65 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
# File lib/backports/1.9.2/random/bits_and_bytes.rb, line 32 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
generates a random number on [0,1) with 53-bit resolution
# File lib/backports/1.9.2/random/bits_and_bytes.rb, line 9 def random_float ((random_32_bits >> 5) * 67108864.0 + (random_32_bits >> 6)) * FLOAT_FACTOR; end
Returns an integer within 0...upto
# File lib/backports/1.9.2/random/bits_and_bytes.rb, line 14 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 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/1.9.2/random/MT19937.rb, line 30 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
# File lib/backports/1.9.2/random/bits_and_bytes.rb, line 38 def state_as_bignum b = 0 @state.each_with_index do |val, i| b |= val << (32 * i) end b end