How does one generate a random number in Swift?

SwiftRandom

Swift Problem Overview


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?

Swift Solutions


Solution 1 - Swift

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()

Solution 2 - Swift

Use arc4random_uniform(n) for a random integer between 0 and n-1.

let diceRoll = Int(arc4random_uniform(6) + 1)

Cast the result to Int so you don't have to explicitly type your vars as UInt32 (which seems un-Swifty).

Solution 3 - Swift

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)

Solution 4 - Swift

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)))
}

Solution 5 - Swift

I used this code:

var k: Int = random() % 10;

Solution 6 - Swift

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.

Solution 7 - Swift

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)

Solution 8 - Swift

Use arc4random_uniform()

Usage:

arc4random_uniform(someNumber: UInt32) -> UInt32

This gives you random integers in the range 0 to someNumber - 1.

The maximum value for UInt32 is 4,294,967,295 (that is, 2^32 - 1).

Examples:

  • Coin flip

      let flip = arc4random_uniform(2) // 0 or 1
    
  • Dice roll

      let roll = arc4random_uniform(6) + 1 // 1...6
    
  • Random day in October

      let day = arc4random_uniform(31) + 1 // 1...31
    
  • Random year in the 1990s

      let year = 1990 + arc4random_uniform(10)
    

General form:

let number = min + arc4random_uniform(max - min + 1)

where number, max, and min are UInt32.

What about...

arc4random()

You can also get a random number by using arc4random(), which produces a UInt32 between 0 and 2^32-1. Thus to get a random number between 0 and x-1, you can divide it by x and take the remainder. Or in other words, use the Remainder Operator (%):

let number = arc4random() % 5 // 0...4

However, this produces the slight modulo bias (see also here and here), so that is why arc4random_uniform() is recommended.

Converting to and from Int

Normally it would be fine to do something like this in order to convert back and forth between Int and UInt32:

let number: Int = 10
let random = Int(arc4random_uniform(UInt32(number)))

The problem, though, is that Int has a range of -2,147,483,648...2,147,483,647 on 32 bit systems and a range of -9,223,372,036,854,775,808...9,223,372,036,854,775,807 on 64 bit systems. Compare this to the UInt32 range of 0...4,294,967,295. The U of UInt32 means unsigned.

Consider the following errors:

UInt32(-1) // negative numbers cause integer overflow error
UInt32(4294967296) // numbers greater than 4,294,967,295 cause integer overflow error

So you just need to be sure that your input parameters are within the UInt32 range and that you don't need an output that is outside of that range either.

Solution 9 - Swift

Example for random number in between 10 (0-9);

import UIKit

let randomNumber = Int(arc4random_uniform(10))

Very easy code - simple and short.

Solution 10 - Swift

I've been able to just use rand() to get a random CInt. You can make it an Int by using something like this:

let myVar: Int = Int(rand())

You can use your favourite C random function, and just convert to value to Int if needed.

Solution 11 - Swift

@jstn's answer is good, but a bit verbose. Swift is known as a protocol-oriented language, so we can achieve the same result without having to implement boilerplate code for every class in the integer family, by adding a default implementation for the protocol extension.

public extension ExpressibleByIntegerLiteral {
    public static func arc4random() -> Self {
        var r: Self = 0
        arc4random_buf(&r, MemoryLayout<Self>.size)
        return r
    }
}

Now we can do:

let i = Int.arc4random()
let j = UInt32.arc4random()

and all other integer classes are ok.

Solution 12 - Swift

In Swift 4.2 you can generate random numbers by calling the random() method on whatever numeric type you want, providing the range you want to work with. For example, this generates a random number in the range 1 through 9, inclusive on both sides

let randInt = Int.random(in: 1..<10)

Also with other types

let randFloat = Float.random(in: 1..<20)
let randDouble = Double.random(in: 1...30)
let randCGFloat = CGFloat.random(in: 1...40)

Solution 13 - Swift

Here is a library that does the job well https://github.com/thellimist/SwiftRandom

