Advertisement
Advertisement


How does one generate a random number in Apple's Swift language?


Question

I realize the Swift book provided an implementation of a random number generator. Is the best practice to copy and paste this implementation in one's own program? Or is there a library that does this that we can use now?

2015/12/29
1
449
12/29/2015 6:08:33 AM

Accepted Answer

Swift 4.2+

Swift 4.2 shipped with Xcode 10 introduces new easy-to-use random functions for many data types. You can call the random() method on numeric types.

let randomInt = Int.random(in: 0..<6)
let randomDouble = Double.random(in: 2.71828...3.14159)
let randomBool = Bool.random()
2019/07/19
478
7/19/2019 12:53:13 AM


Edit: Updated for Swift 3.0

arc4random works well in Swift, but the base functions are limited to 32-bit integer types (Int is 64-bit on iPhone 5S and modern Macs). Here's a generic function for a random number of a type expressible by an integer literal:

public func arc4random<T: ExpressibleByIntegerLiteral>(_ type: T.Type) -> T {
    var r: T = 0
    arc4random_buf(&r, MemoryLayout<T>.size)
    return r
}

We can use this new generic function to extend UInt64, adding boundary arguments and mitigating modulo bias. (This is lifted straight from arc4random.c)

public extension UInt64 {
    public static func random(lower: UInt64 = min, upper: UInt64 = max) -> UInt64 {
        var m: UInt64
        let u = upper - lower
        var r = arc4random(UInt64.self)

        if u > UInt64(Int64.max) {
            m = 1 + ~u
        } else {
            m = ((max - (u * 2)) + 1) % u
        }

        while r < m {
            r = arc4random(UInt64.self)
        }

        return (r % u) + lower
    }
}

With that we can extend Int64 for the same arguments, dealing with overflow:

public extension Int64 {
    public static func random(lower: Int64 = min, upper: Int64 = max) -> Int64 {
        let (s, overflow) = Int64.subtractWithOverflow(upper, lower)
        let u = overflow ? UInt64.max - UInt64(~s) : UInt64(s)
        let r = UInt64.random(upper: u)

        if r > UInt64(Int64.max)  {
            return Int64(r - (UInt64(~lower) + 1))
        } else {
            return Int64(r) + lower
        }
    }
}

To complete the family...

private let _wordSize = __WORDSIZE

public extension UInt32 {
    public static func random(lower: UInt32 = min, upper: UInt32 = max) -> UInt32 {
        return arc4random_uniform(upper - lower) + lower
    }
}

public extension Int32 {
    public static func random(lower: Int32 = min, upper: Int32 = max) -> Int32 {
        let r = arc4random_uniform(UInt32(Int64(upper) - Int64(lower)))
        return Int32(Int64(r) + Int64(lower))
    }
}

public extension UInt {
    public static func random(lower: UInt = min, upper: UInt = max) -> UInt {
        switch (_wordSize) {
            case 32: return UInt(UInt32.random(UInt32(lower), upper: UInt32(upper)))
            case 64: return UInt(UInt64.random(UInt64(lower), upper: UInt64(upper)))
            default: return lower
        }
    }
}

public extension Int {
    public static func random(lower: Int = min, upper: Int = max) -> Int {
        switch (_wordSize) {
            case 32: return Int(Int32.random(Int32(lower), upper: Int32(upper)))
            case 64: return Int(Int64.random(Int64(lower), upper: Int64(upper)))
            default: return lower
        }
    }
}

After all that, we can finally do something like this:

let diceRoll = UInt64.random(lower: 1, upper: 7)
2016/09/07

Edit for Swift 4.2

Starting in Swift 4.2, instead of using the imported C function arc4random_uniform(), you can now use Swift’s own native functions.

// Generates integers starting with 0 up to, and including, 10
Int.random(in: 0 ... 10)

You can use random(in:) to get random values for other primitive values as well; such as Int, Double, Float and even Bool.

Swift versions < 4.2

This method will generate a random Int value between the given minimum and maximum

func randomInt(min: Int, max: Int) -> Int {
    return min + Int(arc4random_uniform(UInt32(max - min + 1)))
}
2018/10/13

I used this code:

var k: Int = random() % 10;
2015/04/21

As of iOS 9, you can use the new GameplayKit classes to generate random numbers in a variety of ways.

You have four source types to choose from: a general random source (unnamed, down to the system to choose what it does), linear congruential, ARC4 and Mersenne Twister. These can generate random ints, floats and bools.

At the simplest level, you can generate a random number from the system's built-in random source like this:

GKRandomSource.sharedRandom().nextInt()

That generates a number between -2,147,483,648 and 2,147,483,647. If you want a number between 0 and an upper bound (exclusive) you'd use this:

GKRandomSource.sharedRandom().nextIntWithUpperBound(6)

GameplayKit has some convenience constructors built in to work with dice. For example, you can roll a six-sided die like this:

let d6 = GKRandomDistribution.d6()
d6.nextInt()

Plus you can shape the random distribution by using things like GKShuffledDistribution. That takes a little more explaining, but if you're interested you can read my tutorial on GameplayKit random numbers.

2015/07/03

You can do it the same way that you would in C:

let randomNumber = arc4random()

randomNumber is inferred to be of type UInt32 (a 32-bit unsigned integer)

2014/06/03