关于double类型的误差问题

以一元二次方程a*x*x+b*x+c=0为例,讲讲关于double类型的误差问题。

a为0时,方程的根为-c/b;

a不为0时得进一步确定判别式△,△=b*b-4*a*cd=△;

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);
}
自己写的第一篇,其中有不对的地方,希望可以指出共同讨论。

猜你喜欢

转载自blog.csdn.net/tuji67/article/details/80214930
今日推荐