public extension Int {
    /// SwiftRandom extension
    public static func random(lower: Int = 0, _ upper: Int = 100) -> Int {
        return lower + Int(arc4random_uniform(UInt32(upper - lower + 1)))
    }
}

public extension Double {
    /// SwiftRandom extension
    public static func random(lower: Double = 0, _ upper: Double = 100) -> Double {
        return (Double(arc4random()) / 0xFFFFFFFF) * (upper - lower) + lower
    }
}

public extension Float {
    /// SwiftRandom extension
    public static func random(lower: Float = 0, _ upper: Float = 100) -> Float {
        return (Float(arc4random()) / 0xFFFFFFFF) * (upper - lower) + lower
    }
}

public extension CGFloat {
    /// SwiftRandom extension
    public static func random(lower: CGFloat = 0, _ upper: CGFloat = 1) -> CGFloat {
        return CGFloat(Float(arc4random()) / Float(UINT32_MAX)) * (upper - lower) + lower
    }
}

Solution 14 - Swift

Since Swift 4.2

There is a new set of APIs:

let randomIntFrom0To10 = Int.random(in: 0 ..< 10)
let randomDouble = Double.random(in: 1 ... 10)
  • All numeric types now have the random(in:) method that takes range.

  • It returns a number uniformly distributed in that range.


TL;DR

Well, what is wrong with the "good" old way?
  1. You have to use imported C APIs (They are different between platforms).

  2. And moreover...

> What if I told you that the random is not that random?

If you use arc4random() (to calculate the remainder) like arc4random() % aNumber, the result is not uniformly distributed between the 0 and aNumber. There is a problem called the Modulo bias.

Modulo bias

Normally, the function generates a random number between 0 and MAX (depends on the type etc.). To make a quick, easy example, let's say the max number is 7 and you care about a random number in the range 0 ..< 2 (or the interval [0, 3) if you prefer that).

The probabilities for individual numbers are:

  • 0: 3/8 = 37.5%
  • 1: 3/8 = 37.5%
  • 2: 2/8 = 25%

In other words, you are more likely to end up with 0 or 1 than 2. Of course, bare in mind that this is extremely simplified and the MAX number is much higher, making it more "fair".

> This problem is addressed by SE-0202 - Random unification in Swift 4.2

Solution 15 - Swift

 let MAX : UInt32 = 9
 let MIN : UInt32 = 1

    func randomNumber()
{
    var random_number = Int(arc4random_uniform(MAX) + MIN)
    print ("random = ", random_number);
}

Solution 16 - Swift

Updated: October 01, 2021.

Swift 5.5

Let's assume we have an array:

let numbers: [Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]



For iOS and macOS you can use system-wide random source in Xcode's framework GameKit. Here you can find GKRandomSource class with its sharedRandom() class method:

import GameKit

private func randomNumberGenerator() -> Int {
    let random = GKRandomSource.sharedRandom().nextInt(upperBound: numbers.count)
    return numbers[random]
}

randomNumberGenerator()



Also you can use a randomElement() method that returns a random element of a collection:

let randomNumber = numbers.randomElement()!
print(randomNumber)



Or use arc4random_uniform(). Pay attention that this method returns UInt32.

let generator = Int(arc4random_uniform(10))
print(generator)



And, of course, we can use a makeIterator() method that returns an iterator over the elements of the collection.

let iterator: Int = (1...10).makeIterator().shuffled().first!
print(iterator)



The final example you see here returns a random value within the specified range with a help of static func random(in range: ClosedRange<Int>) -> Int.

let randomizer = Int.random(in: 1...10)
print(randomizer)

Solution 17 - Swift

var randomNumber = Int(arc4random_uniform(UInt32(5)))

Here 5 will make sure that the random number is generated through zero to four. You can set the value accordingly.

Solution 18 - Swift

I would like to add to existing answers that the random number generator example in the Swift book is a Linear Congruence Generator (LCG), it is a severely limited one and shouldn't be except for the must trivial examples, where quality of randomness doesn't matter at all. And a LCG should never be used for cryptographic purposes.

