为什么比较双精度和单精度会导致意想不到的结果?
为什么比较双精度和单精度会导致意想不到的结果?
这个问题已经在这里有了答案:
可能重复:
float f = 1.1; double d = 1.1; if(f == d) // returns false!
为什么会这样?
admin 更改状态以发布 2023年5月22日
尝试运行此代码,结果将使原因显而易见。
#include#include int main() { std::cout << std::setprecision(100) << (double)1.1 << std::endl; std::cout << std::setprecision(100) << (float)1.1 << std::endl; std::cout << std::setprecision(100) << (double)((float)1.1) << std::endl; }
输出结果:
1.100000000000000088817841970012523233890533447265625 1.10000002384185791015625 1.10000002384185791015625
无论是float
还是double
都无法准确表示1.1。当您尝试进行比较时,浮点数会被隐式地上转换为双精度。双精度数据类型可以准确地表示浮点数的内容,因此比较得出false。
在考虑使用float
或double
数字时,需要考虑的重要因素有:
精度和舍入
精度:
浮点数的精度是它能表示多少个数字,而不会失去它包含的任何信息。
考虑分数1/3
。这个数的十进制表示为0.33333333333333…
,有无数个3。一个无限长度的数字需要无限的内存才能以精确的精度表示,但float
或double
数据类型通常仅有4
或8
字节。因此,浮点数和双精度数只能存储一定数量的数字,其余的数字必定会丢失。因此,没有明确定义的准确方法可以用变量随着精度要求更高的数字来表示浮点或双精度数字。
舍入:
二进制和十进制(基数为10)数字之间存在一些不明显的差异。
考虑分数1/10
。在十进制
中,这可以简单地表示为0.1
,并且0.1
可以被视为一个容易表示的数字。但是,在二进制中,0.1
由无限的序列表示:0.00011001100110011…
例子:
#includeint main() { using namespace std; cout << setprecision(17); double dValue = 0.1; cout << dValue << endl; }
这个输出是:
0.10000000000000001
而不是
0.1.
这是因为双精度数由于其有限的内存而必须截断逼近,导致一个不完全是0.1
的数字。这种情况称为四舍五入误差。
无论何时比较两个接近的浮点数或双精度数,都会出现舍入误差,最终比较会导致不正确的结果,这就是为什么你永远不应该使用==
来比较浮点数或双精度数的原因。
你可以做的最好的方法是取它们的差异并检查它是否小于一个epsilon。
abs(x - y) < epsilon