Search code examples
objective-ccastingfloating-pointintegerarc4random

arc4random_uniform producing very large values when casting to float


Blank project. Code:

int i = 0;
while (i < 8) {
    float amount = 100-arc4random_uniform(200);
    NSLog(@"amount: %f", amount);
    i++;
}

Log:

amount: 21.000000
amount: 90.000000
amount: 79.000000
amount: 4294967296.000000
amount: 39.000000
amount: 4294967296.000000
amount: 81.000000
amount: 4294967296.000000

4294967296.000000 is clearly outside the range of 100 - ran(200) (pseudocode)

If I don't declare amount as float and instead use int this doesn't happen.

What's going on here?


Solution

  • As @rob points out, arc4random_uniform returns a 32-bit unsigned integer type (uint32_t), that is, a number greater than or equal to zero, never negative. The compiler thus evaluates the expression 100-arc4random_uniform(200) expecting the result also to be an unsigned number.

    If the result of arc4random_uniform(200) in your example code happens to be greater than 100, then 100-arc4random_uniform(200) will result in a negative number being assigned to a data type that cannot express negative numbers, so you'll end up with unexpected results.

    You can indicate to the compiler that you want to be dealing with signed numbers by, as @rob suggests, casting the result of arc4random_uniform to a signed number (in this case a float):

    float amount = 100 - (float)arc4random_uniform(200);
    

    ...or by indicating that the expression should return a signed number by explicitly making your other argument a signed number:

    float amount = 100.0f - arc4random_uniform(200);