Tôi đã gặp phải một chút gì đó khó hiểu khi cố giải quyết vấn đề số học dấu chấm động.Tại sao GDB đánh giá số học dấu phẩy động khác với C++?
Đầu tiên, mã. Tôi đã cất bản chất của vấn đề của tôi vào ví dụ này:
#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
và xiden
nên có giá trị như nhau (khi y == 1
), nhưng vì dấu chấm động lỗi roundoff họ thì không. Đó là phần tôi nhận được.
Câu hỏi xuất hiện khi tôi chạy mã này (thực sự, chương trình thực sự của tôi) thông qua GDB để theo dõi sự khác biệt. Nếu tôi sử dụng GDB để tạo lại đánh giá thực hiện trong các mã, nó mang lại cho một kết quả khác nhau cho 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
Bạn sẽ nhận thấy rằng nếu tôi hỏi GDB để tính toán z.d * (1 - tau.d)
, nó mang lại cho 0,16249854626123722 (0x3fc4ccc09aeb769a), trong khi mã C++ thực tế tính toán điều tương tự trong chương trình cho 0.16249854626123725 (0x3fc4ccc09aeb769b). Vì vậy, GDB phải sử dụng một mô hình đánh giá khác cho số học dấu phẩy động. Có ai có thể làm sáng tỏ thêm về điều này không? Đánh giá của GDB khác với đánh giá của bộ xử lý của tôi như thế nào?
Tôi đã xem this related question hỏi về GDB đánh giá sqrt(3)
đến 0, nhưng điều này không phải là điều tương tự vì không có cuộc gọi chức năng nào có liên quan ở đây.
Thực tế, kết quả của gdb là kết quả chính xác hơn, do đó, có vẻ như gdb sử dụng độ chính xác lớn hơn của FPU, trong khi g ++ có thể sử dụng lệnh SSE. –