-1

我正在尝试在 Dev C++ 中运行此代码:

    #include<conio.h>
    #include<iostream>


    using namespace std;

    int main()
    {
        float sum =1;
        int num = -1;

        for(int i=1; i<=1000; i++)
        {
            num *= i;
            sum += 1/(num);
        }
        cout<<sum<<endl;
        getch();
        return 0;
    }

每当我编译和运行代码时,我都会收到程序已停止工作的 Windows 错误消息。有人可以帮我吗?

使用此代码,我正在尝试计算以下总和:

∞</p>

∑ 1/n!

n=0

4

3 回答 3

7

(总和的下限应该是 1 而不是 0,但让我们把它放在一边。)

你的算法在数值上非常不稳定,以至于没有修复可以使它有效地工作。简而言之,阶乘太大了。溢出除signed charor以外的有符号整数类型时的行为char未定义。似乎正在发生的事情是,int本质上是将阶乘以 2 的大幂为模,最终将是 0,因为大阶乘是 2 的大幂的倍数。因此,除以 0 会产生您观察到的行为。

幸运的是,您可能会注意到您的总和可以写为

1 + 1/2(1 + 1/3(1 + 1/4...))

这在数字上更简单。一种方法是

#include <iostream>
#include <iomanip>
#include <cmath>
int main() {
    constexpr int N = 19;
    double sum = 1 + 1.0 / N;
    for (int n = N - 1; n >= 1; --n){
        sum = 1 + sum / n;
    }
    std::cout << std::setprecision(15) << sum << " " << std::exp(1);
}

获得输出2.71828182845905 2.71828182845905,表明这是正确的,因为该系列的总和是数学常数e

虽然这在数字上很漂亮 - 隐藏的深度包括这样一个事实,即这些术语具有相似的量级并且收敛速度非常快,并且这个答案希望能够揭穿浮点运算本质上不准确的普遍神话,但这种方法的缺点是你需要提前知道上限;即当达到一定的容差时你不能停下来。我从经验中知道你需要大约 20 个学期。

于 2018-03-13T14:30:31.907 回答
4

发生这种情况是因为实际上是一个巨大的数字,比甚至可以处理1000!的要大得多。同样重要的是,当乘法溢出时,现实生活中究竟发生了什么。长话短说,很快你就会完全正确,这可能会让你有点吃惊(这应该在被 整除时发生)。然后尝试计算失败并出现算术错误(除以 0)。intlong longnum0n!2^321/(num)

提示:实际上1000!它是如此之大,以至于没有标准类型可以处理它(并且1/1000!小到足以超出任何标准类型的精度)。如果您真的想足够精确地计算总和,您将不得不使用一些重要的技巧。

于 2018-03-13T14:21:38.350 回答
2
  1. num 不应以 -1 开头
  2. 'num' 将在乘法时爆炸
  3. 浮动只能让你到目前为止。双倍更好。

跟踪反阶乘。在这种情况下,您可以只除以前的值。

#include<iostream>

using namespace std;

int main()
{
    double sum = 1.0;
    int num = 1;
    double inv_fact = 1.0;

    for(int i=1; i<=1000; i++)
    {
      inv_fact = inv_fact / i;
      sum += inv_fact;
    }
    cout<<sum<<endl;
    return 0;
}

给:2.71828

于 2018-03-13T14:50:28.690 回答