【问题标题】:Comparing floating point numbers in C比较 C 中的浮点数
【发布时间】:2011-10-23 22:21:58
【问题描述】:

我有一个打印为0.000000double,我试图将它与0.0f 进行比较,但没有成功。为什么这里有区别?确定双精度值是否为零的最可靠方法是什么?

【问题讨论】:

  • 您想知道它是否完全为零,或者它是否足够接近零以至于它是小数点后 0.000000 到 6 位?换句话说,如果它非零但足够接近零以打印与零相同的值,对您来说重要吗?
  • 请显示一些代码,并解释您所说的“不成功”是什么意思。

标签: c comparison floating-point zero


【解决方案1】:

要确定它是否足够接近于零以将0.000000 打印到小数点后六位,例如:

fabs(d) < 0.0000005

不过,处理浮点计算中的小错误通常会变得相当复杂。

如果您想更好地了解自己的价值,请尝试使用%g 而不是%f 进行打印。

【讨论】:

  • 假设您的编译器支持它,您应该使用 DBL_MIN 而不是任意常量。 DBL_MIN(通常?)定义为 2.2250738585072014e-308,它比 0.0000005 小很多,可能有助于消除误报
  • @Steve Mallam:如果DBL_MIN 是可表示的最小浮点数,那么检查小于该值的目的是什么?
  • @Greg:其实DBL_MIN是最小的标准化双精度值,实现可能支持更小的去标准化值。
  • @Steve Mallam:是的,这取决于提问者如何打印它以及他们认为出于他们的目的应该算作零的值有多小。我假设小数点后六位,尽管我没有说明,因此我的代码。 DBL_MIN 非常小,但是,根本没有多少有错误的计算非常接近。有时DBL_EPSILON 乘以计算中数字的大小是好的。使用%g,即使是精确的双精度值0.0 也不会打印为0.000000,我认为没有任何值可以。所以我不知道到底在问什么,这是我最好的猜测,%f
  • 全面+1,你们都说对了:DBL_EPSILON 是我打算建议的值!道歉 - 我想我匆忙发表评论......
【解决方案2】:

你可以做一个范围。比如 -0.00001

【讨论】:

  • 编译,但它不会做你想做的事。试试x=-0.00002;x=5e-6;
  • 你想要-0.00001 &lt;= x &amp;&amp; x &lt;= 0.00001
【解决方案3】:

这是现代计算机上浮点运算的基本问题。它们本质上是不精确的,无法可靠地进行比较。例如,语言 ML 明确禁止对真实类型进行相等比较,因为它被认为太不安全。另请参阅 David Goldberg 关于此主题的出色(如果有点长且面向数学)paper

编辑:tl;博士:你可能做错了。

【讨论】:

    【解决方案4】:

    此外,浮点数的一个经常被忽视的特性是非规范化数。 这是指数最小的数字,但不在 0.5-1 范围内。

    这些数字低于浮点数的 FLT_MIN 和双精度数的 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".
    

    非正规化通常也意味着计算中的性能损失。 但是,您不能禁用它们,否则此类代码仍可能产生除零浮点异常(如果启用):

    float getInverse(float a, float b) {
        if (a != b)
            return 1.0f / (a-b); // 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;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多