Created
May 17, 2020 02:21
-
-
Save nicklockwood/cf1fde3eb24602883c17f94e63e490bc to your computer and use it in GitHub Desktop.
RNG not working as expected
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct RNG: RandomNumberGenerator { | |
let modulus: UInt64 = 233_280 | |
let multiplier: UInt64 = 9301 | |
let increment: UInt64 = 49297 | |
var seed: UInt64 = 0 | |
mutating func next() -> UInt64 { | |
seed = (seed * multiplier + increment) % modulus | |
return seed | |
} | |
} | |
var rng = RNG(seed: 1000) | |
var numbers = [0, 1, 2, 3, 4, 5, 6] | |
print("### next() ###") | |
for _ in 0 ..< 5 { | |
print(rng.next()) | |
} | |
print("### next(upperBound:) ###") | |
for _ in 0 ..< 5 { | |
print(rng.next(upperBound: UInt(numbers.count))) | |
} | |
print("### random(in:) ###") | |
for _ in 0 ..< 5 { | |
print(numbers[Int.random(in: numbers.indices, using: &rng)]) | |
} | |
print("### randomElement() ###") | |
for _ in 0 ..< 5 { | |
print(numbers.randomElement(using: &rng)!) | |
} |
The upperBound usage is consistent with the rest of Swift.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Actually, if you look at https://en.wikipedia.org/wiki/Linear_congruential_generator, at the table column "output bits of seed", you'll see that many PRNGs have the useable bits in the upper area. That's why this Swift class should have a function that returns that "useable range", e.g. as a divisor and a max value, and the upperbound function should use that info to normalize the result from
next()
first, before then applying the reduction for upperBound. It's generally unlikely to expect that all 64 bits of even the standard (system) RNG are all useable.Also, I find the name "upperBound" misleading. Is that term used throughout Swift for "max value plus + 1"? To me, upper bound means max value, without plus 1.