Andy Fedoroff - 4 months ago 47

Swift Question

I'm intending to implement a random number generator via Swift 3. I have three different methods for generating an integer (between

`0`

`50000`

Do these generators use the same math principles of generating a value or not?

What generator is less CPU and RAM intensive at runtime (having 10000 iterations)?

`var generator: Int = random() % 50000`

`let generator = Int(arc4random_uniform(50000))`

`import GameKit`

let number: [Int] = [0, 1, 2... 50000]

func generator() -> Int {

let random = GKRandomSource.sharedRandom().nextIntWithUpperBound(number.count)

return number[random]

}

Answer

All of these are pretty well documented, and most have published source code.

```
var generator: Int = random() % 50000
```

Well, first of all, this is modulo biased, so it certainly won't be equivalent to a proper uniform random number. The docs for `random`

explain it:

The random() function uses a non-linear, additive feedback, random number generator, employing a default table of size 31 long integers. It returns successive pseudo-random numbers in the range from 0 to (2**31)-1. The period of this random number generator is very large, approximately 16*((2**31)-1).

But you can look at the full implementation and documentation in Apple's source code for libc.

Contrast the documentation for `arc4random_uniform`

(which does not have modulo bias):

These functions use a cryptographic pseudo-random number generator to generate high quality random bytes very quickly. One data pool is used for all consumers in a process, so that consumption under program flow can act as additional stirring. The subsystem is re-seeded from the kernel random number subsystem on a regular basis, and also upon fork(2).

And the source code is also available. The important thing to note from `arc4random_uniform`

is that it avoids modulo bias by adjusting the modulo correctly and then generating random numbers until it is in the correct range. In principle this could require generating an unlimited number of random values; in practice it is incredibly rare that it would need to generate more than one, and rare-to-the-point-of-unbelievable that it would generate more than that.

`GKRandomSource.sharedRandom()`

is also well documented:

The system random source shares state with the arc4random family of C functions. Generating random numbers with this source modifies the outcome of future calls to those functions, and calling those functions modifies the sequence of random values generated by this source. As such, this source is neither deterministic nor independentâ€”use it only for trivial gameplay mechanics that do not rely on those attributes.

For performance, you would expect `random()`

to be fastest since it never seeds itself from the system entropy pool, and so it also will not reduce the entropy in the system (though `arc4random`

only does this periodically, I believe around every 1.5MB or so of random bytes generated; not for every value). But as with all things performance, you must profile. Of course since `random()`

does not reseed itself it is less random than `arc4random`

, which is itself less random than the source of entropy in the system (`/dev/random`

).

When in doubt, if you have GameplayKit available, use it. Apple selected the implementation of `sharedRandom()`

based on what they think is going to work best in most cases. Otherwise use `arc4random`

. But if you really need to minimize impact on the system for "pretty good" (but not cryptographic) random numbers, look at `random`

. If you're willing to take "kinda random if you don't look at them too closely" numbers and have even less impact on the system, look at `rand`

. And if you want almost no impact on the system (guaranteed O(1), inlineable), see XKCD's getRandomNumber().