0

我是目标 C 的新手,并试图理解arc4random().

网上有很多相互矛盾的解释。请清除我的困惑,以下哪个是正确的:

// 1.
 arc4random() % (toNumber - fromNumber) + fromNumber;

或者

//2.
arc4random() % ((toNumber - fromNumber) + 1) + fromNumber; 

//toNumber-fromNumbers are any range of numbers like random # between 7-90.
4

2 回答 2

6

此代码将为您提供 7 到 90 之间的随机数。

NSUInteger random = 7 + arc4random_uniform(90 - 7);

用于arc4random_uniform避免模偏差。

于 2013-03-11T16:32:05.913 回答
4

亚当的回答是正确的。但是,只是为了澄清两者之间的区别,第二个将可能的范围提高了 1 以使范围包含在内。需要记住的重要一点是,模是余数除法,因此虽然有toNumber可能的结果,但其中一个是零(如果 的结果arc4random()是 的倍数toNumber)并且toNumber本身不能是余数。

// 1.
 arc4random() % (10 - 5) + 5;

这导致范围0 + 54 + 55 到 9。

//2.
arc4random() % ((10 - 5) + 1) + 5; 

这导致范围0 + 5(4 + 1) + 55 到 10。

如果您想使用模数,则既不正确也不不正确。一个不包括上限,另一个包括上限。但是,如果您考虑余数除法的工作原理并考虑任何 PRNG 返回的数字池以周期为单位的总范围长度,那么您会意识到,如果范围没有均匀地划分为最大范围你会得到有偏见的结果。例如,如果arc4random()返回一个从 1 到 5 的结果(显然不是)并且您想要一个从 0 到 2 的数字,并且您使用arc4random() % 3了 ,那么这些是可能的结果。

1 % 3 = 1
2 % 3 = 2
3 % 3 = 0
4 % 3 = 1
5 % 3 = 2

请注意,有两个一和两个二,但只有一个零。这是因为我们的 3 范围并没有均匀地划分为 PRNG 的 5 范围。结果是(足够幽默)PRNG range % desired range循环结束时的数字需要被剔除,因为它们是“有偏见的”——数字本身不是确实有偏见,但从最后剔除更容易。不这样做会导致范围的较小数字变得更有可能出现。

我们可以通过计算我们可以生成的数字的上限来剔除这些数字,将其与所需的范围取模,然后将这些数字从末尾拉出。通过“从末尾拉出这些数字”,我的真正意思是“无限循环,直到我们得到一个不是末尾数字之一的数字”。

有人会说这是不好的做法;理论上你可以永远循环。然而,在实践中,预期的重试次数总是小于 1,因为模偏差永远不会超过 PRNG 数量池的一半(通常远小于该数量)。我曾经为rand使用这种技术编写了一个包装器。

您可以在OpenBSD的源代码中看到一个这样的示例,其中循环arc4random_uniform调用arc4random,直到确定一个数字是干净的。

于 2013-03-11T18:25:12.990 回答