亞當的答案是正確的。然而,爲了澄清這兩者之間的差異,第二個提出了可能的範圍,使範圍包括在內。需要記住的重要一點是模數是餘數的劃分,所以雖然有可能的結果,但其中一個爲零(如果arc4random()
的結果是toNumber
的倍數),並且toNumber
本身不能爲餘數。
// 1.
arc4random() % (10 - 5) + 5;
這導致到4 + 5
一系列0 + 5
,這是5至9。
//2.
arc4random() % ((10 - 5) + 1) + 5;
這導致到(4 + 1) + 5
一系列0 + 5
,這是5〜10。
如果您希望使用模數,那麼它們都不正確或不正確。一個不包括上限,而另一個包含上限。但是,如果您考慮剩餘部分的工作方式,並考慮任何PRNG在循環總長度範圍內返回的數字池,那麼您會意識到如果範圍沒有均勻分配到最大範圍游泳池你會得到偏見的結果。例如,如果arc4random()
返回1到5的結果(顯然不是這樣),並且您想要一個從0到2的數字,並且您使用arc4random() % 3
,則這些是可能的結果。
1 % 3 = 1
2 % 3 = 2
3 % 3 = 0
4 % 3 = 1
5 % 3 = 2
請注意,有兩個1和兩個2,但只有一個零。這是因爲我們的3的範圍並不等於PRNG的5範圍。結果是(足夠幽默地)在週期結束時的數字需要被撲滅,因爲它們是「偏向」的 - 數字本身不是'沒有什麼偏見,但從最後更容易剔除。未能做到這一點會導致範圍的數字越小越容易出現。
我們可以通過計算我們可以生成的數字的上限範圍來篩選數字,用期望的範圍對其進行模數化,然後將這些數字從結尾中拉出。通過「將這些數字拉掉」我的意思是「無限循環,直到我們得到一個不是最終數字的數字」。
有人會說這是不好的做法;你可以在理論上永遠循環。然而,在實踐中,預期的重試次數總是小於1次,因爲模數偏差永遠不會超過PRNG數值的一半(通常小得多)。我曾使用這種技術爲rand
寫過封裝。
您可以在source for OpenBSD中看到一個示例,其中arc4random_uniform
在循環中調用arc4random
,直到數字被確定爲乾淨。
你想讓號碼成爲可能的價值還是應該排除? – Vladimir 2013-03-11 16:29:56
你的問題可能會更清楚。你有關於函數返回值的問題,或者你對模塊操作員完成什麼有疑問嗎? – WeakPointer 2013-03-11 19:38:05