Math.random()の致命的な2つの欠点

Pocket

javascriptの乱数生成にはMath.randomという呪文があらかじめ用意されていますが、実際に使ってみると不便でしょうがないです。

致命的な欠点が2つあるので紹介します。

seed値が設定できない

こちらの記事で詳しく説明してありますが、乱数を扱う上でとても重要な「seed値」が設定できません。

これによりゲームでよくある「リプレイ」機能が実装できません。

これは大問題ですね。

HTML上でゲームを公開する場合(HTMLとjavascriptは仲がいい)なんかだと致命的です。

乱数に偏りがある

こちらさいころ振り放題マシーンを使って説明します。

ボタンに表示されている数だけさいころを振って、出目を勝手に集計してくれるというものです。

120回振った結果がこちら。

1が29回、

3が13回。

とてつもなく偏ってますね。

120000回振った結果がこちら。

たくさん振ると、偏りは目立たなくなりました。

どういうことなんでしょうか。

あ、ソースコードです。

<form name="js">
<input type="button" name="x" onclick="go(120)" value="120">
<input type="button" name="x" onclick="go(1200)" value="1200">
<input type="button" name="x" onclick="go(12000)" value="12000">
<input type="button" name="x" onclick="go(120000)" value="120000">
</form>

<script>
function go(a){

let da = 0;
let db = 0;
let dc = 0;
let dd = 0;
let de = 0;
let df = 0;

for (let i=0;i<a;i++){
let b = Math.floor(Math.random() * 6);
let c;

switch (b){

case 0 :c=1;da++;break;
case 1 :c=2;db++;break;
case 2 :c=3;dc++;break;
case 3 :c=4;dd++;break;
case 4 :c=5;de++;break;
default :c=6;df++;break;

}}
document.write("1:" + da + "
");
document.write("2:" + db + "
");
document.write("3:" + dc + "
");
document.write("4:" + dd + "
");
document.write("5:" + de + "
");
document.write("6:" + df);
return;
}
</script>

new Array()という配列の呪文を使うとここまでたくさんの変数を使わずに済み、もう少しスッキリした見た目になりますし、工夫すれば、0または1~上限なしに数を格納できます。

まとめ

  • seed値が設定できない
  • 精度に難あり

こちらの最後に紹介したとおり、メルセンヌツイスターというもっと便利で優秀な乱数発生の呪文が公開されています。

こちらの方が、コードを書く際も何かと便利です。