彩りの大地 Laboratory 確率計算機

確率計算機 Ver.2.0

確率○○を××回やった場合に△△回出る確率



説明書

その通り、確率○○を××回やった場合に△△回出る確率を求める計算機です。
以前は”少なくとも1回”を算出するための計算機でしたが、Ver.2.0 からは 2回以上のヒット数でも算出可能なアルゴリズムへと仕様変更しました。

トライ確率は確率○○、つまり、試行する際の確率を記入します。記入フォーマットは百分率、または分数も可能です。
※百分率の場合「50%」なら「50」のように「%」抜きで数値のみを記入、分数の場合は「1/256」のようなスタイルで記入
トライ回数は××回、つまり、トライ確率に対して試行する時の回数を記入します。
ヒット回数は△△回、つまり、少なくとも1回なら1を、3回なら3回と記入します。
結果は「計算結果」の欄に表示されます。 算出結果は小さな値が想定されるため、四捨五入処理はしておらず、「%」スタイル処理(要するに内部的に100倍する処理)もしていないので、常用対数による指数表記(後述参照)を考慮して素の値がそのまま出ます。

計算ボタンがないのですが、入力フォームからフォーカス(入力可能状態)が外れるたびに計算されるようにしているため、 何もないところなど、適当なところをクリックすればいいと思います。

ソースについて


// 例によって、出力からinnerHTMLを使用したスクリプトでコントロールしています。
function calc1() {
	var txt = "";
	
	txt += "<form action='#n1' name='fm'>";
	txt += "トライ確率 : <input type='text' id='prb' value='5' onblur='calc2()'><br>";
	txt += "トライ回数 : <input type='text' id='try' value='10' onblur='calc2()'><br>";
	txt += "ヒット回数 : <input type='text' id='hit' value='1' onblur='calc2()'><br>";
	txt += "</form>";
	
	document.getElementById('inst').innerHTML = txt;
}
function calc2() {
	var i, j;
	var pert = 100;
	var testprb, enprb, entry, enhit;
	var com, ans;
	
	testprb = document.getElementById('prb').value.split("/");
	if(testprb.length == 1){
		pert = 1;
		testprb[1] = "1";
	}
	
	enprb = Number(testprb[0]) / Number(testprb[1]) * pert;
	enprb = Math.min(enprb, 100);
	enprb = Math.max(enprb, 0);
	
	entry = Number(document.getElementById('try').value);
	entry = Math.max(entry, 0);
	
	enhit = Number(document.getElementById('hit').value);
	enhit = Math.min(enhit, entry);
	enhit = Math.max(enhit, 1);
	
	// A と B の好きなほうを選んでね
	// デフォルトでは B を有効にしています
	
	// A.確率が n の時に 試行回数が m 回の場合に少なくとも1回出る確率 p を求める場合はこちら
	// ans = (1 - Math.pow((100 - enprb)/ 100, entry));
	// A.ここまで
	
	// B.確率が n の時に 試行回数が m 回の場合に少なくとも k 回出る確率 p を求めたい場合はこちら
	com = 1;
	for(i = entry, j = enhit; j > 0; i--, j--){
		com *= i / j;
	}
	
	ans = com * Math.pow(enprb / 100, enhit);
	ans = ans * Math.pow((100 - enprb)/ 100, (entry - enhit));
	// B.ここまで
	
	document.getElementById('anst').innerHTML = " 計算結果 : " + ans;
}
window.addEventListener('load', function() { 
	calc1();
	calc2();
}

能書き

確率の入力値の百分率と分数の区別は「/」が入っているかどうかで判別しています。
「/」がない場合は百分率と解釈し、testprb[0]に百分率の値を入れます。
「/」が入っている場合は分数と解釈するため、testprb[0]に分子を、testprb[1]に分母を入れて計算します。 ただし、計算過程においては百分率の値として計算するため、計算結果にpertへ代入されている100を乗じます。

確率が n の時に 試行回数が m 回の場合に少なくとも1回出る確率 p を求める計算式は以下のように求められます。
これをやっているのがソースの「A.」の式です。

p = 1 - (1 - n)^m

それと、確率 1/a の時に 試行回数が a 回の場合に少なくとも1回出る確率はたいてい 63% 程度で収束します。
※ a が大きな数値の場合
99%以上を狙う場合は a×5 ぐらいの試行回数が必要です。

さらに、確率が n の時に 試行回数が m 回の場合に少なくとも k 回出る確率 p を求める計算式は以下のように求められます。
これをやっているのがソースの「B.」の式です。

p = (m C k) * n^k * (1 - n)^(m - k)

※ C は組み合わせです。順列(P)と組み合わせ(C)と階乗(!)のあれです。覚えてますか?
 n! = n * (n - 1) * (n - 2) * ... * 2 * 1 → n から 1 までの整数値全部を乗算する
 m P k = m * (m - 1) * (m - 2) * ... → m から 1 に向かってk回目までの整数値全部を乗算する
 m C k = (m P k) / k! → 順列を階乗で除算する

組み合わせの計算結果(com)を求めるため、for文の繰り返し処理を利用して、 大きな値から順に順列(P)の掛け算と階乗(!)の割り算をして実現しています。

なお、算出結果の値が小さすぎると常用対数(e)表記になります。
簡単に言えば、書いてある分だけ小数点を移動してくださいってことです。
e-12 → 小数点を左に12個移動
e+12 → 小数点を右に12個移動

また、ちょっとした異常値補正も入っています。
入力の異常値については特に処理していないので、計算結果はエラーを示します。
確率を負の値にすると0と解釈し、100を超えた数値にすると100として解釈します。
ヒット回数>トライ回数とすると、ヒット回数はトライ回数と同値で解釈します。