【问题标题】:Does float have a negative zero? (-0f)浮点数是否为负零? (-0f)
【发布时间】:2011-02-23 19:25:13
【问题描述】:

IEEE 浮点数分配了一个位来指示符号,这意味着从技术上讲,您可以使用不同的二进制表示零(+0 和 -0)。有没有我可以做的算术运算,例如在 C 中导致负零浮点值?

这个问题的灵感来自另一个问题,它质疑您是否可以使用== 安全地比较0.0f,我进一步想知道是否还有其他方法可以表示零,这会导致float1 == 0.0f 看似完美地中断相等的值。

[编辑] 请不要评论比较浮动是否相等的安全性!我并不是要添加到那些溢出的重复问题中。

【问题讨论】:

  • 更有趣的是 NaN。 NaN 比较不等于所有值,包括它自己!
  • “是否有我可以在 C 中执行的算术运算,例如导致负零浮点值?” - 可能 C 是一个不好的例子,因为 C 不保证它的浮点类型是 IEEE 浮点数。就 C 标准而言,没有可移植的方式保证 生成负零,但是有些操作允许 生成负零。还有一种实现方式可以宣传它的浮点数实际上是 IEEE 浮点数,在这种情况下,游戏就开始了。
  • 请提供“另一个问题是否可以安全地比较0.0f 使用==”的链接

标签: floating-point language-agnostic negative-zero


【解决方案1】:

根据标准,负零存在,但它等于正零。对于几乎所有目的,两者的行为方式相同,并且许多人认为否定的存在是实现细节。但是,有些函数的行为完全不同,即除法和atan2

#include <math.h>
#include <stdio.h>

int main() {
    double x = 0.0;
    double y = -0.0;
    printf("%.08f == %.08f: %d\n", x, y, x == y);
    printf("%.08f == %.08f: %d\n", 1 / x, 1 / y, 1 / x == 1 / y);
    printf("%.08f == %.08f: %d\n", atan2(x, y), atan2(y, y), atan2(x, y) == atan2(y, y));
}

这段代码的结果是:

0.00000000 == -0.00000000: 1
1.#INF0000 == -1.#INF0000: 0
3.14159265 == -3.14159265: 0

这意味着代码可以正确处理某些限制,而无需显式处理。对于接近极限的值依赖这个特性并不是一个好主意,因为一个简单的计算错误可能会改变符号并使值远离正确,但如果你避免计算,你仍然可以利用它换个牌子。

【讨论】:

  • 你能引用一个标准参考吗?
【解决方案2】:

有算术运算吗 例如可以在 C 中做这导致 在负零浮点 价值?

当然:

float negativeZero = -10.0e-30f * 10.0e-30f;

乘法的数学精确结果不能表示为浮点值,因此它会四舍五入到最接近的可表示值,即-0.0f

负零的语义在 IEEE-754 标准中有很好的定义;在算术表达式中,它的行为与零的行为不同的唯一真正可观察的方式是,如果你除以它,你将得到一个不同的无穷大符号。例如:

1.f /  0.f --> +infinity
1.f / -0.f --> -infinity

-0.f 的比较、加法和减法与+0.f 的结果相同(在默认舍入模式下)。乘法可以保留零的符号,但如前所述,它通常是不可观察的。

一些数学库函数,其行为可能会因零的符号而异。例如:

copysignf(1.0f, 0.0f) -->  1.0f
copysignf(1.0f,-0.0f) --> -1.0f

这在复杂函数中比较常见:

csqrtf(-1.0f + 0.0f*i) --> 0.0f + 1.0f*i
csqrtf(-1.0f - 0.0f*i) --> 0.0f - 1.0f*i

不过,一般来说,您不必担心负零。

【讨论】:

  • 如果表达式 float negativeZero = -10.0e-30f * 10.0e-30f; 舍入为 0.0f 而不是 -0.0f 会不会更好。如果正零和负零都相同,为什么不消除这种歧义并只保留正零呢?另一种获得负零的简单方法-:float neg=-0.00000000000000000001; printf("%f",neg);
