Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift: Random number for 64-bit integers?

So, with my current project, I need to work with 64-bit integers and I need to grab random numbers between ranges up to 100 billion. arc4random()/arc4random_uniform() only works with unsigned 32-bit integers.

I can probably fudge it a little because my min/max range for every call will likely not exceed 2 billion, but I'd like to futureproof myself in case I decide that, well, I do need a broader range.

Any advice?

like image 238
RH224 Avatar asked Oct 24 '14 14:10

RH224


People also ask

How do you generate a random integer in Swift?

To generate a random number in Swift, use Int. random() function. Int. random() returns a number, that is randomly selected, in the given range.

What is arc4random Swift?

The arc4random() function generates numbers between 0 and 4,294,967,295, giving a range of 2 to the power of 32 - 1, i.e., a lot. But if you wanted to generate a random number within a specific range there's a better alternative.


2 Answers

Update: As of Swift 4.2 (distributed with Xcode 10.1) there is a unified random API in the Swift standard library, see

  • SE 0202 Random Unification.

You can simply call

UInt64.random(in: minValue ... maxValue)

to get a random number in the given range.


(Previous answer for Swift < 4.2:) With arc4random_buf() you can create "arbitrary large" random numbers, so this would be a possible solution:

// Swift 2:
func random64(upper_bound: UInt64) -> UInt64 {

    // Generate 64-bit random number:
    var rnd : UInt64 = 0
    arc4random_buf(&rnd, sizeofValue(rnd))

    return rnd % upper_bound
}

// Swift 3:
func random64(upper_bound: UInt64) -> UInt64 {

    // Generate 64-bit random number:
    var rnd : UInt64 = 0
    arc4random_buf(&rnd, MemoryLayout.size(ofValue: rnd))

    return rnd % upper_bound
}

This method suffers from the "modulo bias" problem when the upper bound is not a power of 2 (See Why do people say there is modulo bias when using a random number generator?). Here I have translated the answer https://stackoverflow.com/a/10989061/1187415 from above thread to Swift:

// Swift 2:
func random64(upper_bound: UInt64) -> UInt64 {

    // Generate 64-bit random value in a range that is
    // divisible by upper_bound:
    let range = UInt64.max - UInt64.max % upper_bound
    var rnd : UInt64 = 0
    repeat {
        arc4random_buf(&rnd, sizeofValue(rnd))
    } while rnd >= range

    return rnd % upper_bound
}

// Swift 3:
func random64(upper_bound: UInt64) -> UInt64 {

    // Generate 64-bit random value in a range that is
    // divisible by upper_bound:
    let range = UInt64.max - UInt64.max % upper_bound
    var rnd : UInt64 = 0
    repeat {
        arc4random_buf(&rnd, MemoryLayout.size(ofValue: rnd))
    } while rnd >= range

    return rnd % upper_bound
}

(At first sight it looks as if the loop might not terminate, but it can be shown that on average less than 2 iterations are needed.)

like image 145
Martin R Avatar answered Oct 05 '22 12:10

Martin R


Perhaps you can compose it of two 32 bit integers:

var random64 = Int64(arc4random()) + (Int64(arc4random()) << 32)
like image 24
Kirsteins Avatar answered Oct 05 '22 12:10

Kirsteins