Class | Random::MT19937 |
In: |
lib/backports/1.9.2/random/MT19937.rb
lib/backports/1.9.2/random/bits_and_bytes.rb |
Parent: | Object |
Supplement the MT19937 class with methods to do conversions the same way as MRI. No argument checking is done here either.
STATE_SIZE | = | 624 |
LAST_STATE | = | STATE_SIZE - 1 |
PAD_32_BITS | = | 0xffffffff |
LAST_31_BITS | = | 0x7fffffff |
OFFSET | = | 397 |
FLOAT_FACTOR | = | 1.0/9007199254740992.0 |
MASK_BY | = | [1,2,4,8,16] |
# File lib/backports/1.9.2/random/bits_and_bytes.rb, line 78 78: def self.[](seed) 79: new(convert_seed(seed)) 80: 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 65: def self.convert_seed(seed) 66: seed = seed.abs 67: long_values = [] 68: begin 69: long_values << (seed & PAD_32_BITS) 70: seed >>= 32 71: end until seed == 0 72: 73: long_values.pop if long_values[-1] == 1 && long_values.size > 1 # Done to allow any kind of sequence of integers 74: 75: long_values.size > 1 ? long_values : long_values.first 76: end
# File lib/backports/1.9.2/random/bits_and_bytes.rb, line 46 46: def left # It's actually the number of words left + 1, as per MRI... 47: MT19937::STATE_SIZE - @last_read 48: end
# File lib/backports/1.9.2/random/bits_and_bytes.rb, line 50 50: def marshal_dump 51: [state_as_bignum, left] 52: end
# File lib/backports/1.9.2/random/bits_and_bytes.rb, line 54 54: def marshal_load(ary) 55: b, left = ary 56: @last_read = MT19937::STATE_SIZE - left 57: @state = Array.new(STATE_SIZE) 58: STATE_SIZE.times do |i| 59: @state[i] = b & PAD_32_BITS 60: b >>= 32 61: end 62: end
Generates a completely new state out of the previous one.
# File lib/backports/1.9.2/random/MT19937.rb, line 17 17: def next_state 18: STATE_SIZE.times do |i| 19: mix = @state[i] & 0x80000000 | @state[i+1 - STATE_SIZE] & 0x7fffffff 20: @state[i] = @state[i+OFFSET - STATE_SIZE] ^ (mix >> 1) 21: @state[i] ^= 0x9908b0df if mix.odd? 22: end 23: @last_read = -1 24: end
Returns a random Integer from the range 0 … (1 << 32)
# File lib/backports/1.9.2/random/MT19937.rb, line 65 65: def random_32_bits 66: next_state if @last_read >= LAST_STATE 67: @last_read += 1 68: y = @state[@last_read] 69: # Tempering 70: y ^= (y >> 11) 71: y ^= (y << 7) & 0x9d2c5680 72: y ^= (y << 15) & 0xefc60000 73: y ^= (y >> 18) 74: end
# File lib/backports/1.9.2/random/bits_and_bytes.rb, line 32 32: def random_bytes(nb) 33: nb_32_bits = (nb + 3) / 4 34: random = nb_32_bits.times.map { random_32_bits } 35: random.pack("L" * nb_32_bits)[0, nb] 36: 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 9: def random_float 10: ((random_32_bits >> 5) * 67108864.0 + (random_32_bits >> 6)) * FLOAT_FACTOR; 11: end
Returns an integer within 0...upto
# File lib/backports/1.9.2/random/bits_and_bytes.rb, line 14 14: def random_integer(upto) 15: n = upto - 1 16: nb_full_32 = 0 17: while n > PAD_32_BITS 18: n >>= 32 19: nb_full_32 += 1 20: end 21: mask = mask_32_bits(n) 22: begin 23: rand = random_32_bits & mask 24: nb_full_32.times do 25: rand <<= 32 26: rand |= random_32_bits 27: end 28: end until rand < upto 29: rand 30: 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 30: def seed=(seed) 31: case seed 32: when Integer 33: @state = Array.new(STATE_SIZE) 34: @state[0] = seed & PAD_32_BITS 35: (1..LAST_STATE).each do |i| 36: @state[i] = (1812433253 * (@state[i-1] ^ @state[i-1]>>30) + i)& PAD_32_BITS 37: end 38: @last_read = LAST_STATE 39: when Array 40: self.seed = 19650218 41: i=1 42: j=0 43: [STATE_SIZE, seed.size].max.times do 44: @state[i] = (@state[i] ^ (@state[i-1] ^ @state[i-1]>>30) * 1664525) + j + seed[j] & PAD_32_BITS 45: if (i+=1) >= STATE_SIZE 46: @state[0] = @state[-1] 47: i = 1 48: end 49: j = 0 if (j+=1) >= seed.size 50: end 51: (STATE_SIZE-1).times do 52: @state[i] = (@state[i] ^ (@state[i-1] ^ @state[i-1]>>30) * 1566083941) - i & PAD_32_BITS 53: if (i+=1) >= STATE_SIZE 54: @state[0] = @state[-1] 55: i = 1 56: end 57: end 58: @state[0] = 0x80000000 59: else 60: raise ArgumentError, "Seed must be an Integer or an Array" 61: end 62: end