【问题标题】:Highly specific factorial calculations in PHPPHP中高度具体的阶乘计算
【发布时间】:2018-01-28 22:56:03
【问题描述】:

我一直在开发一个 PHP 页面,该页面计算不同结果的概率,同时从由两种类型的人(+-)组成的较大组中随机选择一个样本组。

例如,考虑到0.15 的美国人是吸烟者(+ )。

它在处理低于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;

【问题讨论】:

  • 请给我们一些代码格式,好吗?
  • 排列和组合最好使用 lngamma 函数而不是阶乘来计算。

标签: php math statistics factorial


【解决方案1】:

您可以使用Stirlings approximation。它对大数相当精确。意思是阶乘可以计算为近似值

一组其他算法can be found here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-19
    • 2022-01-17
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 2013-02-19
    • 1970-01-01
    相关资源
    最近更新 更多