鱼C论坛

 找回密码
 立即注册
查看: 1120|回复: 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

#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: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的数时,计算结果就不会因为整数溢出而出错了。
想知道小甲鱼最近在做啥?请访问 -> 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类型,如下所示:
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;
}
```

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





想知道小甲鱼最近在做啥?请访问 -> 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 类型的变量进行累乘。这是修改后的代码:
#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的数时,计算结果就不会因为整数溢出而出错了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

2023-05-05 22 32 49.png
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

我去,上标复制出来就这样了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

不知道为什么,这个复制到 www.baidu.com 是正常的,一粘贴到论坛就会
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

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

  • long long我试过了 不行 double行
    想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
    回复 支持 反对

    使用道具 举报

    发表于 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;
    }
    ```

    这样便能够避免溢出问题,同时输出结果也更加精确,是一种比较常见的处理方法。感谢您指出之前回答中的错误。
    想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
    回复 支持 反对

    使用道具 举报

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

    本版积分规则

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

    GMT+8, 2024-9-28 01:16

    Powered by Discuz! X3.4

    © 2001-2023 Discuz! Team.

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