a905448839 发表于 2023-5-5 21:32:36

怎么double精度不对呢?




如题:哪里出现问题了呀?

#include <stdio.h>

int main()
{
    double eps,sum = 0;
    scanf("%lf",&eps);
    int i = 1;
    int n = 1;
    while(1)
    {
      if(1.0/i <= eps)
      break;
      if(n % 2 == 1)
      {
            sum += 1.0/i;
            i += 2;
      }
      else
      {
            sum -= 1.0/i;
            i += 2;
      }
      n++;
    }
   
    printf("sum = %.6lf",sum);
    return 0;
}

叶落了 发表于 2023-5-5 21:32:37

#include <stdio.h>

int main()
{
    double eps,sum = 0;
    scanf("%lf",&eps);
    int i = 1;
    int n = 1;
    while(1)
    {
      if(1.0/i <= eps)
      break;
      if(n % 2 == 1)
      {
            sum += (1.0/i);
            i += 3;
      }
      else
      {
            sum -= (1.0/i);
            i += 3;
      }
      n++;
    }
   
    printf("%d\n",i);
    printf("%f\n",(1.0/i));
    printf("sum = %f\n",sum);
    printf("sum = %f",sum-(1.0/i));
    return 0;
}

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

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

这是一个经典的计算交错级数部分和的问题,由于双精度精度限制,当级数项的绝对值变得非常小(比如小于1e-16时),加上或减去这个很小的数字都不会改变部分和的结果,所以在此问题中需要及时停止计算,在余下的部分和输出前面已经计算得到的部分和。

以下是更新后的代码建议:

```c
#include <stdio.h>
#include <math.h>

int main()
{
    double eps, sum = 0.0, term;
    int i;
    scanf("%lf", &eps);

    for (i=1; ;i++)
    {
      if (i % 2 == 1)
            term = 1.0 / (2 * i - 1);
      else
            term = -1.0 / (2 * i - 1);

      sum += term;

      if (fabs(term) < eps)
            break;
    }

    printf("sum = %.6f", sum);

    return 0;
}
```

以上代码首先定义了两个double类型变量`eps`和`sum`,用于存储输入的精度和计算出的部分和。然后使用了一个循环来计算交错级数的部分和,循环终止条件为当前项的绝对值小于精度eps。因为输入的精度可能存在浮点误差,所以一般比较正负数的大小用fabs()`函数比较更为保险。因为循环之前不能确定需要计算多少项,所以此处采用了无限循环`for(;;)`语法来实现循环。

在每一次循环中先判断当前项的符号然后储存在变量`term`中,依次累加到变量`sum`上。然后在每次循环完毕后检查这一次算出来的项的绝对值是否小于给定的精度,如果是,则跳出循环并输出变量`sum`的值。

最后,在输出时请注意控制输出的精度,此处使用了“%.6f”格式控制输出双精度数的小数点后六位。

a905448839 发表于 2023-5-5 22:47:54

歌者文明清理员 发表于 2023-5-5 22:22
这是一个经典的计算交错级数部分和的问题,由于双精度精度限制,当级数项的绝对值变得非常小(比如小于1e-1 ...

谢谢你的回复 你的代码我测试出来不符合本题要求

但是我找出了我的错误 首先我应该 i+=3;

其次是因为 一开始设置sum = 1和sum = 0是不同的结果
sum = 0时 第一个计算第一项是1.0/1   double类型的就会出现精度差 而这题的判断条件第一个是1
我设置为sum = 1 精度就没问题了

修改后代码#include <stdio.h>

int main()
{
    double eps,sum = 1;
    scanf("%lf",&eps);
    double i = 1;
    double n = 1;
    double s = -1;
    while(i/n > eps)
    {
      n += 3;
      sum += 1.0*s*i/n;
      s = -s;
    }
   
    printf("sum = %.6lf",sum);
    return 0;
}



如果设置sum = 0 精度出问题

#include <stdio.h>

int main()
{
    double eps,sum = 0;
    scanf("%lf",&eps);
    double i = 1;
    double n = 1;
    double s = 1;
    while(i/n > eps)
    {
      sum += 1.0*s*i/n;
      s = -s;
      n += 3;
    }
   
    printf("sum = %.6lf",sum);
    return 0;
}

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

a905448839 发表于 2023-5-5 22:47
谢谢你的回复 你的代码我测试出来不符合本题要求

但是我找出了我的错误 首先我应该 i+=3;


很抱歉之前的回答可能存在误导,由于本人对该问题理解不够深刻,造成了您的困扰。而你所提供的代码确实也是解决本题的一种常见思路与方法。感谢您的耐心和指正。

在新的代码中,首先选择给定的初值和变量类型是一个比较重要的决策。为了方便后面交错求和时的处理,在此使用了sum=1.0这个初值,同时将变量i和n也存储成双精度类型的变量,以避免整除过程中的精度损失。

接下来使用一个循环语句进行交错求和,每次累加计算出当前项的值,以符号+1或-1把项加上去。在每次成功累加完值后改变i的值,并检查当前项是否小于给定的阈值精度eps,如果小于等于就直接退出循环并输出结果。

最后值得注意的是,在对double类型数据进行精度比较时使用eps作为评估精度,这个虽然在一般情况下可行,但如果eps设置的过大可能会导致部分和结果的相对误差高于指定的精度范围(比如当eps=1e-12时),所以优秀的实现方式应该是在精度计算时额外考虑保留的小数位数,比如充分理解保留若干位小数的含义,并且适量地考虑舍入误差和求和误差。

a905448839 发表于 2023-5-5 22:51:43

叶落了 发表于 2023-5-5 22:38
#include

int main()


啊!原来不是精度问题 而是多算上了一个1.0/i   想问一下我的代码逻辑为什么会多算上一个1.0/i能告诉我吗?谢谢!

ynnh 发表于 2023-5-6 09:30:54

你这是是不是公式都错了呀{:10_277:}

a905448839 发表于 2023-5-6 09:38:57

ynnh 发表于 2023-5-6 09:30
你这是是不是公式都错了呀

是的 分母那个i应该每次加3但是后面正确答案还是有误差 需要减去或加上一个1.0/i

叶落了 发表于 2023-5-7 16:54:35

我是这样理解的,题目上是最后一项的精度不大于给定精度,那么是包含这一项数据的--0.019231 .但你的程序是先判断的,没有使用最后这一项数据。然后根据规律,应该是sum减最后一组数据,所以我在最后减了
页: [1]
查看完整版本: 怎么double精度不对呢?