C++中的精度问题

先来看一段代码:

#include 
using namespace std;

int main()
{
	float x=1.0;
	double y=2.0;
	x=x/3.14159;
	x=x*3.14159;
	if(x==1.0)
	{
		printf("YES1\n");
	}
	else
	{
		printf("NO1\n");
	}
	
	y=sqrt(y);
	y=y*y;
	if(y==2.0)
	{
		printf("YES2\n");
	}
	else
	{
		printf("NO2\n");
	}
	
	return 0;
} 

输出为:

C++中的精度问题_第1张图片

这里的x、y分别定义的是float和double类型,目的是判断x、y分别进行先除后乘、先开方再平方之后得到的结果是否与原值相等,结果是否,下面作简要分析:

(float和double型都默认保存6位)

关于第一块命令,即:

x=x/3.14159;
x=x*3.14159;

用1除以3.14159,结果显然是除不尽的,系统默认保留至小数点后六位,而1/3.1415926=0.31830989161357204622903682673559,程序输出为0.318310;

显然,0.31830989161357204622903682673559<0.318310,因此将该值乘3.14159,大于原值;

关于第二块命令,即

y=sqrt(y);
y=y*y;

根号2的值为1.4142135623730950488016887242097,同理系统默认保留至小数点后六位,程序输出为1.414214;

由于四舍五入原则,该值仍然大于原值1.4142135623730950488016887242097,因此将该值平方,大于原值;

所以均输出“NO”。

再来看一段代码:

#include 
using namespace std;

int main()
{
	float x=1.0;
	double y=2.0;
	x=x/3.14159;
	x=x*3.14159;
//	if(x==1.0)
	if(fabs(x - 1.0) < 0.000001)
	{
		printf("YES1\n");
	}
	else
	{
		printf("NO1\n");
	}
	
	y=sqrt(y);
	y=y*y;
//	if(y==2.0)
	if(fabs(y - 2.0) < 1e-6)
	{
		printf("YES2\n");
	}
	else
	{
		printf("NO2\n");
	}
	return 0;
} 

注:

①:fabs()的参数是一个变量或者算术表达式,返回值是这个变量或者表达式的绝对值,数据类型是浮点数;

②:1e-6即为1乘10的-6次方,大小与0.000001相同。

与第一段代码相比,唯一的区别就是将条件由判断是否相等改为判断精确度范围,输出为:

C++中的精度问题_第2张图片

由此可见,经过除3.14159和乘3.14159后的x,开方后乘方的y,与原值的差异均小于0.000001。

原因是,x、y在进行第一步运算时,与原值的差异其实已经小于0.000001,

对于x,y来说,对其运算进行分步输出如下:

#include 
using namespace std;

int main()
{
	float x=1.0;
	printf("%f\n",x/3.14159);
	x=x/3.14159;
	printf("%f\n",x*3.14159);
	double y=2.0;
	printf("%f\n",sqrt(y));
	y=sqrt(y);
	printf("%f\n",y*y);
	return 0;
}

输出为:

C++中的精度问题_第3张图片

由于输出数据为浮点型,会自动进行四舍五入,如果此时将printf("%f",)改为printf("%d",),输出为:

C++中的精度问题_第4张图片

即在两步运算中产生了误差,实际的x小于1,y小于2。

对于x,假设x先除以n并保留小数点后六位再乘n,所得结果与原值的差一定小于0.000001(否则即可小数点后第七位可再进一位);

对于y,两个小于0.000001的误差值相乘一定小于0.000001。

你可能感兴趣的:(笔记,c++)