我在處理浮點算術問題時遇到了一些令人困惑的事情。爲什麼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,但這不應該是一回事,因爲這裏沒有涉及函數調用。
實際上,gdb的結果在數學上是更正確的,所以看起來好像gdb使用FPU的更高精度,而g ++可能使用SSE指令。 –