【问题标题】:Is C floating-point non-deterministic?C 浮点数是非确定性的吗?
【发布时间】:2014-08-11 22:55:35
【问题描述】:

我在某处读到 C 双精度浮点中存在不确定性的来源,如下所示:

  1. C 标准规定,仅需要 64 位浮点数(双精度)才能产生大约 64 位精度。

  2. 硬件可以在 80 位寄存器中进行浮点运算。

  3. 由于 (1),C 编译器不需要在将双精度值填充到高位之前清除浮点寄存器的低位。

  4. 这意味着 YMMV,即结果可能会发生微小差异。

是否存在真正发生这种情况的硬件和软件的任何现在常见的组合?我在其他线程中看到.net 有这个问题,但是 C 通过 gcc 加倍好吗? (例如,我正在测试基于精确相等的逐次逼近的收敛性)

【问题讨论】:

  • @Fabian 另一个问题是关于跨平台的可重复性,这是比同一平台上不同运行的可重复性更强的约束。
  • 我相信答案是肯定的。这意味着即使 x == x 也不能保证返回 true (这与无穷大或 NaN 无关,这是因为编译器可能会将相同的变量加载到 80 位寄存器中,然后将 64 位寄存器或内存加载到另一个时间)。
  • @EdHeal:程序不是计算机。
  • @EdHeal:为了证明你不是世界上唯一一个知道如何无用迂腐的人,你是actuallywrong
  • 浮点算术通常不允许关联确定性。然而,在线程或 SIMD 并行编程中,通常使用失败者浮点模型来允许关联浮点运算。不能保证您在每个系统上都会得到相同的结果。

标签: c floating-point numeric non-deterministic


【解决方案1】:

在大多数情况下(如果不是所有情况),标准都严格规定了精度过高的实现行为,这似乎是您关心的问题。结合 IEEE 754(假设您的 C 实现遵循附录 F),这并没有为您似乎在询问的那种不确定性留下空间。特别是,像x == x(Mehrdad 在评论中提到)这样的失败是被禁止的,因为对于何时在表达式中保持超精度以及何时丢弃它是有规则的。显式转换和分配给对象是降低过度精度并确保您使用标称类型的操作。

但是请注意,仍然有许多不符合标准的损坏编译器。除非您使用-std=c99-std=c11(即“gnu99”和“gnu11”选项在这方面被故意破坏),否则 GCC 会故意忽略它们。在 GCC 4.5 之前,甚至不支持正确处理超精度。

【讨论】:

  • 只有当你要求-ffast-math时,IEEE754不是被gcc破坏了吗?
  • -fexcess-precision=fast 在不符合标准的配置文件中默认打开,包括默认配置文件(gnu89 或 gnu99 或现在的其他配置文件)。
  • 刚刚检查过,你是对的。幸运的是,在 AMD64 上它默认使用 SSE,因此无需处理过多的精度。
  • 我希望我能多次投票给这个答案。浮点数是微妙的,但这与非确定性的巨大不同。浮点数用于设计桥梁、建筑物和飞机;您可以想象,非确定性在这些学科中不会被视为有帮助。
  • @JonathanDursi 如何翻译给定的源代码不是“微妙的”,而是不确定的。
【解决方案2】:

这可能发生在使用 x87 浮点单元的 Intel x86 代码上(可能除了 3.,这似乎是假的。LSB 位将设置为零。)。所以硬件平台很普遍,但在软件方面,x87的使用正在逐渐消失,有利于SSE。

基本上,数字是用 80 位还是 64 位表示是编译器的突发奇想,并且可能在代码中的任何位置发生变化。例如,结果是刚刚测试非零的数字现在为零。 m)

参见"The pitfalls of verifying floating-point computations",第 8 页。

【讨论】:

    【解决方案3】:

    测试浮点中的精确收敛(或相等)通常是一个坏主意,即使在完全确定的环境中也是如此。 FP 是一开始的近似表示。在指定的 epsilon 内测试收敛性要安全得多。

    【讨论】:

    • 是的,但是对于任何测试,非确定性意味着您永远不知道是否会再次通过测试。非常令人不安!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多