RosettaCodeData/Task/Subtractive-generator/Ruby/subtractive-generator.rb

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 }