38 lines
1.1 KiB
Ruby
38 lines
1.1 KiB
Ruby
# SubRandom is a subtractive random number generator which generates
|
|
# the same sequences as Bentley's generator, as used in xpat2.
|
|
class SubRandom
|
|
# The original seed of this generator.
|
|
attr_reader :seed
|
|
|
|
# Creates a SubRandom generator with the given _seed_.
|
|
# The _seed_ must be an integer from 0 to 999_999_999.
|
|
def initialize(seed = Kernel.rand(1_000_000_000))
|
|
(0..999_999_999).include? seed or
|
|
raise ArgumentError, "seed not in 0..999_999_999"
|
|
|
|
# @state = 55 elements.
|
|
ary = [seed, 1]
|
|
53.times { ary << ary[-2] - ary[-1] }
|
|
@state = []
|
|
34.step(1870, 34) {|i| @state << ary[i % 55] }
|
|
|
|
220.times { rand } # Discard first 220 elements of sequence.
|
|
|
|
@seed = seed # Save original seed.
|
|
end
|
|
|
|
# Duplicates internal state so SubRandom#dup never shares state.
|
|
def initialize_copy(orig)
|
|
@state = @state.dup
|
|
end
|
|
|
|
# Returns the next random integer, from 0 to 999_999_999.
|
|
def rand
|
|
@state << (@state[-55] - @state[-24]) % 1_000_000_000
|
|
@state.shift
|
|
end
|
|
end
|
|
|
|
rng = SubRandom.new(292929)
|
|
p (1..3).map { rng.rand }
|