jug7.com
[ home / cgi / juggler / column / diary / bbs / link / welcome ]
source : 二項分布
#!/usr/bin/perl
# 二項分布
$cginame = 'nikou.cgi';
$title = '二項分布';
$img = '../g.jpg'; # グラフに使用する画像
if ($ENV{'REQUEST_METHOD'} eq 'POST') {
read (STDIN, $input, $ENV{'CONTENT_LENGTH'});
}
foreach $str (split(/&/,$input)) {
($name,$value) = split(/=/, $str);
push(@input, $value);
}
($prob, $play, $hit) = @input;
print "Content-Type: text/html\n\n";
# ヘッダとフォームの表示
print <<"__ HTML __";
<!DOCTYPE html PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN'>
<html lang='ja'>
<head>
<meta http-equiv='Content-Type' content="text/html; charset=shift_jis">
<title>jug7.com - cgi $title</title>
<style type="text/css"> <!--
A:hover {color:#ff0000;}
--></style>
</head>
<body text='#000000' bgcolor='#ffffff' link='#0000ff' alink='#ff0000' vlink='#0000cc'>
<div align='right'>[ <a href='nikou_memo.html'>memo</a> / <a href='nikou.html'>source</a> / <a href='../index.html'>home</a> ]</div>
<br><br>
<div align='center'><h2>$title</h2></div>
<hr width='70%'><center>
<form action='$cginame' method='POST'>
<br>
<center>
1/ <input type='text' size=7 name='prob' value='$prob'> の確率で
<input type='text' size=7 name='play' maxlength=4 value='$play'> 回試行を行い、
<input type='text' size=7 name='hit' maxlength=4 value='$hit'> 回 当選。
<br><br>
<input type='submit' value="計算開始">
</center><br><br>
</form>
( 注意 : 平均値が50を超える場合、二項分布グラフと各確率の値は出力されません。 )
__ HTML __
# エラーチェックと GET での送信
if ($play>9999) { $error = 1; $er_msg = 'プレイ数は最大9999Pまでです。'; }
if (grep { /[^\d\.]/ } ($play, $hit, $prob)) { $error = 1; $er_msg = '不適切な文字が記入されています。'; };
if ($play < $hit) { $error = 1; $er_msg = '試行回数 < 当選回数 となっています。'; }
if (!$prob) { $error = 1; $er_msg = '確率を入力して下さい。または、確率の分母に 0 は記入できません。'; }
$ave = $play/$prob if($prob); # 平均値
if ($ENV{'REQUEST_METHOD'} ne 'POST') { $error = 1; $er_msg = 0; }
if ($er_msg) {
print q{<center><b><font color='red' size=4>*** ERROR !! ***</font><br><br>},"\n";
print "$er_msg</b></center>\n";
}
if ($error) {
print '<br><br><br><br><br>';
print q{<div align='right'>[ <a href='nikou_memo.html'>memo</a> / <a href='nikou.html'>source</a> / <a href='../index.html'>home</a> ]</div>};
exit;
}
#--------------
# 計算開始
#--------------
$prob0 = $prob; # 確率の分母
$prob = 1/$prob;
# 平均,分散,標準偏差,M±SD,M±2SD などの計算と出力
$var = $ave * (1-$prob); # variance 分散
$sd = sqrt($var); # standard deviation 標準偏差
$ave = &point($ave, 3);
$var = &point($var, 3);
$sd = &point($sd, 3); # 小数点第3位に揃える
$mpsd = $ave + $sd; # M+SD
$mmsd = $ave - $sd; # M-SD
$mp2sd = $ave + $sd * 2; # M+2SD
$mm2sd = $ave - $sd * 2; # M-2SD
print <<"__ TABLE __";
<br><br><br>
<table border=1 align='center' cellspacing=0 cellpadding=3>
<tr><td bgcolor='#ffffcc'>確率</td><td align='right'>1/$prob0</td>
<td bgcolor='#ffffcc'>M+SD</td><td align='right'><font color='blue'>$mpsd</font></td></tr>
<tr><td bgcolor='#ffffcc'>試行回数</td><td align='right'>$play</td>
<td bgcolor='#ffffcc'>M-SD</td><td align='right'><font color='red'>$mmsd</font></td></tr>
<tr><td bgcolor='#ffffcc'>平均値(M)</td><td align='right'><b>$ave</b></td>
<td bgcolor='#ffffcc'>M+2SD</td><td align='right'>$mp2sd</td></tr>
<tr><td bgcolor='#ffffcc'>分散</td><td align='right'>$var</td>
<td bgcolor='#ffffcc'>M-2SD</td><td align='right'>$mm2sd</td></tr>
<tr><td bgcolor='#ffffcc'>標準偏差(SD)</td><td align='right'>$sd</td><td colspan=2> </td></tr>
</table><br><br>
__ TABLE __
if ($ave < 50) { # 平均値が 50 未満なら、グラフの作成と確率の計算
# テーブルタグによるグラフの作成
$ave2 = $ave * 2; # 平均値 * 2 この値を二項分布グラフの横軸のMAXとする。
$ave2 = 20 if $ave2 < 20; # グラフの横軸は最低でも 20
$ave2 = $play if $ave2 > $play;
# 独立試行の定理の計算式より確率を求めて @value に入れる。
for ($x=0; $x<=$ave2; $x++) {
$combi = &combi($play, ($play-$x));
$value[$x] = $combi * $prob**$x * (1-$prob)**($play-$x);
$total += $value[$x] if $x <= $hit-1;
if ($value[$x] eq 'Inf') { last; }
}
# 確率の最も大きい部分 $max を求める。グラフの width, height の値は、この $max を基準にする。
for ($i=0; $i<=$#value; $i++) {
if ($value[$i] > $value[$i+1]) { $max = $value[$i]; last; }
}
# 二項分布グラフの出力
$height = 250/$max if $max;
$width = int(300/$ave2) if $ave;
print q{<table border=0 align='center'><tr><td>},"\n",q{<table border=1 align='center' cellspacing=0>},"\n";
print q{<caption align='top'><font size=2>二項分布</caption><tr valign='bottom'>},"\n";
for ($i=0; $i<=$#value; $i++) {
$height[$i] = int($value[$i] * $height);
$tbg = (!($i%10)) ? '#ffff77' : ''; # グラフの横軸は10個区切りで背景色を #ffff77 とする。
$tbg = '#000000' if $i==$hit; # 入力があった値の背景色は #000000 とする。
print " <td bgcolor='$tbg'><img src='$img' width='$width' height='$height[$i]'></td>\n";
}
print '</tr></table>',"\n",q{<table border=0 width='100%'><tr><td colspan=3><font size=2>0</td>};
print "<td align='center'><font size=2>黄色の区切り → 10 ごと</td><td colspan=3 align='right'>";
print "<font size=2>$#value</td></tr></table>",'</td><tr></table><br><br>';
# 引きの強さの計算
$rank_btm = 100 - int($total*100+0.5);
$rank_top = int($value[$hit]*100+0.5);
$rank = $rank_btm - $rank_top;
$prob2 = ($hit) ? &point(($play/$hit),3) : '∞';
print '<blockquote><br>',"\n","$play 回試行を行い、$hit 回当選 → <b>1/$prob2</b><br><br>";
print 'この試行を<b>100人</b>が行った場合、統計学的には(引きの強さは) ',"\n";
if (($rank==$rank_btm) or ($rank==0)) {
$rank_btm = 1 if ($rank_btm==0);
print "<b>$rank_btm 位。</b>";
} else {
print "<b>$rank 〜 $rank_btm 位。</b>";
}
if ($rank=~m/Inf/) { print '<br><br><font size=2>Inf と表示されている場合は<br>申し訳ありませんが、計算不能です。<br>'; }
print '</blockquote>',"\n";
# 確率の値と累計のの出力
print <<" __ TABLE __";
<br><br><br><table border=1 align='center' cellpadding=3 cellspacing=0>
<caption><font size=2>独立試行の定理から計算</caption>
<tr align='center' bgcolor='#ffffcc'><td><font size=2>当選<br>(回)</font></td>
<td><font size=2>確率</font></td><td><font size=2>確率の累計</font></td></tr>
__ TABLE __
for ($x=0; $x<=$ave2; $x++) {
$tbg = ($hit==$x) ? '#ffff77' : '#ffffff';
$sum += $value[$x];
print "<tr align='right' bgcolor='$tbg'><td><font size=2>$x</font></td>";
print "<td><font size=2>$value[$x]</font></td><td><font size=2>$sum</font></td></tr>\n";
last if ($value[$x] =~ /Inf/);
}
}
# フッタ
print <<"__ HTML __";
</table><br><br><br>
<div align='right'>[ <a href='nikou_memo.html'>memo</a> / <a href='nikou.html'>source</a> / <a href='../index.html'>home</a> ]</div>
</body></html>
__ HTML __
exit;
# 組み合わせの計算
sub combi {
my($a, $b, $i, $p1, $p2, $p);
($a, $b) = @_;
$p1 = $p2 = 1;
for ($i=$a; $i>$b; $i--) { $p1 *= $i; }
for ($i=$a-$b; $i>0; $i--) { $p2 *= $i; }
$p = $p1 / $p2;
return $p;
}
# 少数を四捨五入して指定の桁にする
sub point {
my($value, $fig, $x);
($value, $fig) = @_;
$value = int($value * (10 ** $fig) + 0.5) / (10 ** $fig);
if ($value =~ /(\d+)\.(\d+)/) { $x = $2; }
elsif ($value !~ /\./) { $x =''; $value .= '.'; }
$value = $value.'0' x ( $fig - length($x) );
return $value;
}
[ home / cgi / juggler / column / diary / bbs / link / welcome ]