फ़्लोटिंग-पॉइंट अंकगणितीय समस्या से निपटने का प्रयास करते समय मुझे थोड़ा उलझन में सामना करना पड़ा।जीडीबी सी ++ से अलग-अलग फ्लोटिंग-पॉइंट अंकगणित का मूल्यांकन क्यों करता है?
पहला, कोड। मैं इस उदाहरण में मेरी समस्या का सार आसुत है:
#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
), लेकिन फ्लोटिंग प्वाइंट roundoff त्रुटि के कारण वे नहीं है। वह हिस्सा मुझे मिलता है।
सवाल उठ गया जब मैंने इस कोड को (वास्तव में, मेरा वास्तविक कार्यक्रम) जीडीबी के माध्यम से विसंगति को ट्रैक करने के लिए चलाया। अगर मैं 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
आपको लगता है कि अगर मैं पूछना z.d * (1 - tau.d)
गणना करने के लिए GDB पर ध्यान देंगे, यह .16249854626123722 (0x3fc4ccc09aeb769a) देता है, जबकि वास्तविक सी ++ कोड जो प्रोग्राम में एक ही चीज़ की गणना करता है 0.16249854626123725 (0x3fc4ccc09aeb769b) देता है। तो जीडीबी फ्लोटिंग-पॉइंट अंकगणितीय के लिए एक अलग मूल्यांकन मॉडल का उपयोग करना चाहिए। क्या कोई इस पर कुछ और प्रकाश डाल सकता है? जीडीबी का मूल्यांकन मेरे प्रोसेसर के मूल्यांकन से अलग कैसे है?
मैंने this related question पर देखा था कि जीडीबी sqrt(3)
से 0 का मूल्यांकन करने के बारे में पूछ रहा है, लेकिन यह वही बात नहीं होनी चाहिए क्योंकि इसमें कोई फ़ंक्शन कॉल शामिल नहीं है।
दरअसल, जीडीबी का परिणाम गणितीय रूप से अधिक सही है, इसलिए ऐसा लगता है कि जीडीबी एफपीयू की बड़ी परिशुद्धता का उपयोग करता है, जबकि जी ++ शायद एसएसई निर्देशों का उपयोग करता है। –