PHP 中高度具体的阶乘计算
Highly specific factorial calculations in PHP
我一直在开发一个 PHP 页面,该页面计算不同结果的概率,同时从由两种类型的人(+
和 -
).
例如,考虑到 0.15
,它可以计算在从美国各地随机选择的一组 1000
人中有 0(或 n
)名吸烟者的概率的美国人是吸烟者 (+
)。
它在处理 10000
人以下的人群时效果很好,但当涉及到 1000000
等更大的人群时,它会在所有概率上回显 0
,除非精度 ( .
) 之后的位数增加到 3000
。即使在那种情况下也需要永远。
代码的工作原理是计算 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;
您可以使用 Stirlings approximation。它在大数字上相当精确。意思是阶乘可以计算为一个近似值
一组其他算法can be found here。
我一直在开发一个 PHP 页面,该页面计算不同结果的概率,同时从由两种类型的人(+
和 -
).
例如,考虑到 0.15
,它可以计算在从美国各地随机选择的一组 1000
人中有 0(或 n
)名吸烟者的概率的美国人是吸烟者 (+
)。
它在处理 10000
人以下的人群时效果很好,但当涉及到 1000000
等更大的人群时,它会在所有概率上回显 0
,除非精度 ( .
) 之后的位数增加到 3000
。即使在那种情况下也需要永远。
代码的工作原理是计算 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;
您可以使用 Stirlings approximation。它在大数字上相当精确。意思是阶乘可以计算为一个近似值
一组其他算法can be found here。