Search code examples
iosarmarc4random

arc4random_uniform( ) and different behaviour with arm64


Given the following code NSInteger random = arc4random_uniform(3) - 1;

this code compiled for armv7, armv7 and i386 (tested on an iPhone 5 and iOS Simulator) produce an uniform distribution of the element {-1,0,1}; but when compiled for arm64 and run on iPhone 5s it produce {4294967295, 0, 1}?


Solution

  • arc4random_uniform returns an an unsigned int, - 1 on it will return you to the largest 32 bit integer size 4294967295.

    You'll need to cast arc4random_uniform(3) into an int before you can -1 on it.

    Example of the 64-bit 32-bit unsigned/signed integer problem

    Rule 4: The sum of a signed value and an unsigned value of the same size is an unsigned value.

    int a=-2;
    unsigned int b=1;
    long c = a + b;
    long long d=c; // to get a consistent size for printing.
    

    printf("%lld\n", d); Problem: When this code is executed in the 32-bit runtime, the result is -1 (0xffffffff). When the code is run in the 64-bit runtime, the result is 4294967295 (0x00000000ffffffff), which is probably not what you were expecting.

    Cause: Why does this happen? First, the two numbers are added. A signed value plus an unsigned value results in an unsigned value (rule 4). Next, that value is promoted to a larger type. This promotion does not cause sign extension.

    Solution: To fix this problem in a 32-bit-compatible way, cast b to a long integer. This cast forces the non-sign-extended promotion of b to a 64-bit type prior to the addition, thus forcing the signed integer to be promoted (in a signed fashion) to match. With that change, the result is the expected -1.

    stolen from the apple 64-Bit Transition Guide.