min から max のランダムな整数
重要性: 2
取りうる値として min
と max
を含む、min
から max
のランダムな 整数 値を生成する関数 randomInteger(min, max)
を作りなさい。
範囲 min..max
からの任意の値は、同じ確率で現れなければいけません。
動作例:
alert
(
random
(
1
,
5
)
)
;
// 1
alert
(
random
(
1
,
5
)
)
;
// 3
alert
(
random
(
1
,
5
)
)
;
// 5
シンプルだが間違った解法
最もシンプルで、しかし間違った解法は、min
から max
の値を生成してから丸める方法です:
function
randomInteger
(
min,
max
)
{
let
rand =
min +
Math.
random
(
)
*
(
max -
min)
;
return
Math.
round
(
rand)
;
}
alert
(
randomInteger
(
1
,
3
)
)
;
この関数は動きますが、間違っています。境界値 min
と max
を得る確率は他の値の半分になります。
上の例を複数回実行してみると、2
が他より多く現れることに簡単に気付くでしょう。
これは、Math.round()
が 1..3
のランダムな数値を取った後に、次のように丸めるためです:
1
から 1.4999999999
までの値は 1
になります
1.5
から 2.4999999999
までの値は 2
になります
2.5
から 2.9999999999
までの値は 3
になります
これで、1
が 2
の半分しか取得できないことが明白に分かりますね。3
についても同様です。
正しい解法
このタスクを正しく解く方法はたくさんあります。一例は、区間の端を調整することです。同じ区間となるように、値を 0.5 から 3.5
の間で生成します。そうすると境界値の発生確率が上がります:
function
randomInteger
(
min,
max
)
{
// rand は (min-0.5) から (max+0.5) になりました
let
rand =
min -
0.5
+
Math.
random
(
)
*
(
max -
min +
1
)
;
return
Math.
round
(
rand)
;
}
alert
(
randomInteger
(
1
,
3
)
)
;
もう一つの例は、min
から max+1
のランダムな数値に対して Math.floor
を使う方法です。
function
randomInteger
(
min,
max
)
{
// ここでは rand は min から (max+1) です
let
rand =
min +
Math.
random
(
)
*
(
max +
1
-
min)
;
return
Math.
floor
(
rand)
;
}
alert
(
randomInteger
(
1
,
3
)
)
;
ここでは、区間は次のように割り当てられます:
1
から 1.9999999999
の値は 1
になります
2
から 2.9999999999
の値は 2
になります
3
から 3.9999999999
の値は 3
になります
全ての区間は同じ長さを持つため、最終的な分布が等しくなります。