3

我正在尝试使用 -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);
}

为什么会这样?

4

3 回答 3

3

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

无论如何,在生成随机数时,最好使用arc4random_uniform,这样可以避免代码的模偏差。这种偏差几乎无法观察到,但尽管如此,您应该使用:

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

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

NSInteger random = (NSInteger)arc4random_uniform(121) - 60;
于 2013-10-14T22:24:48.550 回答
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()over modulo 结构:

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

于 2013-10-14T22:22:53.593 回答
0

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

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

正如@Rob 在他的回答中所说,使用arc4random_uniform而不是修改来获得一个范围以消除偏见。

于 2013-10-14T22:26:29.133 回答