C浮点是非确定性的吗?

C浮点是非确定性的吗?,c,floating-point,numeric,non-deterministic,C,Floating Point,Numeric,Non Deterministic,我在某个地方读到过,在C双精度浮点中有一个非确定性的来源,如下所示: C标准规定,64位浮点(双精度)只需要产生大约64位的精度 硬件可以在80位寄存器中进行浮点运算 由于(1)的原因,C编译器不需要在向高阶位填充双精度之前清除浮点寄存器的低阶位 这意味着YMMV,即可能出现结果上的微小差异 现在有没有什么硬件和软件的共同组合可以真正做到这一点?我在其他线程中看到.net有这个问题,但是通过gcc实现C双倍可以吗?(例如,我正在测试基于完全相等的逐次逼近的收敛性)这可能发生在使用x87浮点单元的

我在某个地方读到过,在C双精度浮点中有一个非确定性的来源,如下所示:

  • C标准规定,64位浮点(双精度)只需要产生大约64位的精度

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

  • 由于(1)的原因,C编译器不需要在向高阶位填充双精度之前清除浮点寄存器的低阶位

  • 这意味着YMMV,即可能出现结果上的微小差异


  • 现在有没有什么硬件和软件的共同组合可以真正做到这一点?我在其他线程中看到.net有这个问题,但是通过gcc实现C双倍可以吗?(例如,我正在测试基于完全相等的逐次逼近的收敛性)

    这可能发生在使用x87浮点单元的英特尔x86代码上(可能3除外,这似乎是假的。LSB位将设置为零)。因此,硬件平台非常普遍,但在软件方面,x87的使用正在逐渐消失,取而代之的是SSE

    基本上,一个数字是用80位还是64位来表示取决于编译器的心血来潮,并且可能在代码中的任何一点发生变化。例如,一个刚被测试为非零的数字现在是零。m)


    见第8ff页

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


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

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

    @Fabian另一个问题是关于跨平台的可重复性,这是一个比同一平台上不同运行的可重复性更强的约束。我相信答案是肯定的。这意味着即使
    x==x
    也不能保证返回true(这与无穷大或NaN无关,因为编译器可能会将同一变量加载到80位寄存器中一次,另一次加载到64位寄存器或内存中)@EdHeal:程序不是计算机。@EdHeal:为了证明你不是世界上唯一一个知道如何毫无用处地学究式的人,你是。浮点运算通常不允许与确定性相关联。然而,在使用线程或SIMD的并行编程中,经常使用浮点模型来允许关联浮点运算。无法保证您在每个系统上都会得到相同的结果。IEEE754不是只有在您要求
    -ffast math
    时才会被gcc破坏吗?
    -fexcess precision=fast
    在不符合标准的配置文件中默认打开,包括默认配置文件(gnu89或gnu99或现在的任何内容)。现在刚刚检查,你是对的。幸运的是,在AMD64上,它默认使用SSE,因此没有多余的精度需要处理。我希望我能多次投票支持这个答案。浮点数字是微妙的,但这与非确定性有很大的不同。浮点数用于设计桥梁、建筑物和飞机;你可以想象,非决定论在这些学科中是没有帮助的。@JonathanDursi给定源代码的翻译方式不是“微妙的”,而是非决定论的。是的,但对于任何测试,非决定论意味着你永远不知道是否会在下一次通过测试。非常令人不安!