C++中的精度问题

先来看一段代码:

#include <bits/stdc++.h>
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;
} 

输出为:

这里的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 <bits/stdc++.h>
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相同。

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

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

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

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

#include <bits/stdc++.h>
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;
}

输出为:

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

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

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

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

posted @   ncwzdlsd  阅读(145)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示