Categories
iOS Swift

Random unification in Swift 4.2

In the beginning of this year I blogged about how to generate random float and integers. Meanwhile, SE-0202 “Random Unification” got implemented in Swift 4.2 making my additions unnecessary. Let’s take a look how to use new API for getting random numbers.

Random integers, floats and booleans

In my own implementation I was extending range with a function named random(). Swift 4.2 took different path. Instead, it adds functions like static func random(in range: Range, using generator: inout T) -> UInt64 where T : RandomNumberGenerator to FixedWidthInteger, BinaryFloatingPoint and Bool. By default, SystemRandomNumberGenerator with cryptographically secure implementation is used as a generator. But for example if it is required to seed the generator, custom type needs to be created. This might be useful in testing where every execution should produce the same results.
In addition to getting random numbers, there is now API for shuffling a collection or getting a random element. As collections can be empty, the randomElement() function returns optional.

let double = Double.random(in: -1.2...4.5)
let integer = Int.random(in: .min ... .max)
let unsignedInteger = UInt.random(in: 4...9)
let bool = Bool.random()
var generator = SystemRandomNumberGenerator()
let double2 = Double.random(in: 1.0..<4.2, using: &generator)
let array = ["Cat", "Cow", "Dog", "Sheep"]
if let element = array.randomElement() {
print(element) // e.g Dog
}
let shuffled = array.shuffled()
print(array, shuffled) // e.g ["Cat", "Cow", "Dog", "Sheep"] ["Dog", "Cow", "Sheep", "Cat"]

Seeded random number generator

As I mentioned before, sometimes it is needed to seed random number generator. Creating a generator what uses a seed is quite simple. First, we need a random number function what supports seeding. Therefore arcrandom() and arcrandom_uniform() are not usable in this use case. What we can use is srand48() for seeding and drand48() for getting a random double in range of 0 to 1. Using this, we can implement the required method in the RandomNumberGenerator protocol.

struct SeededRandomNumberGenerator: RandomNumberGenerator {
init(seed: Int) {
srand48(seed)
}
func next() -> UInt64 {
return UInt64(drand48() * Double(UInt64.max))
}
}
var seededGenerator = SeededRandomNumberGenerator(seed: 5)
let random = Int.random(in: -5...5, using: &seededGenerator)

Summary

We took a look at convenient and flexible APIs for getting and using random numbers in Swift 4.2. In addition, we created a seeded random number generator what might be useful in testing.

Playground

RandomUnification (GitHub) Xcode 10, Swift 4.2

References

SE-0202 (Apple)
RandomNumberGenerator (Apple)
srand48 (linux man pages)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s