アダムの答えは正しいです。ただし、2 つの違いを明確にするために、2 番目のものは可能な範囲を 1 つ上げて、範囲を包括的にします。覚えておくべき重要なことは、モジュロは剰余除算であるため、toNumber
可能な結果はあるものの、そのうちの 1 つがゼロ ( の結果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 です。
modulo を使用する場合、どちらも正しくも正しくもありません。1 つは上限範囲を含まず、もう 1 つは上限範囲を含みます。ただし、剰余除算がどのように機能するかを考え、PRNG によって返される数値のプールをサイクル全体の範囲の長さで考えると、範囲が最大範囲の最大範囲に均等に分割されない場合に気付くでしょう。偏った結果が得られるプール。たとえば、arc4random()
が 1 ~ 5 の結果を返した場合 (明らかにそうではありません)、0 ~ 2 の数値が必要で、 を使用した場合arc4random() % 3
、これらは可能な結果です。
1 % 3 = 1
2 % 3 = 2
3 % 3 = 0
4 % 3 = 1
5 % 3 = 2
2 つの 1 と 2 つの 2 がありますが、0 は 1 つだけであることに注意してください。これは、3 の範囲が PRNG の 5 の範囲に均等に分割されないためです。その結果、(滑稽なことに)PRNG range % desired range
サイクルの最後の数字は「偏っている」ため、選別する必要があります。数字自体はそうではありません。本当に偏っていますが、最後から選別する方が簡単です。これを行わないと、範囲の低い数値が表示される可能性が高くなります。
生成できる数値の上限を計算し、それを目的の範囲でモジュロして、それらの数値を最後から引き出すことで、数値を選別できます。「それらの数字を最後から引き出す」とは、「最後の数字ではない数字が得られるまで無限にループする」ことを意味します。
それは悪い習慣だと言う人もいます。理論的には永久にループできます。ただし、実際には、モジュロ バイアスが PRNG の数のプールの半分を超えることはないため (通常はそれよりはるかに少ない)、予想される再試行回数は常に 1 未満です。rand
私はかつて、この手法を使用するためのラッパーを書きました。
この例は、OpenBSD のソースで見ることができます。ここでは、番号がクリーンであると判断されるまでarc4random_uniform
呼び出しがループします。arc4random