Why comparing double and float leads to unexpected result?
Possible Duplicate:
strange output in comparision of float with float literal
1 2 3 | float f = 1.1; double d = 1.1; if(f == d) // returns false! |
为什么会这样?
考虑到
精度:浮点数的精度是指在不丢失所包含的任何信息的情况下,浮点数可以表示的位数。
考虑分数
舍入:
一个例子:
1 2 3 4 5 6 7 8 | #include <iomanip> int main() { using namespace std; cout << setprecision(17); double dValue = 0.1; cout << dValue << endl; } |
这个输出是:
1 | 0.10000000000000001 |
而不是
1 | 0.1. |
这是因为double由于内存有限而必须截断近似值,从而导致一个不完全是
每当比较两个接近浮点数和双精度数时,这样的舍入误差就会产生错误的结果,这就是为什么您不应该使用
你所能做的最好的就是利用它们的差异,检查它是否小于一个ε。
1 | abs(x - y) < epsilon |
尝试运行此代码,结果会使原因变得明显。
1 2 3 4 5 6 7 8 9 | #include <iomanip> #include <iostream> 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 2 3 | 1.100000000000000088817841970012523233890533447265625 1.10000002384185791015625 1.10000002384185791015625 |
一般来说,不应该使用
最佳实践是减去它们,然后检查差值的绝对值是否小于一个小的epsilon。
1 2 3 4 | if(std::fabs(f - d) < std::numeric_limits<float>::epsilon()) { // ... } |
一个原因是因为浮点数是(或多或少)二进制分数,并且只能近似许多十进制数字。许多十进制数必须转换为重复的二进制"小数",或无理数。这将引入舍入误差。
维基百科:
For instance, 1/5 cannot be represented exactly as a floating point number using a binary base but can be represented exactly using a decimal base.
在您的特定情况下,对于非理性/重复分数,float和double将具有不同的舍入,而非理性/重复分数必须用二进制表示
我上面给出的代码通过简单地检查值是否在非常短的delta内来解决这个问题。您的比较从"这些值相等吗?""这些值彼此之间的误差是否在很小的范围内?"
另外,请看这个问题:什么是最有效的浮动和双重比较方法?
关于浮点数还有很多其他的奇怪之处,它们打破了简单的相等比较。查看本文了解其中一些内容的描述:
http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
ieee 754 32位
明白他们为什么不"平等"?
在IEEE754中,分数以2的幂存储:
1 2 | 2^(-1), 2^(-2), 2^(-3), ... 1/2, 1/4, 1/8, ... |
现在我们需要一种方法来代表
1 2 3 | 2^(-4) + 2^(-5) + 2^(-8) + 2^(-9) + 2^(-12) + 2^(-13) + ... + 2^(-24) + 2^(-25) + 2^(-27) 00011001100110011001101 1.10000002384185791015625 |
对于64位的
Resources
IEEE 754 Converter (32-bit)
浮点数和双精度数以二进制格式存储,不能精确表示每个数字(在有限空间中不可能表示无限多个可能的不同数字)。
因此,他们进行四舍五入。浮点必须舍入超过两倍,因为它较小,所以1.1舍入到最近的有效浮点不同于1.1舍入到最近的valud double。
要查看哪些数字是有效的浮点和双精度,请参见浮点