Class: Backports::Random::MT19937
- Defined in:
- lib/backports/random/MT19937.rb,
lib/backports/random/bits_and_bytes.rb
Overview
Supplement the MT19937 class with methods to do conversions the same way as MRI. No argument checking is done here either.
Constant Summary collapse
- STATE_SIZE =
624
- LAST_STATE =
STATE_SIZE - 1
- PAD_32_BITS =
0xffffffff
- LAST_31_BITS =
0x7fffffff
- OFFSET =
397
- FLOAT_FACTOR =
1.0/9007199254740992.0
Class Method Summary collapse
- .[](seed) ⇒ Object
-
.convert_seed(seed) ⇒ Object
Convert an Integer seed of arbitrary size to either a single 32 bit integer, or an Array of 32 bit integers.
Instance Method Summary collapse
-
#initialize(seed) ⇒ MT19937
constructor
See seed=.
-
#left ⇒ Object
It’s actually the number of words left + 1, as per MRI…
- #marshal_dump ⇒ Object
- #marshal_load(ary) ⇒ Object
-
#next_state ⇒ Object
Generates a completely new state out of the previous one.
-
#random_32_bits ⇒ Object
Returns a random Integer from the range 0 …
- #random_bytes(nb) ⇒ Object
-
#random_float ⇒ Object
generates a random number on [0,1) with 53-bit resolution.
-
#random_integer(upto) ⇒ Object
Returns an integer within 0…upto.
-
#seed=(seed) ⇒ Object
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).
- #state_as_bignum ⇒ Object
Constructor Details
#initialize(seed) ⇒ MT19937
See seed=
10 11 12 |
# File 'lib/backports/random/MT19937.rb', line 10 def initialize(seed) self.seed = seed end |
Class Method Details
.[](seed) ⇒ Object
79 80 81 |
# File 'lib/backports/random/bits_and_bytes.rb', line 79 def self.[](seed) new(convert_seed(seed)) end |
.convert_seed(seed) ⇒ Object
Convert an Integer seed of arbitrary size to either a single 32 bit integer, or an Array of 32 bit integers
66 67 68 69 70 71 72 73 74 75 76 77 |
# 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 |
Instance Method Details
#left ⇒ Object
It’s actually the number of words left + 1, as per MRI…
47 48 49 |
# 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 ⇒ Object
51 52 53 |
# File 'lib/backports/random/bits_and_bytes.rb', line 51 def marshal_dump [state_as_bignum, left] end |
#marshal_load(ary) ⇒ Object
55 56 57 58 59 60 61 62 63 |
# 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 ⇒ Object
Generates a completely new state out of the previous one.
18 19 20 21 22 23 24 25 |
# 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 ⇒ Object
Returns a random Integer from the range 0 … (1 << 32)
66 67 68 69 70 71 72 73 74 75 |
# 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) ⇒ Object
33 34 35 36 37 |
# 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 ⇒ Object
generates a random number on [0,1) with 53-bit resolution
10 11 12 |
# 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) ⇒ Object
Returns an integer within 0…upto
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# 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) ⇒ Object
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
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 |
# 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 ⇒ Object
39 40 41 42 43 44 45 |
# 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 |