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 ]