以一元二次方程a*x*x+b*x+c=0为例,讲讲关于double类型的误差问题。
当a为0时,方程的根为-c/b;
当a不为0时,得进一步确定判别式△,△=b*b-4*a*c,令d=△;
当d<0,无实根;当d=0,两根为同一值,x1=x1=-c/b;当d>0,由求根公式得到两个不同的根值。
其中C语言编程中必用到根号,所以涉及到使用double。double有32位,每一位具有相应的意义,第1位为符号位,第2位至第9位为指数位,后23位为尾数部分。由于浮点型的特殊存储,1在内存中不是1,可能是0.999999,也可能是1.000001。当进行运算时,储存小数部分的尾数会有不够的现象,即无限循环小数,从而出现误差。误差示例如下:
浮点数本身有误差,不精确,含有有效数字,我们假设误差为EPS=0.000001(此精度可自定义,真实精度可通过头文件#include<float.h>查看使用,但一般不推荐使用)通过使用定义的精度误差,将内存中接近于真实值,在误差之内的数统一认为为一定值,消除误差带来的问题。
程序如下:
#include<stdio.h>
#include<math.h>
#define EPS 0.000001
void Fun(double a,double b,double c)
{
double x1;
double x2;
double d=b*b-4*a*c;
if(-EPS<=a&&a<=EPS)//a==0
{
x1=x2=-c/b;
printf("x1=%f,x2=%f\n",x1,x2);
}
else//a!=0
{
if(-EPS<=d&&d<=EPS)//d==0
{
x1=x2=-b/(2*a);
printf("x1=%f,x2=%f\n",x1,x2);
}
else
{
if(d>EPS)
{
x1=(-b+sqrt(d))/(2*a);
x2=(-b-sqrt(d))/(2*a);
printf("x1=%f,x2=%f\n",x1,x2);
}
else
{
printf("无实根!\n");
}
}
}
}
int main()
{
Fun(0,1,2);
Fun(1,2,1);
Fun(1,4,2);
Fun(1,1,1);
}
#include<stdio.h>
#include<math.h>
#define EPS 0.000001
void Fun(double a,double b,double c)
{
double x1;
double x2;
double d=b*b-4*a*c;
if(-EPS<=a&&a<=EPS)//a==0
{
x1=x2=-c/b;
printf("x1=%f,x2=%f\n",x1,x2);
}
else if(-EPS<=d&&d<=EPS)//d==0
{
x1=x2=-b/(2*a);
printf("x1=%f,x2=%f\n",x1,x2);
}
else if(d>EPS)
{
x1=(-b+sqrt(d))/(2*a);
x2=(-b-sqrt(d))/(2*a);
printf("x1=%f,x2=%f\n",x1,x2);
}
else
{
printf("无实根\n");
}
}
int main()
{
Fun(0,1,2);
Fun(1,2,1);
Fun(1,4,2);
Fun(1,1,1);
}
自己写的第一篇,其中有不对的地方,希望可以指出共同讨论。