在计算机中, 我们的real number 是以二进制的方式存储的。 而且存储一个float或者一个double类型的数据的存储空间是固定的, float一般是4个字节, double是8个字节。于是这就涉及到了将十进制转换为二进制的过程中, 可能一个十进制的数对应的二进制的表示的位数是无穷大的。 例如十进制数字0.1 和 0.15都不能在计算机中精确的表示。 除非我们使用无穷多的位数去表示0.1 或者0.15, 1.0/3.0等这样的数数字。
bottom line:、
Never use == to compare two floating point numbers
下面看如下例:
#include <iostream>
using namespace std;
int main()
{
cout << 0.15 << endl;
cout << 0.1 << endl;
if (0.3 == 3 * 0.1)
cout << "YES" << endl;
else
cout << "NOT" << endl;
return 0;
}
运行结果:
问题, 既然0.15无法精确的表示, 为什么仍然可以精确输出来的?
下面是解答:
当我们迫切需要比较两个double的数值该咋办呢?
The message is that some floating point numbers cannot always be represented exactly, so comparisons don't always do what you'd like them to do. In other words, if the computer actually multiplies 10.0 by 1.0/10.0, it might not exactly get 1.0 back.
That's the problem. Now here's the solution: be very careful when comparing floating point numbers for equality (or when doing other things with floating point numbers; e.g., finding the average of two floating point numbers seems simple but to do it right requires an if/else with at least three cases).
Here's the wrong way to do it:
void dubious(double x, double y) { ... if (x == y) // Dubious! foo(); ... }If what you really want is to make sure they're "very close" to each other (e.g., if variable a contains the value 1.0 / 10.0 and you want to see if (10*a == 1)), you'll probably want to do something fancier than the above:
void smarter(double x, double y) { ... if (isEqual(x, y)) // Smarter! foo(); ... }There are many ways to define the isEqual() function, including:
#include <cmath> /* for std::abs(double) */ inline bool isEqual(double x, double y) { const double epsilon = /* some small number such as 1e-5 */; return std::abs(x - y) <= epsilon * std::abs(x); // see Knuth section 4.2.2 pages 217-218 }Note: the above solution is not completely symmetric, meaning it is possible for isEqual(x,y) != isEqual(y,x). From a practical standpoint, does not usually occur when the magnitudes of x and y are significantly larger than epsilon, but your mileage may vary.
另外: 补充一下float和double的区别: