为什么GDB以不同于C的方式评估浮点运算?

在尝试处理浮点算术问题时,我遇到了一些有点混乱的事情.

一,代码.我将这个问题的精华放在了这个例子中:

#include <iostream>
#include <iomanip>

using namespace std;
typedef union {long long ll; double d;} bindouble;

int main(int argc, char** argv) {
    bindouble y, z, tau, xinum, xiden;
    y.d = 1.0d;
    z.ll = 0x3fc5f8e2f0686eee; // double 0.17165791262311053
    tau.ll = 0x3fab51c5e0bf9ef7; // double 0.053358253178712838
    // xinum = double 0.16249854626123722 (0x3fc4ccc09aeb769a)
    xinum.d = y.d * (z.d - tau.d) - tau.d * (z.d - 1);
    // xiden = double 0.16249854626123725 (0x3fc4ccc09aeb769b)
    xiden.d = z.d * (1 - tau.d);
    cout << hex << xinum.ll << endl << xiden.ll << endl;
}

xinum和xiden应该具有相同的值(当y == 1时),但是由于浮点舍入错误,它们没有.我得到的那部分

当我运行这个代码(实际上是我的真实程序)通过GDB来跟踪差异时,出现了这个问题.如果我使用GDB重现在代码中完成的评估,它给出了xiden的不同结果:

$gdb mathtest
GNU gdb (Gentoo 7.5 p1) 7.5
...
This GDB was configured as "x86_64-pc-linux-gnu".
...
(gdb) break 16
Breakpoint 1 at 0x4008ef: file mathtest.cpp, line 16.
(gdb) run
Starting program: /home/diazona/tmp/mathtest 
...
Breakpoint 1, main (argc=1, argv=0x7fffffffd5f8) at mathtest.cpp:16
16          cout << hex << xinum.ll << endl << xiden.ll << endl;
(gdb) print xiden.d
$1 = 0.16249854626123725
(gdb) print z.d * (1 - tau.d)
$2 = 0.16249854626123722

你会注意到,如果我要求GDB计算z.d *(1-tau.d),它给出0.16249854626123722(0x3fc4ccc09aeb769a),而程序中计算相同内容的实际C代码给出0.16249854626123725(0x3fc4ccc09aeb769b).所以GDB必须使用不同的浮点运算评估模型.任何人都可以看清这一点吗? GDB的评估与我的处理器的评估不同?

我看过this related question询问GDB评估sqrt(3)为0,但这不应该是一样的,因为这里没有函数调用.

最佳答案
可能是因为x86 FPU在寄存器中工作在80位精度,但是当值存储到存储器时会舍入到64位. GDB将在(解释)计算的每个步骤存储到内存.

转载注明原文:为什么GDB以不同于C的方式评估浮点运算? - 代码日志