133

so my goal in this codebit is to randomly roll two dice and as we all know your regular die only has 6 sides so I imported Foundation for access to arc4random_uniform(UInt32). I attempted using the range of (1..7) to avoid randomly getting 0 however that returned an error which I didn't enjoy too much. I tried to do this:

dice1 = arc4random_uniform(UInt32(1..7))

however that returned

Could not find an overload for 'init' that accepts the supplied arguments

I hope that this is enough information for you amazing debs out there to help me :)

Please note I am just doing this in a playground to practice swift. It isn't imperative that I learn how to do this; it's just me tinkering before I jump into building actual apps :D

//imports random number function
import Foundation
//creates data storage for dice roll
var dice1: UInt32 = 0
var dice2: UInt32 = 0
//counter variable
var i = 0
//how many times snake eyes happens
var snakeeyes = 0
 //how many times a double is rolled
var `double` = 0
//rolls dice 100 times
while i < 100{
    //from here
    //sets dice roll

This returns an error of 'Range $T3' is not convertible to UInt32

   dice1 = arc4random_uniform(1..7)
   dice2 = arc4random_uniform(1..7)
    //checks for snake eyes
    if dice1 == 1 && dice2 == 1 {
        snakeeyes = snakeeyes + 1

    }
    //checks for doubles
    if dice1 == dice2{
        `double` = `double` + 1
    }
    //increases counter
        i = i + 1
    //to here
}
println("You got Snake Eyes \(snakeeyes) times.")
println("You got Doubles, \(`double`) times.")
Huangism
  • 16,278
  • 7
  • 48
  • 74
arcreigh
  • 1,423
  • 2
  • 11
  • 12
  • 4
    I believe you should do `dice1 = arc4random_uniform(6) + 1` to get the range 1 - 6. I don't do iOS objective C nor has any knowledge on swift-language though. The random method should returns you 0 - 5, and + 1 will be 1 - 6. – Sky Jun 10 '14 at 03:42
  • 1
    Range is an object data itself, it isn't an integer data that's why you are getting the error when the argument only takes in (UInt32) - `u_int32_t arc4random_uniform(u_int32_t upper_bound);` – Sky Jun 10 '14 at 03:49
  • aha! thank you sky! did an assert to test if it was going less then 0 and can confirm this was exactly what I needed put it as an answer so I can check it off as such! – arcreigh Jun 10 '14 at 03:50
  • probability = Int(arc4random_uniform(UInt32(total))) – if you have multiple casting complaints that are nonspecific (because the typeahead / headers are not functional) – bshirley Jan 07 '16 at 17:59
  • This is built in starting with Swift 4.2 as pointed out below https://stackoverflow.com/a/50696901/1148030 – Peter Lamberg Oct 08 '18 at 12:42
  • https://stackoverflow.com/questions/34712453/how-to-generate-a-random-number-in-a-range-10-20-using-swift/34712601#34712601 – Leo Dabus Feb 25 '19 at 03:55

18 Answers18

263

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;
Sky
  • 3,350
  • 2
  • 14
  • 12
  • 2
    @JoeSmith you're exactly right on this, it should be arc4random_uniform(21)+10 to return a range between 10 - 30 as the upper bound is not inclusive. The part "arc4random_uniform(20)+10" is based off community edit and votes. – Sky Nov 29 '16 at 13:02
  • Yes, I've just tested and to get a random colour (i.e. wanting a random value between and including 0 - 255), I used: "arc4random_uniform(256) + 0" – Chris Allinson Feb 19 '17 at 19:07
91

I've made an Int type extension. tested it in playground, hope this is useful. It also accepts negative ranges:

extension Int
{
    static func random(range: Range<Int> ) -> Int
    {
        var offset = 0

        if range.startIndex < 0   // allow negative ranges
        {
            offset = abs(range.startIndex)
        }

        let mini = UInt32(range.startIndex + offset)
        let maxi = UInt32(range.endIndex   + offset)

        return Int(mini + arc4random_uniform(maxi - mini)) - offset
    }
}

use like

var aRandomInt = Int.random(-500...100)  // returns a random number within the given range.

or define it as a Range extension as property like this:

extension Range
{
    var randomInt: Int
    {
        get
        {
            var offset = 0

            if (startIndex as Int) < 0   // allow negative ranges
            {
                offset = abs(startIndex as Int)
            }

            let mini = UInt32(startIndex as Int + offset)
            let maxi = UInt32(endIndex   as Int + offset)

            return Int(mini + arc4random_uniform(maxi - mini)) - offset
        }
    }
}

