Math.random()
(およびほとんどの疑似乱数ジェネレータ、AFAIK)が生成するため、以下にリストされている関数を使用して、目的の範囲[X,Y)
(Xは包括的で、Yは排他的であることに注意)内のランダムな浮動小数点数を簡単に取得できます。 [0,1)
の数字:
function randomInRange(min, max) {
return Math.random() * (max-min) + min;
}
// Notice that we can get "min" exactly but never "max".
どうすれば、両方の境界に望ましい範囲を含むの乱数、つまり[X,Y]
を取得できますか?
IEE-754浮動小数点倍精度 のビットを「ローリング」して、可能な最大値を1.0にすることにより、Math.random()
(または同等のもの)から値を「インクリメント」できると思います正確ですが、特にビット操作にあまり適していない言語では、それを正しく行うのは面倒なようです。もっと簡単な方法はありますか?
(余談ですが、なぜ乱数ジェネレータは[0,1)
ではなく[0,1]
で数値を生成するのですか?)
[編集]これには必要がないことに注意してください。教訓的です。好奇心旺盛で興味深い答えを期待しています。この質問が不適切な場合は、自由に投票して終了してください。
私はもっと良い決断があると信じていますが、これはうまくいくはずです:)
function randomInRange(min, max) {
return Math.random() < 0.5 ? ((1-Math.random()) * (max-min) + min) : (Math.random() * (max-min) + min);
}
この問題に対する私の解決策は、常に上限の代わりに以下を使用することでした。
Math.nextAfter(upperBound,upperBound+1)
または
upperBound + Double.MIN_VALUE
したがって、コードは次のようになります。
double myRandomNum = Math.random() * Math.nextAfter(upperBound,upperBound+1) + lowerBound;
または
double myRandomNum = Math.random() * (upperBound + Double.MIN_VALUE) + lowerBound;
これは単に、上限を最小のdouble(Double.MIN_VALUE
)だけインクリメントするため、上限はランダム計算の可能性として含まれます。
これは、1つの数値を優先して確率を歪めないため、これを回避するのに適した方法です。
これが機能しない唯一のケースは、上限がDouble.MAX_VALUE
に等しい場合です。
まず、コードに問題があります:randomInRange(0,5e-324)
を試すか、ブラウザのJavaScriptコンソールにMath.random()*5e-324
と入力してください。
オーバーフロー/アンダーフロー/デノルムがなくても、浮動小数点演算について確実に推論することは困難です。少し掘り下げた後、私は反例を見つけることができます:
_>>> a=1.0
>>> b=2**-54
>>> Rand=a-2*b
>>> a
1.0
>>> b
5.551115123125783e-17
>>> Rand
0.9999999999999999
>>> (a-b)*Rand+b
1.0
_
これがa = 2で発生する理由を説明する方が簡単です53 およびb = 0.5:253-1は、次に表現可能な数です。デフォルトの丸めモード(「最も近い偶数に丸める」)は2を丸めます53-0.5アップ(2のため53 「偶数」[LSB = 0]および253-1は「奇数」[LSB = 1])なので、b
を減算して2を取得します53、乗算して2を取得53-1、b
を追加して2を取得53 再び。
2番目の質問に答えるには、基になるPRNGは、ほとんどの場合、間隔[0,2ん-1]、つまりランダムなビットを生成します。適切なn(浮動小数点表現の精度のビット)を選択して2で除算するのは非常に簡単ですん 予測可能な分布を取得します。 _[0,1)
_にはいくつかの数値があることに注意してくださいneverこのメソッドを使用して生成します((0,2-53)IEEEダブルスを使用)。
また、オーバーフローを心配せずにa[Math.floor(Math.random()*a.length)]
を実行できることも意味します(宿題:IEEEバイナリ浮動小数点では、_b < 1
_が正の整数a
に対して_a*b < a
_を意味することを証明します)。
もう1つのいい点は、各ランダム出力xを間隔[x、x + 2-53)(あまり良くないのは、返される平均値が0.5をわずかに下回ることです)。 [0,1]に戻った場合、他のすべてと同じ確率でエンドポイントを返しますか、それとも他のすべての場合と同じように間隔の半分しか表さないため、エンドポイントは半分の確率しかありませんか?
[0,1]に数値を返すという簡単な質問に答えるために、以下のメソッドは整数[0,2]を効果的に生成しますん]([0,2n + 1-1]そして、それが大きすぎる場合は捨て、2で割るん:
_function randominclusive() {
// Generate a random "top bit". Is it set?
while (Math.random() >= 0.5) {
// Generate the rest of the random bits. Are they zero?
// If so, then we've generated 2^n, and dividing by 2^n gives us 1.
if (Math.random() == 0) { return 1.0; }
// If not, generate a new random number.
}
// If the top bits are not set, just divide by 2^n.
return Math.random();
}
_
コメントはベース2を意味しますが、私はthinkであると想定されています。
乱数は常にペアで生成されることに注意してください。while
(a)内の乱数の後には常にif
内の乱数または末尾(b)内の乱数が続きます。 0または0.5を返すPRNGを検討することで、それが賢明であることを確認するのはかなり簡単です。
a=0 b=0
_:0を返しますa=0 b=0.5
_:0.5を返しますa=0.5 b=0
_:1を返すa=0.5 b=0.5
_:ループ問題:
選択した閉じた間隔がサブセットになるように、半分開いた間隔をわずかに大きくするだけです。次に、ランダムな変数を生成して、それが上記の閉じた間隔になるまで続けます。
例:[3,8]で均一なものが必要な場合は、[3,8]に到達するまで、[3,9)で均一なランダム変数を繰り返し再生成します。
function randomInRangeInclusive(min,max) {
var ret;
for (;;) {
ret = min + ( Math.random() * (max-min) * 1.1 );
if ( ret <= max ) { break; }
}
return ret;
}
注:ハーフオープンR.Vを生成する回数。はランダムで無限の可能性がありますが、予想される呼び出し回数はそれ以外の場合は1に近づけることができます。また、無限に何度も呼び出さない可能性のあるソリューションは存在しないと思います。
0と1の間の値の「非常に大きい」数を考えると、それは本当に重要ですか? 実際にが1に当たる可能性は非常に低いため、実行していることに対して大きな違いが生じる可能性はほとんどありません。
私はかなり経験が少ないので、解決策も探しています。
これは私の大まかな考えです:
乱数ジェネレータは、[0,1]ではなく[0,1)で数値を生成します。
[0,1)は、[1,2)などが続くユニット長で、重複することなく...
Random [x、y]の場合、これを行うことができます:
float randomInclusive(x, y){
float MIN = smallest_value_above_zero;
float result;
do{
result = random(x, (y + MIN));
} while(result > y);
return result;
}
[x、y]のすべての値が選択される可能性が同じで、uがyに到達できる場合。
これが機能しない場合、または潜在的な問題がある場合はお知らせください。
ありがとう〜
private static double random(double min, double max) {
final double r = Math.random();
return (r >= 0.5d ? 1.5d - r : r) * (max - min) + min;
}
Math.round()
は、バインドされた値を含めるのに役立ちます。 _0 <= value < 1
_(1は排他的)がある場合、Math.round(value * 100) / 100
は_0 <= value <= 1
_(1は包括的)を返します。ここでの注意は、値の小数点以下の桁数が2桁になっていることです。 3桁が必要な場合は、Math.round(value * 1000) / 1000
などを試します。次の関数にはもう1つのパラメーターがあります。つまり、小数点以下の桁数です。私はprecisionと呼びます。
_function randomInRange(min, max, precision) {
return Math.round(Math.random() * Math.pow(10, precision)) /
Math.pow(10, precision) * (max - min) + min;
}
_
質問は尋ねるのと似ています1.0の直前の浮動小数点数は何ですか?そのような浮動小数点数がありますが、これは2 ^ 24分の1です(IEEE float
の場合) )または2 ^ 53分の1(double
の場合)。
違いは実際には無視できます。
これはどう?
function randomInRange(min, max){
var n = Math.random() * (max - min + 0.1) + min;
return n > max ? randomInRange(min, max) : n;
}
これでスタックオーバーフローが発生した場合、プレゼントを購入します。
-編集:現在のことを気にしないでください。私は野生になりました:
randomInRange(0, 0.0000000000000000001)
スタックオーバーフローが発生しました。
上限を含めるために浮動小数点値が必要になる状況は何でしょうか?整数については理解できますが、浮動小数点については、包含と排他の違いは1.0e-32のようなものです。
このように考えてください。浮動小数点数が任意の精度であると想像すると、正確にmin
を取得する可能性はゼロです。 max
を取得する可能性もあります。私はあなたにあなた自身の結論を出させます。
この「問題」は、0と1の間の実線上のランダムな点を取得することと同等です。「包括的」と「排他的」はありません。