鱼C论坛

 找回密码
 立即注册
查看: 1848|回复: 7

[已解决]这也是一个精度问题的难题(求助)

[复制链接]
发表于 2023-5-5 22:13:03 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

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

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

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

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

输入样例:
10

输出样例:
2.71828180


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


  3. int main()
  4. {
  5.     int e,i;
  6.     scanf("%d",&e);
  7.     double sum = 0;

  8.     for(i = 0;i <= e;i++)
  9.     {
  10.         sum += 1.0/jc(i);
  11.     }

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

  13.     return 0;
  14. }

  15. int jc(int n)
  16. {
  17.     int i,sum = 1;
  18.     for(i = 2;i <= n;i++)
  19.     {
  20.         sum *= i;
  21.     }
  22.     return sum;
  23. }
复制代码
最佳答案
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 类型的变量进行累乘。这是修改后的代码:

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

  3. int main()
  4. {
  5.     int e, i;
  6.     scanf("%d", &e);
  7.     double sum = 0;

  8.     for (i = 0; i <= e; i++)
  9.     {
  10.         sum += 1.0 / jc(i);
  11.     }

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

  13.     return 0;
  14. }

  15. double jc(int n)
  16. {
  17.     int i;
  18.     double sum = 1;
  19.     for (i = 2; i <= n; i++)
  20.     {
  21.         sum *= i;
  22.     }
  23.     return sum;
  24. }
复制代码


这样,当输入大于33的数时,计算结果就不会因为整数溢出而出错了。
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 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类型,如下所示:
  1. long long jc(int n)
  2. {
  3.     int i;
  4.     long long sum=1;
  5.     for(i=2;i<=n;i++)
  6.         sum*=i;
  7.     return sum;
  8. }
复制代码

同时需要修改main函数中调用jc函数的部分,变成 1.0/jc(i),以避免出现整数除法计算错误的问题。

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

  3. int main()
  4. {
  5.     int e,i;
  6.     scanf("%d",&e);
  7.     double sum = 0.0;

  8.     for(i = 0;i <= e;i++)
  9.     {
  10.         sum += 1.0/jc(i);
  11.     }

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

  13.     return 0;
  14. }

  15. long long jc(int n)
  16. {
  17.     int i;
  18.     long long sum = 1;
  19.     for(i = 2;i <= n;i++)
  20.     {
  21.         sum *= i;
  22.     }
  23.     return sum;
  24. }
复制代码

```

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





小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 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 类型的变量进行累乘。这是修改后的代码:

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

  3. int main()
  4. {
  5.     int e, i;
  6.     scanf("%d", &e);
  7.     double sum = 0;

  8.     for (i = 0; i <= e; i++)
  9.     {
  10.         sum += 1.0 / jc(i);
  11.     }

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

  13.     return 0;
  14. }

  15. double jc(int n)
  16. {
  17.     int i;
  18.     double sum = 1;
  19.     for (i = 2; i <= n; i++)
  20.     {
  21.         sum *= i;
  22.     }
  23.     return sum;
  24. }
复制代码


这样,当输入大于33的数时,计算结果就不会因为整数溢出而出错了。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

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

2023-05-05 22 32 49.png
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-5-5 22:34:30 | 显示全部楼层

我去,上标复制出来就这样了
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2023-5-5 22:40:24 | 显示全部楼层
isdkz 发表于 2023-5-5 22:34
我去,上标复制出来就这样了

不知道为什么,这个复制到 www.baidu.com 是正常的,一粘贴到论坛就会
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-5 23:01:13 | 显示全部楼层
歌者文明清理员 发表于 2023-5-5 22:14
  • 问题分析

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

  • long long我试过了 不行 double行
    小甲鱼最新课程 -> https://ilovefishc.com
    回复 支持 反对

    使用道具 举报

    发表于 2023-5-5 23:03:26 | 显示全部楼层
    a905448839 发表于 2023-5-5 23:01
    long long我试过了 不行 double行

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

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

    ```
    1. #include <stdio.h>

    2. int main()
    3. {
    4.     int e,i;
    5.     scanf("%d",&e);
    6.     double sum = 0.0;

    7.     for(i = 0;i <= e;i++)
    8.     {
    9.         double item = 1.0;
    10.         int j;
    11.         for(j = 2;j <= i;j++)
    12.         {
    13.             item /= j;
    14.         }
    15.         sum += item;
    16.     }

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

    18.     return 0;
    19. }
    复制代码

    ```

    这样便能够避免溢出问题,同时输出结果也更加精确,是一种比较常见的处理方法。感谢您指出之前回答中的错误。
    小甲鱼最新课程 -> https://ilovefishc.com
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

    GMT+8, 2025-7-7 08:31

    Powered by Discuz! X3.4

    © 2001-2023 Discuz! Team.

    快速回复 返回顶部 返回列表