Reputation: 18149
int chance = -5;
int rand = arc4random() % 100; // Number from 0 to 99
if (rand <= chance) { // This will never happen
NSLog(@"This is... NOT POSSIBLE");
}
Effectively, this never happens. But
int chance = -5;
if (arc4random() % 100 <= chance) {
NSLog(@"This is... NOT POSSIBLE");
}
Here, instead of storing it in a variable, I placed the random number expression directly in the condition. And the condition is fulfilled (sometimes).
Why is that? How can I debug this behavior?
Upvotes: 3
Views: 220
Reputation: 224864
Type promotion rules.
arc4random
returns an unsigned value. That means in your second case, the -5
gets promoted to that same unsigned type, turning it into 4294967291
. 4+ billion is definitely larger than any number 0-99!
Let's walk through what happens in both of your examples.
From your first example, in this line:
int rand = arc4random() % 100;
arc4random()
returns an unsigned value. So then it looks like:
int rand = someUnsignedNumber % 100;
The 100
is a signed int, so it gets promoted to the same type as someUnsignedNumber
, and the %
operation is applied. After that you have:
int rand = someUnsignedNumberBetween0And99;
Assigning that unsigned number to int rand
makes it back into a signed number. Your comparison then goes forward as expected.
In the second example, you have this line:
if (arc4random() % 100 <= chance)
The same things happen with arc4random() % 100
, yielding something like:
if (someUnsignedNumberBetween0And99 <= chance)
But here, chance
is a signed number. It gets promoted, changing its value as described above, and you end up with the strange behaviour you're seeing.
Upvotes: 6
Reputation:
Silly, silly type system of C... If you read the man page for arc4random()
, you find out that its prototype is
u_int32_t arc4random(void);
So it returns an unsigned integer.
When comparing its - unsigned - result with another integer, the unsignedness "wins": the other value (-5
) is promoted to the unsigned type (u_int32_t
in this case), it rolls over (since unsigned integer "underflow" is designed to work like this in C - you'll get 2 ^ 32 - 5
) and so an "erroneous" (i. e. behaving-as-unexpected) comparison occurs.
When you explicitly assign the value to an int
(i. e. signed) variable, this promotion does not occur since the comparison is between two signed types, so it is evaluated as you would expect.
Upvotes: 5