【解决方案3】:

是的,零可以签名,但标准要求正零和负零测试相等

【讨论】:

    【解决方案4】:

    有几个简单的算术运算会导致负零答案(至少在我测试过的 i386/x64/ARMv7/ARMv8 系统上):

    • -1 * 0
    • 0 / -1

    当我编写优化器来简化算术表达式时,这些让我感到惊讶。将“a = b * 0”优化为“a = 0”,如果 b 恰好为负数(正确答案为 -0 )。

    【讨论】:

      【解决方案5】:

      是的,float does 有一个负零,但是 no,在比较浮点值时不必担心这个问题。

      浮点运算被定义为在特殊情况下正常工作。

      【讨论】:

      • 许多编译器将 FP 值的 == 转换为内存比较。
      • @David:如果他们在这样做时不考虑负零,则应将其作为错误报告给编译器供应商。
      • @David:当然可以,但是这些语言不算在内。 =P
      • @David:我很震惊地发现有人在做有限元建模而不使用 fortran,所以我承认我的好奇心:你使用的语言/编译器 尊重 IEEE-754?
      • @David:很有趣。我仍然认为这种行为值得向您的编译器供应商投诉,特别是如果他们设法在其他方面符合 IEEE-754。德尔福采用这种方法是否有一些奇怪的历史原因?
      【解决方案6】:

      是的,floats 与其他 IEEE 浮点类型(例如 double)一样具有负零(在具有 IEEE 浮点的系统上)。 Octave 中有一个示例here 说明如何创建它们;相同的操作在 C 中有效。不过,== 运算符将 +0 和 -0 视为相同,因此负零不会破坏这种类型的比较。

      【讨论】:

      • 您指的是 Octave == 运算符吗?
      • @David:C ==,但 Octave 也应该这样做。
      【解决方案7】:

      是的,您可以使用 +0 和 -0,它们是不同的位模式(应该无法通过相等性测试)。你不应该使用 == 和浮点数,当然不是 IEEE 浮点数。 都可以。关于这个主题还有很多其他的 SO 问题和讨论,所以我不会在这里展开。

      【讨论】:

      • +0 和 -1?你不是说我认为
      • -1 平等比比较位更进一步。而且,事实上,-0 和 +0 被定义 相等。
      • 很公平,一个快速的示例程序确认 gcc 在 -0 和 +0 之间产生相等性。并不意味着您不能有 -0,即原始问题,也不意味着使用 float 进行相等比较是一个好主意。
      • 您是否有参考,其中 -0 和 +0 被定义为相等?谢谢。
      • 尽管出于比较目的,负零和正零通常被认为是相等的,但某些编程语言关系运算符和类似结构可能或确实将它们视为不同的。
      【解决方案8】:

      在使用浮点数进行相等比较时应该小心。请记住,您正在尝试在二进制系统中表示十进制值。

      Is it safe to check floating point values for equality to 0?

      如果您必须比较浮点值,我建议您使用某种您可以接受的容差float1 &lt;= toleranceVal &amp;&amp; float1 &gt;= toleranceVal2 或乘以十倍并转换为整数。 if (!(int)(float1 * 10000)) { .. some stuff .. }

      【讨论】:

      • 十进制/二进制不是问题,它的可表示性/精度不是一回事
      【解决方案9】:

      -lm 具有 signbit() 函数可用于指示值是否为负(包括 -0)

      【讨论】:

        【解决方案10】:

        这个float1 == 0.0f 从来都不是一个真正安全的比较。

        如果你有类似的东西

        float x = 0.0f;
        for (int i = 0; i < 10; i++) x += 0.1f;
        x -= 1.0f;
        assert (x == 0.0f);
        

        即使看起来应该是 0,它也会失败。

        【讨论】:

        • 这个答案与启发我的问题有关。不过不是我的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-02-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多