Math.random()
0 から 1 (1.0 を除く) までの「実数」を返します。
それは素晴らしいことですが、1 から 2 までの「実数」が必要な場合はどうすればよいでしょうか。
答え: [0,1) を [1,2) に「変換」します。
実際には、結果に 1 を加算することを意味します。
試してみてください -- Math.random()+1
1 から 2 までの数字が表示されます。
数学では、これは「マッピング」として知られています。つまり、[0,1) のすべての可能な実数について、その実数を [1,2) の別の実数に「マッピング」する方法を見つけます。つまり、[0,1) の間の実数を与えた場合、その数をマッピングできるはずです。[1,2) の間の数を返す関数にその数を適用します。
この場合、関数 f(x) = x+1 です。
[1,2) の間の乱数がどのように得られるかわかりましたか? 隣り合う 2 つの間隔を視覚化し、[0,1) のすべての点から [1,2) の対応するマップに向かう線を想像してください。次に、[0,1) 上のランダムな点を選び、線をたどります。[1,2) のランダムな点まで線をたどります!
[0,1) から [1,2) へのすべての完全な 1 対 1 マップは、[0,1) の間の乱数を [1,2) の間の乱数に変換します...しかし、すべてではありません。 [1,2) の間で均等に分散された乱数が得られます。均等に分散された結果を与えるマップの背後にある数学は少し複雑ですが、要するに、マップが定数による加算、減算、乗算、および除算のみを含む場合、結果も均等に分散されるという意味で「合法」です。
これで、[0,1) を [1,2) に変換する方法がわかりました。
[0,1) を [0,2) にマップしたい場合はどうすればよいですか? もう数字の足し算はできません...
すべてを 2 倍したらどうですか。
これは機能するはずです -- 関数 f(x) = x*2 は実際に [0,1) 上のすべての点を [0,2) 上の点にマッピングします --- そして定数 (2) による乗算のみを含むため、これは分布を維持するマップです。
これはうまくいきます! Math.random()*2
0 から 2 の間の乱数が返されます。
さて、もう少し複雑なこと... [0,1) を [1,3) に変換します。
2 を掛けてもうまくいきません... 0*2 = 0 であり、それは目標範囲内ではありません。1 を追加しても機能しません... 0+1 が目標範囲内にあり、1+1 も目標範囲内にあるとしても、3 に到達する方法はありません。
[0,1) を [1,3) に変換できない場合は、別のものを [1,3) に変換できるかどうか試してみましょう。
[0,2) はどうですか? はい、これを行うことができます... 関数 f(x) = x+1 は [0,2) を [1,3) に完全にマップします。+
範囲を「シフト」すると考えることができます。
したがって、ここでの解決策は明らかです。最初に [0,1) を [0,2) に変更し、次に [0,2) を [1,3) に変更します。
1 つ目 (f(x) = x*2) は既にわかっており、2 つ目 (f(x) = x+1) もわかっています。したがって、「結合された」変換/マップは f(x) = (x*2)+1 です。
つまりMath.random()*2 + 1
、0 から 3 までの数値が返されます。
最後のトリックとして、[0,1) を任意の範囲 [min,max) にマッピングします。
ここでの秘訣は、これを [min,min+range) のように書き直すことです。ここで、range = max-min.
ここで、範囲 [0,range) を [min,min+range) に変換するのは簡単であることがわかります。これに「min」を追加するだけです。したがって、範囲 [0,range) があり、[min,min+range) を取得したい場合、f(x) = x+min を使用します。
では、 [0,1) から [0,range) にするにはどうすればよいでしょうか?
範囲で乗算!
f(x) = (x*範囲) + 最小
range = max-min を使用して、元の用語に書き戻します。
f(x) = (x*(最大-最小)) + 最小
[0,1) の実数を [min,max) の実数に変換します。
残りは(便利な整数に変換して)あなたに任せます