Swift: Random Number for 64-Bit Integers

How to express 64-bit integers in Swift?

The code below will generate random Int64 bits integers between it's minimum and it's maximum value. So you can change the range to fit your needs.

let myInt: Int64 = Int64.random(in: Int64.min...Int64.max)

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

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

Generate random number of certain amount of digits

Here is some pseudocode that should do what you want.

generateRandomNumber(20)
func generateRandomNumber(int numDigits){
var place = 1
var finalNumber = 0;
for(int i = 0; i < numDigits; i++){
place *= 10
var randomNumber = arc4random_uniform(10)
finalNumber += randomNumber * place
}
return finalNumber
}

Its pretty simple. You generate 20 random numbers, and multiply them by the respective tens, hundredths, thousands... place that they should be on. This way you will guarantee a number of the correct size, but will randomly generate the number that will be used in each place.

Update

As said in the comments you will most likely get an overflow exception with a number this long, so you'll have to be creative in how you'd like to store the number (String, ect...) but I merely wanted to show you a simple way to generate a number with a guaranteed digit length. Also, given the current code there is a small chance your leading number could be 0 so you should protect against that as well.

Need explanation about random function swift

A IEEE 754 32-bit floating point number has 24 significant bits for the mantissa, that is not enough to store a 10-digit integer exactly:

print(0xFFFFFFFF)             // 4294967295
print(Float(0xFFFFFFFF)) // 4.2949673e+09
print(Int(Float(0xFFFFFFFF))) // 4294967296

That won't affect your code because

Float(arc4random()) / Float(0xFFFFFFFF)

is still a floating point number between 0.0 and 1.0. Changing the calculation to

return CGFloat(arc4random()) / 0xFFFFFFFF

will fix the warning on 64-bit platforms: The integer constant is now converted to a (64-bit) Double.

But as of Swift 4.2 you can avoid the problem completely by using the new Random API:

func random(min: CGFloat, max: CGFloat) -> CGFloat {
return CGFloat.random(in: min...max)
}

same Int has different values in Swift, mysterious riddle

arc4random generates an unsigned 32bit int. Int is probably 64 bit on your machine so you get the same number and it doesn't overflow. But %i and %d are signed 32-bit format specifiers. See here and here. That's why you get a negative number when arc4random returns a number greater than 2^32-1, aka Int32.max.

For example, when 2340152522 is generated, you get -1954814774 in the %i position because:

Int32(bitPattern: 2340152522) == -1954814774

On the other hand, converting an Int to String won't change the number. Int is a signed 64 bit integer.

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;


Related Topics



Leave a reply



Submit