2017-08-20 22 views
0

私は、2つのタイプの人(+-)からなるより大きなグループからランダムにサンプルグループを選択しながら、異なる結果の確率を計算するPHPページを作成しています。例えばPHPでの具体的な階乗計算

、それはアメリカ人の0.15が喫煙者(+)であることを考慮すると、ランダムに米国全土から選ばれた1000人のグループに0(またはn)喫煙者を有する確率を計算することができます。

10000人以下の集団での作業中には非常にうまく動作しますが、それは1000000のようなのより大きな集団になると精度(.の桁数)が3000を好きに増加されていない限り、それはすべての確率のため0をエコーし​​ます。その場合でも、それは永遠にかかる。

コードは、0の確率を計算し、その計算を実行して1の正の確率などを計算します。これは、これらの確率の大部分が役に立たない間です。

私は( 1000000!のような)非常に大きな階乗のほぼ正確な( 99.999%以上)の値を計算する高速な方法を見つけ出すことができれば、 0から開始する必要がないだろうと思って、されている

必要な場所から計算を開始することができ、非常に低い精度で計算時間を短縮できます。私が探していたまさにでしたあなたの応答のための

<html> 
<body> 
    <form method="get"> 
     target population: 
     <input type="text" name="tpop"><br><br> 
     selected population: 
     <input type="text" name="selected"><br><br> 
     fraction of positives: 
     <input type="text" name="fop"><br><br> 
     output margin: 
     <input type="text" name="margin"><br><br> 
     precision: 
     <input type="text" name="precision"><br><br> 
     <input type="submit"> 
    </form> 
</body> 
</html> 
<?php 
set_time_limit(0); 
if (isset($_GET["precision"],$_GET["tpop"],$_GET["selected"],$_GET["fop"],$_GET["margin"])&&$_GET["precision"]!=''&&$_GET["tpop"]!=''&&$_GET["selected"]!=''&&$_GET["fop"]!=''&&$_GET["margin"]!=''&&$_GET["tpop"]>=$_GET["selected"]&&$_GET["fop"]>=0&&$_GET["fop"]<=1){ 
    $tpop=$_GET["tpop"]; 
    $selected=$_GET["selected"]; 
    $fop=$_GET["fop"]; 
    $margin=$_GET["margin"]; 
    $ioioio=0; 
    $precision=$_GET["precision"]; 

    $minor=($selected*$fop)-$margin; 
    $maxor=$minor+(2*$margin); 
    $popopo=bcmul($tpop,$fop); 
    echo '<br><br>min is'.$minor.'max is'.$maxor.'<br><br>'; 

    $mmm=bcsub($tpop,$selected,$precision); 
    $rea=bcsub($mmm,1,$precision); 
    $fops=bcmul($tpop,$fop); 
    $trss=bcsub($tpop,$fops,$precision); 
    $trss=bcsub($trss,$selected,$precision); 
    $trss=bcadd($trss,1,$precision); 
    while($rea>=$trss){ 
    $mmm=bcmul($mmm,$rea,$precision); 
    $rea=bcsub($rea,1,$precision); 
} 

$nnn=$tpop; 
$sfg=bcsub($nnn,1,$precision); 
$ugt=bcmul($tpop,$fop,$precision); 
$uyt=bcsub($tpop,$ugt); 
$uyt=bcadd($uyt,1,$precision); 
while($sfg>=$uyt){ 
    $nnn=bcmul($nnn,$sfg,$precision); 
    $sfg=bcsub($sfg,1,$precision); 
} 

$zero=bcdiv($mmm,$nnn,$precision); 

echo '0==>'.$zero.'<br><br>'; 
$a=$selected; 
$b=($tpop-($tpop*$fop)-$selected+1); 
$c=1; 
$d=($tpop*$fop); 
$i=1; 

$origzero=$zero; 
$save=$zero; 

while($i<=$selected){ 

    if($d<=0){ 
     echo $i.'==>impossible<br><br>'; 
     $a--; 
     $b++; 
     $c++; 
     $d--; 
     $i++; 
    }else{ 
     $zero=bcmul($zero,$a,$precision); 
     $zero=bcmul($zero,$d,$precision); 
     $zero=bcdiv($zero,$b,$precision); 
     $zero=bcdiv($zero,$c,$precision); 
     if($i>=$minor){ 
      if($i<=$maxor){ 
       if($i<=$popopo){ 
        $ioioio=bcadd($ioioio,$zero,$precision); 
        echo 'following value is included in p value<br>'; 
        echo $i.'==>'.$zero.'<br><br>'; 
       } 
      } 
     } 
     $save=bcadd($save,$zero,$precision); 

     $a--; 
     $b++; 
     $c++; 
     $d--; 
     $i++; 
    } 
} 
echo 'precision==> '.$save.'<br><br>'; 
$savee = bcsub(1,$save,$precision); 
echo '1-precision==> '.$savee.'<br><br>'; 
if($minor<0||$maxor>$selected){ 
    echo 'p value==>margin larger than surronding probabilties select an smaller margin to calculate p value'; 
} elseif($minor>0){ 
    echo 'p value==>'.$ioioio; 
} else{ 
    $ioioiop=bcadd($ioioio,$origzero,$precision); 
    echo 'p value(0included)==> '.$ioioiop;} 
} 
?> 

親愛なる@ shukshin.ivan 多くの感謝:ここ

がコードである] これは、それがどのように他の誰かのためにどのように機能するかの例があります

$x=950000; 
$x =2*$x+1; 
$P=pi(); 
$x =(log(2.0*$P)+log($x/2.0)*$x-$x-(1.0-7.0/(30.0*$x*$x))/(6.0*$x))/2.0; 
$x=$x/log(10); 
$ex=floor($x);    
$x=pow(10,$x-$ex); 
$res=$x.'A'; 
$res=substr($x,0,6).'E'.$ex; 
echo $res; 
+0

コードの書式設定はできますか? – localheinz

+0

順列と組み合わせは、階乗ではなく、lngamma関数を使用して最もよく計算されます。 – duffymo

答えて

0

Stirlings approximationを使用できます。それはかなり正確です。意味は階乗近似

enter image description here

他のアルゴリズムcan be found hereのセットとして計算することができるということです。

関連する問題