Generate a random float between 0 and 1
For Swift 4.2+ see: https://stackoverflow.com/a/50733095/1033581
Below are recommendations for correct uniformity and optimal precision for ObjC and Swift 4.1.
32 bits precision (Optimal for Float
)
Uniform random value in [0, 1] (including 0.0 and 1.0), up to 32 bits precision:
Obj-C:
float val = (float)arc4random() / UINT32_MAX;
Swift:
let val = Float(arc4random()) / Float(UInt32.max)
It's optimal for:
- a
Float
(orFloat32
) which has a significand precision of 24 bits for its mantissa
48 bits precision (discouraged)
It's easy to achieve 48 bits precision with drand48
(which uses arc4random_buf
under the hood). But note that drand48 has flaws because of the seed requirement and also for being suboptimal to randomize all 52 bits of Double mantissa.
Uniform random value in [0, 1], 48 bits precision:
Swift:
// seed (only needed once)
srand48(Int(Date.timeIntervalSinceReferenceDate))
// random Double value
let val = drand48()
64 bits precision (Optimal for Double
and Float80
)
Uniform random value in [0, 1] (including 0.0 and 1.0), up to 64 bits precision:
Swift, using two calls to arc4random:
let arc4random64 = UInt64(arc4random()) << 32 &+ UInt64(arc4random())
let val = Float80(arc4random64) / Float80(UInt64.max)
Swift, using one call to arc4random_buf:
var arc4random64: UInt64 = 0
arc4random_buf(&arc4random64, MemoryLayout.size(ofValue: arc4random64))
let val = Float80(arc4random64) / Float80(UInt64.max)
It's optimal for:
- a
Double
(orFloat64
) which has a significand precision of 52 bits for its mantissa - a
Float80
which has a significand precision of 64 bits for its mantissa
Notes
Comparisons with other methods
Answers where the range is excluding one of the bounds (0 or 1) likely suffer from a uniformity bias and should be avoided.
- using
arc4random()
, best precision is 1 / 0xFFFFFFFF (UINT32_MAX) - using
arc4random_uniform()
, best precision is 1 / 0xFFFFFFFE (UINT32_MAX-1) - using
rand()
(secretly using arc4random), best precision is 1 / 0x7FFFFFFF (RAND_MAX) - using
random()
(secretly using arc4random), best precision is 1 / 0x7FFFFFFF (RAND_MAX)
It's mathematically impossible to achieve better than 32 bits precision with a single call to arc4random
, arc4random_uniform
, rand
or random
. So our above 32 bits and 64 bits solutions should be the best we can achieve.
// Seed (only once)
srand48(time(0));
double x = drand48();
// Swift version
// Seed (only once)
srand48(Int(Date().timeIntervalSince1970))
let x = drand48()
The drand48() and erand48() functions return non-negative, double-precision, floating-point values, uniformly distributed over the interval [0.0 , 1.0].
Random value in [0, 1[ (including 0, excluding 1):
double val = ((double)arc4random() / UINT32_MAX);
A bit more details here.
Actual range is [0, 0.999999999767169356], as upper bound is (double)0xFFFFFFFF / 0x100000000.