我是目标C的新手,并试图理解arc4random()
。
网上有太多相互矛盾的解释。请清除我的困惑,以下哪项是正确的:
// 1.
arc4random() % (toNumber - fromNumber) + fromNumber;
OR
//2.
arc4random() % ((toNumber - fromNumber) + 1) + fromNumber;
//toNumber-fromNumbers are any range of numbers like random # between 7-90.
答案 0 :(得分:6)
此代码将为您提供7到90之间的随机数。
NSUInteger random = 7 + arc4random_uniform(90 - 7);
使用arc4random_uniform
来避免模偏差。
答案 1 :(得分:4)
亚当的回答是正确的。然而,为了澄清两者之间的差异,第二个将可能的范围提高一个以使范围包含。要记住的重要一点是模数是余数除法,因此虽然有toNumber
个可能的结果,但其中一个为零(如果arc4random()
的结果是toNumber
的倍数)并且toNumber
本身不能成为其余部分。
// 1.
arc4random() % (10 - 5) + 5;
这导致范围为0 + 5
到4 + 5
,即5到9。
//2.
arc4random() % ((10 - 5) + 1) + 5;
这会产生0 + 5
到(4 + 1) + 5
的范围,即5到10。
如果您希望使用模数,则不正确或不正确。一个是上限范围,另一个是上限。但是,如果您考虑余数除法如何工作并考虑任何PRNG返回的数字池的周期长度,那么您将意识到如果范围不均匀分配到最大范围在游泳池你会得到偏见的结果。例如,如果arc4random()
返回的结果为1到5(显然不是),并且您想要一个0到2之间的数字,而您使用arc4random() % 3
,则可能会产生这些结果。< / p>
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
编写了一个包装器。
您可以在source for OpenBSD中看到此示例,其中arc4random_uniform
在循环中调用arc4random
,直到确定某个数字是干净的。