比较C中的浮点数
我有一个打印为0.000000
的double
,我试图将它与0.0f
进行比较, 0.0f
成功。 为什么这里有区别? 什么是最可靠的方法来确定你的双倍是零?
要确定它是否足够接近零,它将打印为0.000000
到六位小数,如下所示:
fabs(d) < 0.0000005
但是,处理浮点计算中的小的不准确性通常会变得非常复杂。
如果您想更好地了解您的价值,请尝试使用%g
而不是%f
打印。
你可以做一个范围。 像-0.00001 <= x <= 0.00001
这是现代计算机上浮点运算的基本问题。 它们本质上是不精确的,无法可靠地进行比较。 例如,语言ML明确禁止对实际类型进行相等比较,因为它被认为太不安全了。 另请参阅David Goldberg关于此主题的优秀(如果有点长且以数学为导向) 论文 。
编辑:tl;博士:你可能做错了。
此外,一个经常被忽略的浮点数特征是非规范化数。 这是具有最小指数的数字,但不适合0.5-1范围。
对于float,这些数字低于 FLT_MIN,对于double,这些数字低于 DBL_MIN。
使用阈值的常见错误是比较两个值,或使用FLT_MIN / DBL_MIN作为限制。
例如,这将导致非逻辑结果(如果您不了解非正规):
bool areDifferent(float a, float b) { if (a == b) return false; // Or also: if ((a - b) == FLT_MIN) return true; } // What is the output of areDifferent(val, val + FLT_MIN * 0.5f) ? // true, not false, even if adding half the "minimum value".
非正规数通常也意味着计算中的性能损失。 但是,您无法禁用它们,否则此类代码仍可能产生DIVIDE BY ZERO浮点exception(如果已启用):
float getInverse(float a, float b) { if (a != b) return 1.0f / (ab); // With denormals disabled, a != b can be true, but (a - b) can still be denormals, it'll rounded to 0 and throw the exception return FLT_MAX; }