arc4random() is much better and can be used for most purposes, but again should not be used for cryptographic purposes.

If you want something that is guaranteed to be cryptographically secure, use SecCopyRandomBytes(). Note that if you build a random number generator into something, someone else might end up (mis)-using it for cryptographic purposes (such as password, key or salt generation), then you should consider using SecCopyRandomBytes() anyway, even if your need doesn't quite require that.

Solution 19 - Swift

Without arc4Random_uniform() in some versions of Xcode(in 7.1 it runs but doesn't autocomplete for me). You can do this instead.

To generate a random number from 0-5. First

import GameplayKit

Then

let diceRoll = GKRandomSource.sharedRandom().nextIntWithUpperBound(6)

Solution 20 - Swift

Swift 4.2

Bye bye to import Foundation C lib arc4random_uniform()

// 1  
let digit = Int.random(in: 0..<10)

// 2
if let anotherDigit = (0..<10).randomElement() {
  print(anotherDigit)
} else {
  print("Empty range.")
}

// 3
let double = Double.random(in: 0..<1)
let float = Float.random(in: 0..<1)
let cgFloat = CGFloat.random(in: 0..<1)
let bool = Bool.random()
  1. You use random(in:) to generate random digits from ranges.
  2. randomElement() returns nil if the range is empty, so you unwrap the returned Int? with if let.
  3. You use random(in:) to generate a random Double, Float or CGFloat and random() to return a random Bool.

More @ Official

Solution 21 - Swift

The following code will produce a secure random number between 0 and 255:

extension UInt8 {
  public static var random: UInt8 {
    var number: UInt8 = 0
    _ = SecRandomCopyBytes(kSecRandomDefault, 1, &number)
    return number
  }
}

You call it like this:

print(UInt8.random)

For bigger numbers it becomes more complicated.
This is the best I could come up with:

extension UInt16 {
  public static var random: UInt16 {
    let count = Int(UInt8.random % 2) + 1
    var numbers = [UInt8](repeating: 0, count: 2)
    _ = SecRandomCopyBytes(kSecRandomDefault, count, &numbers)
    return numbers.reversed().reduce(0) { $0 << 8 + UInt16($1) }
  }
}

extension UInt32 {
  public static var random: UInt32 {
    let count = Int(UInt8.random % 4) + 1
    var numbers = [UInt8](repeating: 0, count: 4)
    _ = SecRandomCopyBytes(kSecRandomDefault, count, &numbers)
    return numbers.reversed().reduce(0) { $0 << 8 + UInt32($1) }
  }
}

These methods use an extra random number to determine how many UInt8s are going to be used to create the random number. The last line converts the [UInt8] to UInt16 or UInt32.

I don't know if the last two still count as truly random, but you can tweak it to your likings :)

Solution 22 - Swift

Swift 4.2

Swift 4.2 has included a native and fairly full-featured random number API in the standard library. (Swift Evolution proposal SE-0202)

let intBetween0to9 = Int.random(in: 0...9) 
let doubleBetween0to1 = Double.random(in: 0...1)

All number types have the static random(in:) which takes the range and returns the random number in the given range

Solution 23 - Swift

You can use GeneratorOf like this:

var fibs = ArraySlice([1, 1])
var fibGenerator = GeneratorOf{
    _ -> Int? in
    fibs.append(fibs.reduce(0, combine:+))
    return fibs.removeAtIndex(0)
}

println(fibGenerator.next())
println(fibGenerator.next())
println(fibGenerator.next())
println(fibGenerator.next())
println(fibGenerator.next())
println(fibGenerator.next())

Solution 24 - Swift

I use this code to generate a random number:

//
//  FactModel.swift
//  Collection
//
//  Created by Ahmadreza Shamimi on 6/11/16.
//  Copyright © 2016 Ahmadreza Shamimi. All rights reserved.
//

import GameKit

struct FactModel {
    
    let fun  = ["I love swift","My name is Ahmadreza","I love coding" ,"I love PHP","My name is ALireza","I love Coding too"]
    
    
    func getRandomNumber() -> String {
        
        let randomNumber  = GKRandomSource.sharedRandom().nextIntWithUpperBound(fun.count)
        
        return fun[randomNumber]
    }
}

Solution 25 - Swift

Details

xCode 9.1, Swift 4

Math oriented solution (1)

import Foundation

class Random {
    
    subscript<T>(_ min: T, _ max: T) -> T where T : BinaryInteger {
        get {
            return rand(min-1, max+1)
        }
    }
}

let rand = Random()

func rand<T>(_ min: T, _ max: T) -> T where T : BinaryInteger {
    let _min = min + 1
    let difference = max - _min
    return T(arc4random_uniform(UInt32(difference))) + _min
}

Usage of solution (1)

let x = rand(-5, 5)       // x = [-4, -3, -2, -1, 0, 1, 2, 3, 4]
let x = rand[0, 10]       // x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Programmers oriented solution (2)

> Do not forget to add Math oriented solution (1) code here

import Foundation

extension CountableRange where Bound : BinaryInteger {
    
    var random: Bound {
        return rand(lowerBound-1, upperBound)
    }
}

extension CountableClosedRange where Bound : BinaryInteger {
    
    var random: Bound {
        return rand[lowerBound, upperBound]
    }
}

Usage of solution (2)

let x = (-8..<2).random           // x = [-8, -7, -6, -5, -4, -3, -2, -1, 0, 1]
let x = (0..<10).random           // x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
let x = (-10 ... -2).random       // x = [-10, -9, -8, -7, -6, -5, -4, -3, -2]

Full Sample

> Do not forget to add solution (1) and solution (2) codes here

private func generateRandNums(closure:()->(Int)) {
    
    var allNums = Set<Int>()
    for _ in 0..<100 {
        allNums.insert(closure())
    }
    print(allNums.sorted{ $0 < $1 })
}

generateRandNums {
    (-8..<2).random
}

generateRandNums {
    (0..<10).random
}

generateRandNums {
    (-10 ... -2).random
}
     
generateRandNums {
    rand(-5, 5)
}
generateRandNums {
    rand[0, 10]
}

Sample result

enter image description here

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questiondoor_number_threeView Question on Stackoverflow
Solution 1 - SwiftCatfish_ManView Answer on Stackoverflow
Solution 2 - SwiftJohn PavleyView Answer on Stackoverflow
Solution 3 - SwiftjstnView Answer on Stackoverflow
Solution 4 - SwiftGrootView Answer on Stackoverflow
Solution 5 - SwiftfockusView Answer on Stackoverflow
Solution 6 - SwiftTwoStrawsView Answer on Stackoverflow
Solution 7 - SwiftDave DeLongView Answer on Stackoverflow
Solution 8 - SwiftSuragchView Answer on Stackoverflow
Solution 9 - SwiftR.SView Answer on Stackoverflow
Solution 10 - SwiftConnorView Answer on Stackoverflow
Solution 11 - SwiftRyne WangView Answer on Stackoverflow
Solution 12 - SwiftSh_KhanView Answer on Stackoverflow
Solution 13 - SwiftdemiculusView Answer on Stackoverflow
Solution 14 - SwiftJakub TruhlářView Answer on Stackoverflow
Solution 15 - SwiftRajesh SharmaView Answer on Stackoverflow
Solution 16 - SwiftAndy JazzView Answer on Stackoverflow
Solution 17 - SwiftTaran GoelView Answer on Stackoverflow
Solution 18 - SwiftJeffrey GoldbergView Answer on Stackoverflow
Solution 19 - SwiftbrokenrhinoView Answer on Stackoverflow
Solution 20 - SwiftiSrinivasan27View Answer on Stackoverflow
Solution 21 - SwiftYvoView Answer on Stackoverflow
Solution 22 - SwiftSuhit PatilView Answer on Stackoverflow
Solution 23 - SwiftDurul DalkanatView Answer on Stackoverflow
Solution 24 - SwiftAhmadreza ShamimiView Answer on Stackoverflow
Solution 25 - SwiftVasily BodnarchukView Answer on Stackoverflow