具有高阶乘的泊松计算

Poisson Calc with high factorial

我有这段计算代码:

    public static double CalcPoisson(double m, double u, boolean va)
{
    double answer = 0;
    if(!va)
    {
        answer = (Math.exp(-u)* Math.pow(u, m)) / (factorial(m));
    }
    if(va)
    {
        for(int i = 0; i < m; i++)
        {
            answer = answer + (Math.exp(-u)* Math.pow(u, i)) / (factorial(i));
        }
    }

    return answer;

这是我的阶乘方法

    public static double factorial (double n)
{
    return n == 0 ? 1 : n *factorial(n-1);
}

问题是:要计算的最大值是 170...我需要更多(例如 500 的阶乘)

我写了一个新方法:

    public static BigDecimal factorial2 (double n)
{
    BigDecimal fct = BigDecimal.valueOf(1);
    for(int i = 1; i<=n; i++)
    {
        fct = fct.multiply(BigDecimal.valueOf(i));
    }

    return fct;

如何在我的 "CalcPoisson" 方法中使用我的新阶乘方法? 问题是,我不能用 BigDecimal 双除...

感谢您的帮助:)

没有人:

我在一个使用 CalcPoisson 的方法中仍然有这行代码,我对 BigDecimal 仍然不好,我无法处理它。

线路:

        BigDecimal nenner = CalcPoisson(m, u, false) + (1-p) * CalcPoisson(m, u, true);

您可以将您的双倍转换为 BigDecimal,然后您可以按如下方式划分两个 BigDecimal

BigDecimal answer = BigDecimal.ZERO;
BigDecimal myOwn = new BigDecimal(Double.toString(Math.exp(-u)* Math.pow(u, i)));
answer = answer.add(myOwn.divide(factorial2(i)));

使用 BigDecimal 求阶乘,就像您在 factorial2() 中所做的那样。

最终您的方法将如下所示:

    public static BigDecimal CalcPoisson(double m, double u, boolean va)
{
BigDecimal answer = BigDecimal.ZERO;
if(!va)
{
    BigDecimal myOwn1 = new BigDecimal(Double.toString((Math.exp(-u)* Math.pow(u, m))));
    answer =  myOwn1.divide(fakultaet(m));
}
if(va)
{
    for(int i = 0; i < m; i++)
    {
        BigDecimal myOwn = new BigDecimal(Double.toString(Math.exp(-u)* Math.pow(u, i)));
        answer = answer.add(myOwn.divide(factorial2(i)));
    }
}

return answer;

假设您有 return 类型的方法 fakultaet() 是 BigDecimal。如果你有相同的 return 值 double,那么试试:

answer =  myOwn1.divide(new BigDecimal(fakultaet(m)));

编辑

BigDecimal nenner = CalcPoisson(m, u, false).add((BigDecimal.ONE.subtract(new BigDecimal(p))).multiply( CalcPoisson(m, u, true)));

您可以从 Double 中创建一个新的 BigDecimal
然后你可以使用 BigDecimal

的 multiplie 方法
fct = fct.multiplie(new BigDecimal(doubleValue));

你的方法太直接了。此类循环通常以 while (nextTerm < epsilon) 的形式编写,而不是 for 循环。当然,前提是您可以证明项确实随着 i.

而减少

另一个问题是虽然表达式 pow(u,i) / factorial(i) 的值可能适合双精度数,但它的部分肯定不适合。您需要以不同的方式计算它。当然,这样做会失去精度,所以会变得更加复杂。

我最好停下来。我的数学教授承诺他会追捕并杀死我们任何试图进行计算数学的人,他是一位严肃的绅士。

for(int i = 0; i < m; i++)
{
    answer = answer + (Math.exp(-u)* Math.pow(u, i)) / (factorial(i));
}

请注意,此算法计算从 0 到 m-1 的所有阶乘。更快更准确地分解出来:

   long fact = 1;
    for(int i = 0; i < m; i++) {
        answer = answer + (Math.exp(-u)* Math.pow(u, i)) / fact;
        fact *= (i+1);
    }

然后注意Math.exp(-u)在循环中是不变的,所以提取出来:

long fact = 1;
double eu = Math.exp(-u);
for(int i = 0; i < m; i++) {
    answer = answer + (eu * Math.pow(u, i)) / fact;
    fact *= (i+1);
}

而且您还可以摆脱对 Math.pow():

的重复调用
long fact = 1;
double eu = Math.exp(-u);
double term = u;
for(int i = 0; i < m; i++) {
    answer = answer + (eu * term) / fact;
    fact *= (i+1);
    term *= u;
}

最后,您还可以将术语和事实合并为一个参数(留给学生作为练习)。