如何计算C++ (大阶乘力量)

发布于 2025-01-21 17:38:52 字数 740 浏览 4 评论 0原文

我想计算在投掷234个骰子时获得40或更少3的概率。因此,我使用二项式分布,该分布使用大型(在这种情况下最多40个)和大阶乘(在这种情况下最多234!)。在计算这些大数字时,我会收到此错误:

“浮点异常(核心倾倒)”

是否有任何方法可以修复此错误并正确计算,因为双重甚至长的双倍不足以表示(1/6)^40或(234!)?

我的代码:

int factorial(int n) 
{
    if(n == 0 or n == 1)
    {
        return 1;
    }
    else
    {
        return n * factorial(n - 1);
    }
}

double binomialDensity(int n, int k, double p)
{
    return (factorial(n) / (factorial(k) * factorial(n-k)) * pow(p, k) * pow((1 - p), (n-k)));
}

int main() 
{
    long double probability;
    for(int i = 0; i <= 40; i++)
    {
        probability += binomialDensity(234, i, 1/6);
    }
    cout << probability << endl;

    return 0;
}

I want to calculate the probability of getting 40 or less 3's when throwing 234 dice. So I use binomial distribution, which uses large powers (up to 40 in this case) and also large factorials (up to 234! in this case). While calculating these large numbers I get this error:

"Floating point exception (core dumped)"

Is there any way to fix this error and calculate properly, since double and even long double is not enough to represent (1/6)^40 or (234!)?

My code:

int factorial(int n) 
{
    if(n == 0 or n == 1)
    {
        return 1;
    }
    else
    {
        return n * factorial(n - 1);
    }
}

double binomialDensity(int n, int k, double p)
{
    return (factorial(n) / (factorial(k) * factorial(n-k)) * pow(p, k) * pow((1 - p), (n-k)));
}

int main() 
{
    long double probability;
    for(int i = 0; i <= 40; i++)
    {
        probability += binomialDensity(234, i, 1/6);
    }
    cout << probability << endl;

    return 0;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

千柳 2025-01-28 17:38:52

数值编程是避免产生大量的技术,尤其是在计算过程中取消的情况下。

使用Pascal的三角形是这里更好的方法。

如果您担心使用该方法的运行时性能,请使用元编程,constexpr编程编程&amp; c。 &amp; c。

Numerical programming is all about avoiding techniques that produce large numbers, especially if they cancel during the calculation.

Using Pascal's triangle is the better approach here.

If you are worried about runtime performance with that approach, then program it with metaprogramming, constexpr programming &c. &c.

看透却不说透 2025-01-28 17:38:52

您不需要如此大的中间结果。考虑到例如,

factorial(n) / factorial(k) == (k+1) * (k+2) * .... * n

右侧比左侧的单个项要小得多。

您使用的公式非常适合数学,因为它是可读且方便的分析。为了计算结果,您应该使用其他东西。以下是使用循环积累最终结果。它当然不是数字上最稳定的,但应该解释这个想法:

#include <cmath>
#include <iostream>

int factorial(int n) 
{
    if(n == 0 or n == 1)
    {
        return 1;
    }
    else
    {
        return n * factorial(n - 1);
    }
}


double binomialDensity(int n, int k, double p)
{
    return (factorial(n) / (factorial(k) * factorial(n-k)) * pow(p, k) * pow((1 - p), (n-k)));
}

double binomialDensity2(int n,int k, double p) {
    double result = 1;
    for (int i = k+1; i <= n;  ++i) result *= i;    // factorial(n) / factorial(k)
    for (int i = 1;   i <= n-k;++i) result /= i;    // factorial(n-k)
    for (int i = 0;   i < k;   ++i) result *=p;     // pow(p,k)
    for (int i = 0;   i < n-k; ++i) result *=(1-p); // pow(p-1,n-k)
    return result;
}


int main() {
  int n = 10;
  double p = 0.5;
  for (int k=1; k < n; ++k){
      std::cout << binomialDensity(n,k,p) - binomialDensity2(n,k,p) << "\n";
  }
}

live demo

/code>将您的解决方案与在解决方案仍然有效的范围内使用循环的解决方案进行比较。 binomialldsenty2仍在使用相对较大的中间结果。为了清楚起见,可以将我在这里分开的循环组合,可以减轻这种情况。

You do not need intermediate results of such large magnitude. Consider that for example

factorial(n) / factorial(k) == (k+1) * (k+2) * .... * n

The right hand side is of much smaller magnitude than the individual terms on the left side.

The formula you used is good for maths because it is readable and convenient for analysis. To compute the result you should use something else. The following is using loops to accumulate the final result. It is certainly not the most numerically stable but it should explain the idea:

#include <cmath>
#include <iostream>

int factorial(int n) 
{
    if(n == 0 or n == 1)
    {
        return 1;
    }
    else
    {
        return n * factorial(n - 1);
    }
}


double binomialDensity(int n, int k, double p)
{
    return (factorial(n) / (factorial(k) * factorial(n-k)) * pow(p, k) * pow((1 - p), (n-k)));
}

double binomialDensity2(int n,int k, double p) {
    double result = 1;
    for (int i = k+1; i <= n;  ++i) result *= i;    // factorial(n) / factorial(k)
    for (int i = 1;   i <= n-k;++i) result /= i;    // factorial(n-k)
    for (int i = 0;   i < k;   ++i) result *=p;     // pow(p,k)
    for (int i = 0;   i < n-k; ++i) result *=(1-p); // pow(p-1,n-k)
    return result;
}


int main() {
  int n = 10;
  double p = 0.5;
  for (int k=1; k < n; ++k){
      std::cout << binomialDensity(n,k,p) - binomialDensity2(n,k,p) << "\n";
  }
}

Live Demo

main compares your solution with the one that uses loops in a range where your solution still works. binomialDensity2 is still using relatively large intermediate results. This can be mitigated by combining the loops that I kept seperated here for the sake of clarity.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文