Class: Random::MT19937

Inherits:
Object show all
Defined in:
lib/vendor/backports-3.3.5/lib/backports/extra/random/MT19937.rb,
lib/vendor/backports-3.3.5/lib/backports/extra/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

Instance Method Summary collapse

Constructor Details

#initialize(seed) ⇒ MT19937

See seed=



9
10
11
# File 'lib/vendor/backports-3.3.5/lib/backports/extra/random/MT19937.rb', line 9

def initialize(seed)
  self.seed = seed
end

Class Method Details

.[](seed) ⇒ Object



78
79
80
# File 'lib/vendor/backports-3.3.5/lib/backports/extra/random/bits_and_bytes.rb', line 78

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



65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/vendor/backports-3.3.5/lib/backports/extra/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

Instance Method Details

#leftObject

It’s actually the number of words left + 1, as per MRI…



46
47
48
# File 'lib/vendor/backports-3.3.5/lib/backports/extra/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

#marshal_dumpObject



50
51
52
# File 'lib/vendor/backports-3.3.5/lib/backports/extra/random/bits_and_bytes.rb', line 50

def marshal_dump
  [state_as_bignum, left]
end

#marshal_load(ary) ⇒ Object



54
55
56
57
58
59
60
61
62
# File 'lib/vendor/backports-3.3.5/lib/backports/extra/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

#next_stateObject

Generates a completely new state out of the previous one.



17
18
19
20
21
22
23
24
# File 'lib/vendor/backports-3.3.5/lib/backports/extra/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

#random_32_bitsObject

Returns a random Integer from the range 0 … (1 << 32)



65
66
67
68
69
70
71
72
73
74
# File 'lib/vendor/backports-3.3.5/lib/backports/extra/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

#random_bytes(nb) ⇒ Object



32
33
34
35
36
# File 'lib/vendor/backports-3.3.5/lib/backports/extra/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

#random_floatObject

generates a random number on [0,1) with 53-bit resolution



9
10
11
# File 'lib/vendor/backports-3.3.5/lib/backports/extra/random/bits_and_bytes.rb', line 9

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



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/vendor/backports-3.3.5/lib/backports/extra/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=(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



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
# File 'lib/vendor/backports-3.3.5/lib/backports/extra/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

#state_as_bignumObject



38
39
40
41
42
43
44
# File 'lib/vendor/backports-3.3.5/lib/backports/extra/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