2 + 2 = 5(*)
(对于某些浮点精度值的2)
当我们将“浮点数”视为增加精度的方法时,这个问题经常出现。然后我们遇到了“浮动”部分,这意味着没有保证可以表示哪些数字。
因此,虽然我们可能很容易地表示“1.0,-1.0,0.1,-0.1”,但随着数字变大,我们开始看到近似值 - 或者我们应该看到,除非我们通常通过截断数字来隐藏它们以供显示。
因此,我们可能认为计算机正在存储“0.003”,但它实际上可能存储“0.0033333333334”。
如果执行“0.0003 - 0.0002”会发生什么?我们期望得到0.0001,但实际存储的值可能更接近于“0.00033”-“0.00029”,这产生了“0.000004”,或者是最接近可表示值,可能是0,也可能是“0.000006”。
当前浮点数运算中, (a / b) * b == a 不能保证成立。
#include <stdio.h>
extern double bodge(int base, int divisor) {
return static_cast<double>(base) / static_cast<double>(divisor);
}
int main() {
int errors = 0;
for (int b = 1; b < 100; ++b) {
for (int d = 1; d < 100; ++d) {
double res = bodge(b, d) * static_cast<double>(d);
if (res != static_cast<double>(b))
++errors;
}
}
printf("errors: %d\n", errors);
}
ideone报告了599个实例,其中(b * d) / d != b,仅使用1<=b<=100和1<=d<=100的10,000种组合。
FAQ中描述的解决方案基本上是应用粒度约束 - 测试if (a == b +/- epsilon)
。
另一种方法是通过使用定点精度或将所需粒度用作存储的基本单位来完全避免问题。例如,如果您希望以纳秒精度存储时间,请使用纳秒作为存储单位。
C++11引入了std::ratio作为不同时间单位之间的定点转换的基础。
if(counter > 10.0) { counter = 0.0; //dostuff }
在代码的其他地方:if(counter == 0.0){//oh I know that counter is reseted} else{//do other stuff}
... - relaxxx