// usage example: get an Int within the given Range:
let nr = (-1000 ... 1100).randomInt
Arbitur
  • 38,684
  • 22
  • 91
  • 128
Ted van Gaalen
  • 1,159
  • 8
  • 5
65

Quite a few good answers, but I just wanted to share my personal favourite Swift random number generation function for positive integers:

Swift 2

func randomNumber(range: Range<Int> = 1...6) -> Int {
    let min = range.startIndex
    let max = range.endIndex
    return Int(arc4random_uniform(UInt32(max - min))) + min
}

Swift 3

Here's a quick update for Swift 3 and, as a bonus, it now works for any value type that conforms to the SignedInteger protocol - much more convenient for core data applications that need to specify Int16, Int32 etc. As a quick note, if you really need it to work on unsigned integers as well, just copy the entire function then replace SignedInteger with UnsignedInteger and toIntMax() with toUIntMax().

func randomNumber<T : SignedInteger>(inRange range: ClosedRange<T> = 1...6) -> T {
    let length = (range.upperBound - range.lowerBound + 1).toIntMax()
    let value = arc4random().toIntMax() % length + range.lowerBound.toIntMax()
    return T(value)
}

Swift 4

Thanks to the removal of toIntMax() in Swift 4, we now have to use a different means of converting to a common integer type. In this example I'm using Int64 which is large enough for my purposes, but if you're using unsigned integers or have an Int128 or Int256 custom type you should use those.

public func randomNumber<T : SignedInteger>(inRange range: ClosedRange<T> = 1...6) -> T {
    let length = Int64(range.upperBound - range.lowerBound + 1)
    let value = Int64(arc4random()) % length + Int64(range.lowerBound)
    return T(value)
}

One more, for the total random-phile, here's an extension that returns a random element from any Collection type object. Note this uses the above function to generate its index so you will need both.

extension Collection {
    func randomItem() -> Self.Iterator.Element {
        let count = distance(from: startIndex, to: endIndex)
        let roll = randomNumber(inRange: 0...count-1)
        return self[index(startIndex, offsetBy: roll)]
    }
}

Usage

randomNumber()

returns a random number between 1 and 6.

randomNumber(50...100)

returns a number between 50 and 100 inclusive. Naturally you can replace the values of 50 and 100 with whatever you like.

Swift 4.2

Alas, my best StackOverflow answer has been rendered obsolete at last. You can now use simply Int.random(in: 1 ... 6) to generate a random number in a given range. Also works for other forms of integer and floating point number. Collection types also now provide shuffle() and randomElement() functions. There is therefore no longer any need for fancy randomisation functions unless you want to use a specific randomiser type.

