# Random Number Generation with Seed

Hello, I am trying to generate random numbers with a seed so that I can have deterministic sequence for reproducibility. I am using the technique provided here: Random Numbers In Swift [+Generate Random Number, Set A Seed]

but it does not seem to work. This is my code:

class MyRandomNumberGenerator: RandomNumberGenerator {
// Random Numbers In Swift [+Generate Random Number, Set A Seed]
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
}
}
``````

}

class Random {

``````var rnd: MyRandomNumberGenerator

init(_ seed: Int) {
// Set the random seed
rnd = MyRandomNumberGenerator(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)
}
``````

}

When I run it like this:

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

I just get a sequence of 0s. Can anyone tell me what is wrong here and how to fix it? Thanks.

This is not a valid conformance to `RandomNumberGenerator`, because it does not produce a uniform random value in `0...UInt64.max`. This is pretty clear if we print a few values in hex in the REPL:

``````1> for _ in 0 ..< 10 {
3. }
3fd465765ea34540
3fec5d9f295dff80
3f8fe9e6a4b2b800
3fe2b0ddf945a2c0
3fc46630ef7b3480
3fd88ecd07503000
3fe61cb534223960
3fae22c169eaf400
3feccb9b42041fa0
3fc4ef12deace200
``````

Because this is not a valid conformance, algorithms that transform its output do not behave as expected. In particular, because the value produced by `next()` is always less than `0x40...`, generating random integers with an upper bound of `4` will always produce zero.

If you really want to build a conforming RNG out of `drand48()` specifically, you can do that as follows:

``````next() -> UInt64 {
UInt64(drand48() * 0x1.0p64) ^ UInt64(drand48() * 0x1.0p16)
}
``````

conducing the very simple test above then yields:

``````e43907dd08417f89
b5c43c88d3634952
dd6ba1ae7855acf0
755f99509397f5aa
c651209e55a96065
3a8817d7a30b5ac2
4ce1a81e343dab75
b80e317bb5bf90e2
d31028a4e81163ff
d19aab41bfb3d810
``````

(Why 0x1.0p64 and 0x1.0p16? Because `drand48()` produces 48 bits scaled to fit in (0,1); multiplying by 2⁶⁴ before conversion gives us a random value filling the high-order 48 bits of the UInt64, multiplying by 2¹⁶ fills the low-order 16 bits (and lets the next 32 bits be chopped off, since conversion to UInt64 throws away any fractional bits).

6 Likes

thanks a lot!