How to Generate a Random Number in a Range (10...20) Using Swift

How to generate a random number in a range (10...20) using Swift

Xcode 11 • Swift 5.1 or later

extension Range where Bound: FixedWidthInteger {
var random: Bound { .random(in: self) }
func random(_ n: Int) -> [Bound] { (0..<n).map { _ in random } }
}

extension ClosedRange where Bound: FixedWidthInteger  {
var random: Bound { .random(in: self) }
func random(_ n: Int) -> [Bound] { (0..<n).map { _ in random } }
}

Note: For older Swift versions check the edit history

Usage:

(10...20).random    // 16
(0...1).random(10) // [0, 1, 0, 0, 1, 1, 1, 1, 1, 0]

How does one generate a random number in 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()

How can I generate large, ranged random numbers in Swift?

Here is a possible solution for UInt, Int and Double which works with
the full range of those types. It is written as extension methods
(now updated for Swift 2), but the same can be done with global functions.

Note that arc4random_uniform() produces 32-bit numbers only, so that
can not be used if Int/UInt are 64-bit integers (which is the case
for all OS X machines and all newer iOS devices).

For UInt we use the technique from https://stackoverflow.com/a/26550169/1187415
(which is just a Swift translation of https://stackoverflow.com/a/10989061/1187415).
The case where the range covers the full range of UInt is treated separately.

extension UInt {
static func random(minValue minValue : UInt, maxValue : UInt) -> UInt {
precondition(minValue <= maxValue, "attempt to call random() with minValue > maxValue")

if minValue == UInt.min && maxValue == UInt.max {
// Random number in the full range of UInt:

var rnd : UInt = 0
arc4random_buf(&rnd, sizeofValue(rnd))
return rnd
} else {
// Compute random number in the range 0 ... (maxValue-minValue),
// using the technique from
// https://stackoverflow.com/a/26550169/1187415, https://stackoverflow.com/a/10989061/1187415
// and avoiding the "modulo bias problem":

let range = maxValue - minValue + 1
let randLimit = UInt.max - UInt.max % range
var rnd : UInt = 0
repeat {
arc4random_buf(&rnd, sizeofValue(rnd))
} while rnd >= randLimit
rnd = rnd % range

// Transform `rnd` back to the range minValue ... maxValue:
return minValue + rnd
}
}
}

Examples:

let u1 = UInt.random(minValue: 1000, maxValue: 2000)
let u2 = UInt.random(minValue: UInt.min, maxValue: UInt.max)

The case of signed integers can be reduced to the unsigned case using the
overflow operators and the bitPattern: conversion:

extension Int {
static func random(minValue minValue : Int, maxValue : Int) -> Int {
precondition(minValue <= maxValue, "attempt to call random() with minValue > maxValue")

// Compute unsigned random number in the range 0 ... (maxValue-minValue):
let diff = UInt(bitPattern: maxValue &- minValue)
let rnd = UInt.random(minValue: 0, maxValue: diff)

// Transform `rnd` back to the range minValue ... maxValue:
return minValue &+ Int(bitPattern: rnd)
}
}

Examples:

let i1 = Int.random(minValue: -1000, maxValue: 1000)
let i2 = Int.random(minValue: Int.min, maxValue: Int.max)

Finally, a straight-forward implementation for Double:

extension Double {
static func random(minValue minValue : Double, maxValue : Double) -> Double {
precondition(minValue <= maxValue, "attempt to call random() with minValue > maxValue")

// Random floating point number in the range 0.0 ... 1.0:
let rnd = Double(UInt.random(minValue: 0, maxValue: UInt.max))/Double(UInt.max)

// Scale to range minValue ... maxValue:
return minValue + rnd * (maxValue - minValue)
}
}

Example:

let d = Double.random(minValue: 10.5, maxValue: 123.5)

Update for Swift 3:

extension UInt {
static func random(minValue: UInt, maxValue: UInt) -> UInt {
precondition(minValue <= maxValue, "attempt to call random() with minValue > maxValue")

if minValue == UInt.min && maxValue == UInt.max {
// Random number in the full range of UInt:

var rnd: UInt = 0
arc4random_buf(&rnd, MemoryLayout.size(ofValue: rnd))
return rnd
} else {
// Compute random number in the range 0 ... (maxValue-minValue),
// using the technique from
// https://stackoverflow.com/a/26550169/1187415, https://stackoverflow.com/a/10989061/1187415
// and avoiding the "modulo bias problem":

let range = maxValue - minValue + 1
let randLimit = UInt.max - UInt.max % range
var rnd: UInt = 0
repeat {
arc4random_buf(&rnd, MemoryLayout.size(ofValue: rnd))
} while rnd >= randLimit
rnd = rnd % range

// Transform `rnd` back to the range minValue ... maxValue:
return minValue + rnd
}
}
}

extension Int {
static func random(minValue: Int, maxValue: Int) -> Int {
precondition(minValue <= maxValue, "attempt to call random() with minValue > maxValue")

// Compute unsigned random number in the range 0 ... (maxValue-minValue):
let diff = UInt(bitPattern: maxValue &- minValue)
let rnd = UInt.random(minValue: 0, maxValue: diff)

// Transform `rnd` back to the range minValue ... maxValue:
return minValue &+ Int(bitPattern: rnd)
}
}

extension Double {
static func random(minValue: Double, maxValue: Double) -> Double {
precondition(minValue <= maxValue, "attempt to call random() with minValue > maxValue")

// Random floating point number in the range 0.0 ... 1.0:
let rnd = Double(UInt.random(minValue: 0, maxValue: UInt.max))/Double(UInt.max)

// Scale to range minValue ... maxValue:
return minValue + rnd * (maxValue - minValue)
}
}

Generating a random number in Swift

It really depends on how much casting you want to avoid. You could simply wrap it in a function:

func random(max maxNumber: Int) -> Int {
return Int(arc4random_uniform(UInt32(maxNumber)))
}

So then you only have to do the ugly casting once. Everywhere you want a random number with a maximum number:

let r = random(max: _names.count)
let name: String = _names[r]

As a side note, since this is Swift, your properties don't need _ in front of them.

How does one make random number between range for arc4random_uniform()?

I believe you should do

dice1 = arc4random_uniform(6) + 1;

to get the range 1 - 6. I don't do iOS objective C nor have I any knowledge on swift-language though. The random method should return a value between 0 and 5, and + 1 will make it a value between 1 and 6.

If you need a range between lets say 10 - 30 then just do

int random = arc4random_uniform(21) + 10;

Generating random numbers with Swift

let randomIntFrom0To10 = Int.random(in: 1..<10)
let randomFloat = Float.random(in: 0..<1)

// if you want to get a random element in an array
let greetings = ["hey", "hi", "hello", "hola"]
greetings.randomElement()

Return an array of Integers within a range

The function randomNumber() is expensive not efficient because min and max are extracted in each call (aka in each iteration of the loop)

This might be a bit swiftier

func randomNumbers(range: ClosedRange<Int>, count: Int) -> [Int] {
let min = range.lowerBound
let randomMax = UInt32(1 + range.upperBound - min)
return (0..<count).map {_ in return Int(arc4random_uniform(randomMax)) + min }
}

let nums = randomNumbers(range: 10...20, count: 5)

How to select range of values when using arc4random()

As pointed out in other posts below, it is better to use arc4random_uniform. (When this answer was originally written, arc4random_uniform was not available). Besides avoiding the modulo bias of arc4random() % x, it also avoids a seeding problem with arc4random when used recursively in short timeframes.

arc4random_uniform(4)

will generate 0, 1, 2 or 3. Thus you could use:

arc4random_uniform(51)

and merely add 50 to the result to get a range between 50 & 100 (inclusive).



Related Topics



Leave a reply



Submit