Ash
  • 9,064
  • 3
  • 48
  • 59
  • 1
    I looked at this and thought it must be wrong because (max - min) = 5, yielding a random integer in the range 0 to 4 (plus 1 making 1 to 5). But by putting the code into an Xcode playground it was evident that it worked. The reason being that max is actually equal to 7 since endIndex returns "The collection's first 'past the end' position." (as stated in Apple's documentation). So, a good answer and a useful learning exercise for me. – Vince O'Sullivan Nov 16 '15 at 08:56
  • This works with negative integers too. `randomNumber(-3 ... -1)` works as long as you have spaces before and after the `...`. You can use `random(-3 ..< -1` to exclude the last number too. – Carter Medlin Jul 12 '16 at 16:15
  • Use `ClosedInterval` instead of `Range` if you want to have this work with non-integers. – Carter Medlin Jul 12 '16 at 16:28
  • I wouldn't. Interval types were deprecated in Swift 3. There's probably a way to use Generics to expand the functionality of the code, but I've not had the time, inclination or reason to investigate. – Ash Jul 14 '16 at 10:23
  • 1
    There we go, a genericised integer version of the code. – Ash Mar 06 '17 at 09:02
  • i tried for Double let rotation = Double.random(in: 0.1...1) – Abhishek Thapliyal Jun 14 '20 at 15:23
23

According to Swift 4.2 now it's easily to get random number like this

let randomDouble = Double.random(in: -7.9...12.8)

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

for more details check this out

Nosov Pavel
  • 1,571
  • 1
  • 18
  • 34
19

If You want i create that for random numbers. this is extension of number Int and Double, Float

/**
    Arc Random for Double and Float
*/
public func arc4random <T: IntegerLiteralConvertible> (type: T.Type) -> T {
    var r: T = 0
    arc4random_buf(&r, UInt(sizeof(T)))
    return r
}
public extension Int {
    /**
    Create a random num Int
    :param: lower number Int
    :param: upper number Int
    :return: random number Int
    By DaRkDOG
    */
    public static func random (#lower: Int , upper: Int) -> Int {
        return lower + Int(arc4random_uniform(upper - lower + 1))
    }

}
public extension Double {
    /**
    Create a random num Double
    :param: lower number Double
    :param: upper number Double
    :return: random number Double
    By DaRkDOG
    */
    public static func random(#lower: Double, upper: Double) -> Double {
        let r = Double(arc4random(UInt64)) / Double(UInt64.max)
        return (r * (upper - lower)) + lower
    }
}
public extension Float {
    /**
    Create a random num Float
    :param: lower number Float
    :param: upper number Float
    :return: random number Float
    By DaRkDOG
    */
    public static func random(#lower: Float, upper: Float) -> Float {
        let r = Float(arc4random(UInt32)) / Float(UInt32.max)
        return (r * (upper - lower)) + lower
    }
}

USE :

let randomNumDouble = Double.random(lower: 0.00, upper: 23.50)
let randomNumInt = Int.random(lower: 56, upper: 992)
let randomNumInt =Float.random(lower: 6.98, upper: 923.09)
YanSte
  • 10,661
  • 3
  • 57
  • 53
13

Swift 3/4:

func randomNumber(range: ClosedRange<Int> = 1...6) -> Int {
    let min = range.lowerBound
    let max = range.upperBound
    return Int(arc4random_uniform(UInt32(1 + max - min))) + min
}
Alessandro Ornano
  • 34,887
  • 11
  • 106
  • 133
8

That's because arc4random_uniform() is defined as follows:

func arc4random_uniform(_: UInt32) -> UInt32

It takes a UInt32 as input, and spits out a UInt32. You're attempting to pass it a range of values. arc4random_uniform gives you a random number in between 0 and and the number you pass it (exclusively), so if for example, you wanted to find a random number between -50 and 50, as in [-50, 50] you could use arc4random_uniform(101) - 50

Mick MacCallum
  • 129,200
  • 40
  • 280
  • 281
  • Sky answered my question perfectly I believe you are saying the same thing as well thank you very much can confirm that by setting dice1,2 = arc4random_uniform(6)+1 did indeed set the range to 1-6 I tested this with an assert :D – arcreigh Jun 10 '14 at 03:56
6

I modified @DaRk-_-D0G's answer to work with Swift 2.0

/**
Arc Random for Double and Float
*/
public func arc4random <T: IntegerLiteralConvertible> (type: T.Type) -> T {
    var r: T = 0
    arc4random_buf(&r, sizeof(T))
    return r
}
public extension Int {
    /**
    Create a random num Int
    :param: lower number Int
    :param: upper number Int
    :return: random number Int
    By DaRkDOG
    */
    public static func random (lower: Int , upper: Int) -> Int {
        return lower + Int(arc4random_uniform(UInt32(upper - lower + 1)))
    }

}
public extension Double {
    /**
    Create a random num Double
    :param: lower number Double
    :param: upper number Double
    :return: random number Double
    By DaRkDOG
    */
    public static func random(lower: Double, upper: Double) -> Double {
        let r = Double(arc4random(UInt64)) / Double(UInt64.max)
        return (r * (upper - lower)) + lower
    }
}
public extension Float {
    /**
    Create a random num Float
    :param: lower number Float
    :param: upper number Float
    :return: random number Float
    By DaRkDOG
    */
    public static func random(lower: Float, upper: Float) -> Float {
        let r = Float(arc4random(UInt32)) / Float(UInt32.max)
        return (r * (upper - lower)) + lower
    }
}
YanSte
  • 10,661
  • 3
  • 57
  • 53
Joped
  • 1,108
  • 1
  • 11
  • 12
5

Swift:

var index = 1 + random() % 6
Alexander Volkov
  • 7,904
  • 1
  • 47
  • 44
3

In swift...

This is inclusive, calling random(1,2) will return a 1 or a 2, This will also work with negative numbers.

    func random(min: Int, _ max: Int) -> Int {
        guard min < max else {return min}
        return Int(arc4random_uniform(UInt32(1 + max - min))) + min
    }
Carter Medlin
  • 11,857
  • 5
  • 62
  • 68
3

The answer is just 1 line code:

let randomNumber = arc4random_uniform(8999) + 1000 //for 4 digit random number
let randomNumber = arc4random_uniform(899999999) + 100000000 //for 9 digit random number
let randomNumber = arc4random_uniform(89) + 10    //for 2 digit random number
let randomNumber = arc4random_uniform(899) + 100  //for 3 digit random number

The alternate solution is:

    func generateRandomNumber(numDigits: Int) -> Int{
    var place = 1
    var finalNumber = 0;
    var finanum = 0;
    for var i in 0 ..< numDigits {
        place *= 10
        let randomNumber = arc4random_uniform(10)         
        finalNumber += Int(randomNumber) * place
        finanum = finalNumber / 10
           i += 1
    }
    return finanum
}

Although the drawback is that number cannot start from 0.

Nupur Sharma
  • 1,106
  • 13
  • 15
3

Since Swift 4.2:

Int {    
    public static func random(in range: ClosedRange<Int>) -> Int
    public static func random(in range: Range<Int>) -> Int
}

Used like:

Int.random(in: 2...10)
Camsoft
  • 11,718
  • 19
  • 83
  • 120
2

Edit: Swift 4.2+ provides this now:

(100...200).randomElement()

It’s idiomatic to me to extend Range:

public extension Range where Bound == Int {
    var random: Int {
        return lowerBound + Int(arc4random_uniform(UInt32(upperBound - lowerBound)))
    }
}

public extension ClosedRange where Bound == Int {
    var random: Int {
        return lowerBound + Int(arc4random_uniform(UInt32(upperBound - lowerBound + 1)))
    }
}

In use:

let foo = (100..<600).random
mxcl
  • 26,392
  • 12
  • 99
  • 98
  • Probably just a stylistic thing. There's no inherent advantage to either method, it's just whatever you feel more comfortable with. – Ash Mar 27 '18 at 13:25
  • 1
    For people who consider this “stylistic” I have a language recommendation for them: `C`. Have fun! – mxcl Mar 27 '18 at 16:05
  • I am sure someone had already done it 3 years ago :) https://stackoverflow.com/questions/34712453/how-to-generate-a-random-number-in-a-range-10-20-using-swift/34712601#34712601 – Leo Dabus Feb 25 '19 at 03:54
1

I successfully accomplished creating a random number using the following code:

var coin = arc4random_uniform(2) + 1

Hope this can help you.

Bigfoot11
  • 911
  • 2
  • 11
  • 25
0

Swift 3 Xcode Beta 5 Solution. Based on Ted van Gaalen Answer.

extension Int
  {
     static func random(range: Range<Int> ) -> Int
    {
        var offset = 0

        if range.lowerBound < 0   // allow negative ranges
        {
            offset = Swift.abs(range.lowerBound)
        }

        let mini = UInt32(range.lowerBound + offset)
        let maxi = UInt32(range.upperBound   + offset)

        return Int(mini + arc4random_uniform(maxi - mini)) - offset
    }
}
Statik
  • 342
  • 1
  • 3
  • 14
0

var rangeFromLimits = arc4random_uniform( (UPPerBound - LOWerBound) + 1)) + LOWerBound;

Asim Khan
  • 508
  • 1
  • 7
  • 21
0

hope this is working. make random number between range for arc4random_uniform()?

var randomNumber = Int(arc4random_uniform(6))
print(randomNumber)
0

Probably one find useful this a bit updated version of Range extension from Ted van Gaalen's answer using Swift 4/Xcode 9+:

extension CountableClosedRange where Bound == Int {
    var randomFromRange: Bound {
        get {
            var offset = 0
            if lowerBound < 0 {
                offset = abs(lowerBound)
            }
            let mini = UInt32(lowerBound + offset)
            let maxi = UInt32(upperBound + offset)
            return Int(mini + arc4random_uniform(maxi - mini)) - offset
        }
    }
}

let n = (-1000 ... 1000).randomFromRange
print(n)

Or this a bit "hacky" solution to support open and closed intervals:

extension CountableRange where Bound == Int {
    var randomFromRange: Bound {
        return uniformRandom(from: lowerBound, to: upperBound)
    }
}

extension CountableClosedRange where Bound == Int {
    var randomFromRange: Bound {
        return uniformRandom(from: lowerBound, to: upperBound - 1)
    }
}

func uniformRandom(from: Int, to: Int) -> Int {
    var offset = 0
    if from < 0 {
        offset = abs(from)
    }
    let mini = UInt32(from + offset)
    let maxi = UInt32(to + offset)
    return Int(mini + arc4random_uniform(maxi - mini)) - offset
}

Not sure if there is a way to add property to both types of intervals simultaneously.

devforfu
  • 1,570
  • 1
  • 19
  • 41