比较浮点数与零的标准方法是什么



可能是:比较浮点数与零的标准方法是什么?

据我所知直接比较:

if ( x == 0 ) { 
  // x is zero?
} else {
  // x is not zero??

可能会因浮点变量而失败。

我曾经使用

float x = ...
...
if ( std::abs(x) <= 1e-7f ) { 
  // x is zero, do the job1
} else {
 // x is not zero, do the job2
...

我在这里找到的方法相同。但我看到两个问题:

  1. 随机幻数 1e-7f(或上面链接中的 0.00005)。
  2. 代码更难阅读

这是一个如此常见的比较,我想知道是否有一个标准的简短方法来做到这一点。喜欢

 x.is_zero();

要将浮点值与 0 进行比较,只需比较它:

if (f == 0)
    // whatever

这种比较没有错。如果它没有按照你的期望去做,那是因为f的价值不是你想象的那样。它本质上与此相同的问题:

int i = 1/3;
i *= 3;
if (i == 1)
    // whatever

这种比较没有错,但i的值不是 1。几乎所有程序员都了解整数值的精度损失;许多人不理解浮点值。

使用"几乎相等"而不是==是一种先进的技术;它经常导致意想不到的问题。例如,它不是可传递的;也就是说,a几乎等于bb几乎等于c并不意味着a几乎等于c

没有标准的方法,因为是否要把一个小数字当作零来处理取决于你如何计算这个数字以及它的用途。这反过来又取决于计算引入的任何误差的预期大小,也可能取决于确定原始输入的物理测量误差。

例如,假设您的值表示某些地图软件中的旅程长度(以英里为单位)。然后,您很乐意将1e-7视为等于零,因为在这种情况下,这是一个非常小的数字:它是由于舍入误差或其他轻微不精确的原因而出现的。

另一方面,假设您的值在某些电子显微镜软件中以米为单位表示分子的大小。那么你当然不想1e-7看成等于零,因为在这种情况下,这是一个非常大的数字。

您应该首先考虑显示您的值的合适精度:误差线是多少,或者您可以合理显示多少有效数字。这将使您了解针对零进行测试的公差,尽管它仍然可能无法解决这种情况。对于地图软件,如果旅程小于某个固定值,您可能会将其视为零,尽管该值本身可能取决于地图的分辨率。对于显微镜软件,如果两种尺寸之间的差异为零,这些测量的95%误差范围为零,则可能仍然不足以将它们描述为相同的尺寸。

我不知道

我的答案是否有用,我在 irrlicht 的 irrmath.h 中找到了这个,直到现在仍在引擎的 mathlib 中使用它:

const float ROUNDING_ERROR_f32 = 0.000001f;
//! returns if a equals b, taking possible rounding errors into account
inline bool equals(const float a, const float b, const float tolerance = ROUNDING_ERROR_f32)
{
        return (a + tolerance >= b) && (a - tolerance <= b);
}

作者通过"经过多次旋转(三角运算)后,坐标破坏和直接比较可能会导致故障"来解释这种方法。

最新更新