How not to generate deterministic random numbers in Swift

Deterministic and random are opposites but sometimes we want a way to generate and reproduce the same sequence of random numbers when a program is run. Swift language is now more than 8 years in the making but still does not provide a seedable PRNG (pseudo random number generator) out of the box. There is no way for a programmer to set the seed of the PRNG that comes with Swift. So we have to resort to other methods. One of the top results that came in my search to create a seedable random number generator was this link:

struct RandomNumberGeneratorWithSeed: RandomNumberGenerator {
    init(seed: Int) {
        // Set the random seed
        srand48(seed)
    }
    
    func next() -> UInt64 {
        // drand48() returns a Double, transform to UInt64
        return withUnsafeBytes(of: drand48()) { bytes in
            bytes.load(as: UInt64.self)
        }
    }
}

It works by using the drand48 system function to get a random number and calls srand48 to set drand48‘s seed. So far so good. We can wrap it in a class like so:

class Random {

var rnd: RandomNumberGeneratorWithSeed

init(_ seed: Int) {
    // Set the random seed
    rnd = RandomNumberGeneratorWithSeed(seed)
}    

func nextFloat() -> Float {
    return Float.random(in: 0..<1, using: &rnd)
}

func nextDouble() -> Double {
    return Double.random(in: 0..<1, using: &rnd)
}

func next(_ x: UInt) -> UInt {
    return UInt.random(in: 0..<x, using: &rnd)
}

func nextInt() -> Int {
    return Int.random(in: Int.min..<Int.max, using: &rnd)
}
}

There are at least 3 problems with this class:

1. Try following code:

let seed = Int.random(in: Int.min..<Int.max)
let random = Random(seed)
for i in 0..<10 {
    print(random.next(4))
}

You just get a sequence of 0s. Why?

2. Create instances of more than one Random in your app and see how it goes. Since both instances depend on the same drand48 they are not isolated.

3. The third problem is this:

Note

The algorithm used to create random values may change in a future version of Swift. If you’re passing a generator that results in the same sequence of integer values each time you run your program, that sequence may change when your program is compiled using a different version of Swift.

I won’t give out the solution here but this not how you should be generating deterministic random numbers in Swift.

This entry was posted in Computers, programming, Software and tagged . Bookmark the permalink.

Leave a comment