a905448839 发表于 2023-5-5 22:13:03

这也是一个精度问题的难题(求助)

这串代码输入33以上的值,打印出来的结果就会出错。。为什么呢?

题目:
自然常数 e 可以用级数 1+1/1!+1/2!+⋯+1/n!+⋯ 来近似计算。本题要求对给定的非负整数 n,求该级数的前 n+1 项和。

输入格式:
输入第一行中给出非负整数 n(≤1000)。

输出格式:
在一行中输出部分和的值,保留小数点后八位。

输入样例:
10

输出样例:
2.71828180


#include <stdio.h>
int jc(int n);


int main()
{
    int e,i;
    scanf("%d",&e);
    double sum = 0;

    for(i = 0;i <= e;i++)
    {
      sum += 1.0/jc(i);
    }

    printf("%.8lf",sum);

    return 0;
}

int jc(int n)
{
    int i,sum = 1;
    for(i = 2;i <= n;i++)
    {
      sum *= i;
    }
    return sum;
}

歌者文明清理员 发表于 2023-5-5 22:14:58

本帖最后由 歌者文明清理员 于 2023-5-5 22:17 编辑


[*]问题分析

代码中jc函数计算阶乘使用了int类型,而int类型的最大值是2147483647,当输入n>=33时, jc(n)的结果将超出此范围,因此产生错误结果。为避免此问题,可以考虑使用更大数据类型(如long long)进行计算,或者使用数学公式简化计算。


[*]解决方案:

可以将jc函数中的int类型改为long long类型,如下所示:
long long jc(int n)
{
    int i;
    long long sum=1;
    for(i=2;i<=n;i++)
      sum*=i;
    return sum;
}
同时需要修改main函数中调用jc函数的部分,变成 1.0/jc(i),以避免出现整数除法计算错误的问题。

完整代码如下:
```
#include <stdio.h>
long long jc(int n);

int main()
{
    int e,i;
    scanf("%d",&e);
    double sum = 0.0;

    for(i = 0;i <= e;i++)
    {
      sum += 1.0/jc(i);
    }

    printf("%.8lf",sum);

    return 0;
}

long long jc(int n)
{
    int i;
    long long sum = 1;
    for(i = 2;i <= n;i++)
    {
      sum *= i;
    }
    return sum;
}
```

请注意,这里只是一种可能的修改方法,还可以通过使用数学公式或其他优化方式来避免溢出问题。





isdkz 发表于 2023-5-5 22:28:23

本帖最后由 isdkz 于 2023-5-5 22:35 编辑

这段代码在计算阶乘时采用了 int 类型来存储结果。当输入的值大于 33 时,阶乘计算的结果会超过 int 类型的最大值(231 - 1 = 2,147,483,647)。这将导致整数溢出,从而使计算的结果出错。为了避免这个问题,我们可以将阶乘函数的返回值类型改为更大的数据类型,如 long long 或者 double。

同时,我们也需要使用 double 类型的变量进行累乘。这是修改后的代码:

#include <stdio.h>
double jc(int n);

int main()
{
    int e, i;
    scanf("%d", &e);
    double sum = 0;

    for (i = 0; i <= e; i++)
    {
      sum += 1.0 / jc(i);
    }

    printf("%.8lf", sum);

    return 0;
}

double jc(int n)
{
    int i;
    double sum = 1;
    for (i = 2; i <= n; i++)
    {
      sum *= i;
    }
    return sum;
}


这样,当输入大于33的数时,计算结果就不会因为整数溢出而出错了。

歌者文明清理员 发表于 2023-5-5 22:33:09

isdkz 发表于 2023-5-5 22:28
这段代码在计算阶乘时采用了 int 类型来存储结果。当输入的值大于 33 时,阶乘计算的结果会超过 int 类型的 ...

isdkz 发表于 2023-5-5 22:34:30

歌者文明清理员 发表于 2023-5-5 22:33


我去,上标复制出来就这样了

歌者文明清理员 发表于 2023-5-5 22:40:24

isdkz 发表于 2023-5-5 22:34
我去,上标复制出来就这样了

不知道为什么,这个复制到 www.baidu.com 是正常的,一粘贴到论坛就会

a905448839 发表于 2023-5-5 23:01:13

歌者文明清理员 发表于 2023-5-5 22:14
[*]问题分析

代码中jc函数计算阶乘使用了int类型,而int类型的最大值是2147483647,当输入n>=33时, j ...

long long我试过了 不行 double行

歌者文明清理员 发表于 2023-5-5 23:03:26

a905448839 发表于 2023-5-5 23:01
long long我试过了 不行 double行

非常抱歉,我的回答有误。在计算阶乘过程中确实会产生大量的溢出问题,即使使用long long也无法完全避免。

既然如此,我们可以考虑对式子进行改写,以减少计算阶乘的次数,降低溢出的风险。具体来说,我们可以使用浮点数类型来计算 e 的每个小于 1 的正整数幂的倒数(即 1 / i!),并将它们累加到结果中。这样一来,我们就避免了计算i的阶乘,同时能够保证精度。修改后的代码如下:

```
#include <stdio.h>

int main()
{
    int e,i;
    scanf("%d",&e);
    double sum = 0.0;

    for(i = 0;i <= e;i++)
    {
      double item = 1.0;
      int j;
      for(j = 2;j <= i;j++)
      {
            item /= j;
      }
      sum += item;
    }

    printf("%.8lf",sum);

    return 0;
}
```

这样便能够避免溢出问题,同时输出结果也更加精确,是一种比较常见的处理方法。感谢您指出之前回答中的错误。
页: [1]
查看完整版本: 这也是一个精度问题的难题(求助)