为什么我会使用NSInteger和arc4random获得奇怪的垃圾?

时间:2013-10-14 22:02:59

标签: objective-c random nsinteger arc4random

我试图在-60和60之间使用arc4random获取一个随机数。我生成1到120之间的avnumber,然后减去60.

如果这是一行,只要数字是负数,我就会得到奇怪的结果。

//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);
}

为什么会这样?

3 个答案:

答案 0 :(得分:3)

我怀疑问题源于arc4random在0和(2 ** 32)-1之间返回u_int32_t(无符号32位整数)这一事实,但仅进行计算适用于有符号整数。

无论如何,在生成随机数时,最好使用arc4random_uniform,这样可以避免代码的模偏差。这种偏见几乎不会被观察到,但是你应该使用:

NSInteger random = 1 + (NSInteger)arc4random_uniform(120) - 60;

或者,从技术上讲,如果你想要包含-60到60之间的数字,你应该使用:

NSInteger random = (NSInteger)arc4random_uniform(121) - 60;

答案 1 :(得分:1)

arc4random()返回无符号整数,1 + (arc4random() %120) - 60;被解释为无符号,然后分配给NSInteger random1

您可以将(arc4random() %120)的返回值强制转换为有符号整数:

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

或将arc4random()的中间结果存储在无符号整数中:

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


另请注意,arc4random手册页建议使用arc4random_uniform()而不是模数构造:

  

arc4random_uniform()建议使用像``arc4random()%upper_bound''这样的结构,因为它避免了        当上限不是2的幂时,“模偏”。

答案 2 :(得分:0)

对于初学者arc4random(),返回u_int32_t无符号32位数。无符号数不能为负数,因此减去大于无符号值的数字会导致未指定的行为。

在第二种情况下,您将mod'ed值分配给可以具有负数的有符号整数。

正如@Rob在他的回答中所述,使用arc4random_uniform代替mod'ing来获得范围以消除偏见。