C++ 在C+中,添加双精度值会在不同的程序之间产生不同的结果+;

C++ 在C+中,添加双精度值会在不同的程序之间产生不同的结果+;,c++,precision,addition,floating-accuracy,C++,Precision,Addition,Floating Accuracy,我有一个关于浮点加法的问题。我了解编译器和处理器体系结构如何产生浮点算术值。我在这里看到了许多与我的问题类似的问题,但是它们都有一些变化,比如不同的编译器、不同的代码、不同的机器等等,我遇到了一个问题,在两个不同的程序中,使用相同的参数调用相同的函数,以相同的方式在精确的中添加双精度,这会导致不同的结果。两个程序都在同一台机器上使用相同的编译器/标记进行编译。代码与此类似: void function(double tx, double ty, double tz){ double a

我有一个关于浮点加法的问题。我了解编译器和处理器体系结构如何产生浮点算术值。我在这里看到了许多与我的问题类似的问题,但是它们都有一些变化,比如不同的编译器、不同的代码、不同的机器等等,我遇到了一个问题,在两个不同的程序中,使用相同的参数调用相同的函数,以相同的方式在精确的中添加双精度,这会导致不同的结果。两个程序都在同一台机器上使用相同的编译器/标记进行编译。代码与此类似:

void function(double tx, double ty, double tz){

    double answer;
    double x,y;

    x = y = answer = 0;

    x = tx - ty;
    y = ty - tz;

    answer = (tx + ty + tz) * (x*y)
}
以下各项的价值:

tx,ty,tz

订单号为[10e-15,10e-30]。显然,这是我实际使用的函数的一个非常简化的版本,但是,两个程序,在同一台机器上,使用相同的编译器/标记,运行相同的浮点运算(不只是相同的函数,完全相同的代码),是否可能得到不同的函数结果?

答案很简单。如果您的计算机表现为确定性
,它将始终为相同的输入返回相同的结果。这是迄今为止编程语言背后的基本思想。(当然,除非我们谈论的是量子计算机。)

因此,问题归结为您是否真的有相同的输入

尽管上述函数看起来功能严格,但通常存在不太明显的隐藏输入。例如,您可以在调用函数之前调整FPU的舍入模式。或者您可以设置不同的异常行为。在这两种情况下,对于某些输入,函数的行为可能不同


因此,即使您的计算机不是非确定性的(即有缺陷),上述函数也可能返回不同的结果。虽然可能性不大。

答案很简单。如果您的计算机表现为确定性
,它将始终为相同的输入返回相同的结果。这是迄今为止编程语言背后的基本思想。(当然,除非我们谈论的是量子计算机。)

因此,问题归结为您是否真的有相同的输入

尽管上述函数看起来功能严格,但通常存在不太明显的隐藏输入。例如,您可以在调用函数之前调整FPU的舍入模式。或者您可以设置不同的异常行为。在这两种情况下,对于某些输入,函数的行为可能不同

因此,即使您的计算机不是非确定性的(即有缺陷),上述函数也可能返回不同的结果。尽管可能性不大。

有些可能性:

  • 函数
    的源代码在两个程序中是相同的,但它在不同的上下文中出现,导致编译器以不同的方式编译它。例如,编译器可能将其内联在一个位置而不是另一个位置,内联可能会由于在内联调用点与其他表达式的组合而导致某些表达式减少,因此会执行不同的算法。(要测试这一点,请将
    函数
    移动到一个单独的源文件中,单独编译,并在不进行跨模块优化的情况下将其与链接器链接。此外,请尝试在禁用优化的情况下编译。)

  • 您认为
    函数
    有相同的输入,因为它们在打印或在调试器中查看时看起来是相同的,但由于未打印的低位之间的细微差异,它们实际上是不同的。(要测试这一点,请使用十六进制浮点格式打印完整值。为此,请在输出流中插入
    std::hexfloat
    ,后跟浮点值。或者,使用
    %a
    格式使用C
    printf
    。)

  • 程序中的其他内容会更改浮点状态,例如舍入模式

  • 您认为您使用了相同的编译器、相同的源代码、相同的编译开关等等,但实际上没有

  • 请注意,浮点值在存储时可能会发生更改,就像它们只是溢出到堆栈时一样。这是因为某些处理器和C++实现可以在寄存器中存储浮点值,而在存储器中的精度较低。从技术上讲,这符合1。(在
    函数中名义上不同的计算)或2。(传递给
    函数的值不同),但它的隐蔽性足以值得单独提及。

    一些可能性:

  • 函数
    的源代码在两个程序中是相同的,但它在不同的上下文中出现,导致编译器以不同的方式编译它。例如,编译器可能将其内联在一个位置而不是另一个位置,内联可能会由于在内联调用点与其他表达式的组合而导致某些表达式减少,因此会执行不同的算法。(要测试这一点,请将
    函数
    移动到一个单独的源文件中,单独编译,并在不进行跨模块优化的情况下将其与链接器链接。此外,请尝试在禁用优化的情况下编译。)

  • 您认为
    函数
    有相同的输入,因为它们在打印或在调试器中查看时看起来是相同的,但由于未打印的低位之间的细微差异,它们实际上是不同的。(要测试这一点,请使用十六进制浮点格式打印完整值。为此,请在输出流中插入
    std::hexfloat
    ,后跟浮点值。或者,使用
    %a
    格式使用C
    printf
    。)

  • 程序中的其他内容会更改浮点状态,例如roundi