Search code examples
objective-crandomnsintegerarc4random

Why am I getting strange garbage with NSInteger and arc4random?


I'm trying to get a random number using arc4random between -60 and 60. I generate avnumber between 1 and 120 inclusively, and then subtract 60.

If this is in one line, I get weird results whenever the number is negative.

//Loop illustrates point better.
while (1) {
    //Gets garbage numbers approximately half the time (when random1 should be negative)
    NSInteger random1 = 1 + (arc4random() %120) - 60;
    NSLog (@"random1: %li", random1);

    //Essentially same thing, but works fine.
    NSInteger random2 = 1 + (arc4random() %120);
    NSInteger random3 = random2 - 60;
    NSLog (@"random2: %li random3: %li", random2, random3);
}

Why does this happen?


Solution

  • arc4random() returns an unsigned integer, 1 + (arc4random() %120) - 60; is interpreted as unsigned, then assigned to NSInteger random1.

    You can either cast the return value of (arc4random() %120) to a signed integer:

    NSInteger random1 = 1 + (NSInteger)(arc4random() %120) - 60;
    

    or store the intermediate result of arc4random() in an unsigned integer:

    NSInteger r = (arc4random() %120);
    NSInteger random1 = 1 + r - 60;
    


    Also note that the arc4random man page recommends using arc4random_uniform() over modulo constructs:

    arc4random_uniform() is recommended over constructions like ``arc4random() % upper_bound'' as it avoids "modulo bias" when the upper bound is not a power of two.