फ्लोटिंग पॉइंट नंबरों की सापेक्ष तुलना


10

मेरे पास एक संख्यात्मक फ़ंक्शन है f(x, y)जो एक डबल फ़्लोटिंग पॉइंट नंबर लौटाता है जो किसी सूत्र को लागू करता है और मैं यह जांचना चाहता हूं कि यह मापदंडों के सभी संयोजन के लिए विश्लेषणात्मक अभिव्यक्तियों के खिलाफ सही है xऔर yमुझे इसमें दिलचस्पी है। गणना की तुलना करने का उचित तरीका क्या है। विश्लेषणात्मक अस्थायी बिंदु संख्या?

चलो का कहना है कि दोनों संख्याएं aऔर b। अब तक मैं यह सुनिश्चित कर रहा हूं कि निरपेक्ष ( abs(a-b) < eps) और रिश्तेदार ( abs(a-b)/max(abs(a), abs(b)) < eps) त्रुटियां ईपीएस से कम हों। इस तरह यह संख्या 1-20 के आस-पास के अंकों को कहे जाने पर भी संख्यात्मक अशुद्धियों को पकड़ लेगा।

हालाँकि, आज मुझे एक समस्या का पता चला, संख्यात्मक मूल्य aऔर विश्लेषणात्मक मूल्य bथे:

In [47]: a                                                                     
Out[47]: 5.9781943146790832e-322

In [48]: b                                                                     
Out[48]: 6.0276008792632078e-322

In [50]: abs(a-b)                                                              
Out[50]: 4.9406564584124654e-324

In [52]: abs(a-b) / max(a, b)                                                  
Out[52]: 0.0081967213114754103

तो पूर्ण त्रुटि [50] (स्पष्ट रूप से) छोटी है, लेकिन सापेक्ष त्रुटि [52] बड़ी है। इसलिए मैंने सोचा कि मेरे कार्यक्रम में एक बग है। डिबगिंग करके, मुझे एहसास हुआ, कि ये संख्याएं असामान्य हैं । इस तरह, मैंने उचित सापेक्ष तुलना करने के लिए निम्नलिखित दिनचर्या लिखी:

real(dp) elemental function rel_error(a, b) result(r)
real(dp), intent(in) :: a, b
real(dp) :: m, d
d = abs(a-b)
m = max(abs(a), abs(b))
if (d < tiny(1._dp)) then
    r = 0
else
    r = d / m
end if
end function

tiny(1._dp)मेरे कंप्यूटर पर 2.22507385850720138E-308 कहां से आया। अब सब कुछ काम करता है और मुझे सापेक्ष त्रुटि के रूप में 0 मिलता है और सब ठीक है। विशेष रूप से, उपरोक्त रिश्तेदार त्रुटि [५२] गलत है, यह केवल संख्याओं की अपर्याप्त सटीकता के कारण है। क्या rel_errorफंक्शन का मेरा कार्यान्वयन सही है? क्या मुझे बस यह देखना चाहिए कि abs(a-b)छोटे (= नाममात्र) से कम है, और 0 लौटाएं? या मुझे कुछ अन्य संयोजन की जांच करनी चाहिए, जैसे max(abs(a), abs(b))?

मैं सिर्फ यह जानना चाहूंगा कि "उचित" तरीका क्या है।

जवाबों:


11

आप सीधे का उपयोग कर denormals के लिए जाँच कर सकते हैं isnormal()से math.h(C99 या बाद में, POSIX.1 या बाद में)। फोरट्रान में, यदि मॉड्यूल ieee_arithmeticउपलब्ध है, तो आप उपयोग कर सकते हैं ieee_is_normal()। फ़ज़ी समानता के बारे में अधिक सटीक होने के लिए, आपको डॉर्मोर्ल्स के फ़्लोटिंग पॉइंट प्रतिनिधित्व पर विचार करना होगा और यह तय करना होगा कि परिणाम अच्छे होने के लिए आपका क्या मतलब है।

इस बिंदु पर, यह मानने के लिए कि या तो परिणाम सही है, आपको यह सुनिश्चित करना होगा कि आपने एक मध्यवर्ती चरण में बहुत अधिक अंक नहीं खोए हैं। Denormals के साथ कम्प्यूटिंग आमतौर पर अविश्वसनीय है और आंतरिक रूप से आपके एल्गोरिथ्म को पुनर्विक्रय होने से बचा जाना चाहिए। यह सुनिश्चित करने के लिए कि आपका आंतरिक स्केलिंग सफल था, मैं feenableexcept()फ़्लोटन में C99 या ieee_arithmeticमॉड्यूल के साथ फ्लोटिंग पॉइंट अपवादों को सक्रिय करने की सलाह देता हूं ।

यद्यपि आप अपने आवेदन को उस संकेत को पकड़ सकते हैं जो फ्लोटिंग पॉइंट अपवादों पर उठाया गया है, सभी कर्नेल मैंने हार्डवेयर फ्लैग को रीसेट करने का प्रयास किया है ताकि fetestexcept()उपयोगी परिणाम वापस न आए। जब साथ चलाया जाता है -fp_trap, तो PETSc प्रोग्राम एक फ्लोटिंग पॉइंट एरर उठाए जाने पर स्टैक ट्रेस को प्रिंट करेगा, लेकिन ऑफ़ेंडिंग लाइन की पहचान नहीं करेगा। यदि आप डिबगर में चलते हैं, तो डीबगर हार्डवेयर ध्वज को संरक्षित करता है और आपत्तिजनक अभिव्यक्ति पर टूट जाता है। आप fetestexceptडिबगर से कॉल करके सटीक कारण की जांच कर सकते हैं जहां परिणाम थोड़ा सा है या निम्न झंडे के (मान मशीन द्वारा भिन्न हो सकते हैं, देखें fenv.h; ये मान gl86c के साथ x86-64 के लिए हैं)।

  • FE_INVALID = 0x1
  • FE_DIVBYZERO = 0x4
  • FE_OVERFLOW = 0x8
  • FE_UNDERFLOW = 0x10
  • FE_INEXACT = 0x20

उत्कृष्ट उत्तर के लिए धन्यवाद। विषम अभिव्यक्ति के खिलाफ मैं जिस विश्लेषणात्मक अभिव्यक्ति की तुलना करता हूं वह exp(log_gamma(m+0.5_dp) - (m+0.5_dp)*log(t)) / 2एम = 234, टी = 2000 के लिए है। जैसे ही मैं बढ़ता हूं, यह जल्दी शून्य हो जाता है m। सभी मैं यह सुनिश्चित करना चाहता हूं कि मेरी संख्यात्मक दिनचर्या कम से कम 12 महत्वपूर्ण परीक्षाओं के लिए "सही" संख्या (शून्य को पूरी तरह से ठीक करने के लिए भी) लौटाए। इसलिए यदि गणना एक असामान्य संख्या देता है, तो यह बस शून्य है, और कोई समस्या नहीं होनी चाहिए। तो बस तुलनात्मक दिनचर्या को इसके खिलाफ मजबूत होना चाहिए।
ओडिन्ज íertík

5

डोनाल्ड नुथ के पास "द आर्ट ऑफ़ कंप्यूटर प्रोग्रामिंग" के वॉल्यूम 2 ​​"सेमिनुमेरिकल एल्गोरिदम" में एक फ्लोटिंग पॉइंट तुलना एल्गोरिथ्म का प्रस्ताव है। इसे C द्वारा Th में लागू किया गया था। बेल्डिंग ( fcmp पैकेज देखें ) और जीएसएल में उपलब्ध है ।


2
यहाँ मेरा फोरट्रान कार्यान्वयन है: gist.github.com/3776847 , ध्यान दें कि मुझे स्पष्ट रूप से इसमें असामान्य संख्याओं को संभालने की आवश्यकता है। अन्यथा मुझे लगता है कि यह सापेक्ष त्रुटि के बराबर है, केवल अंतर यह है कि ऐसा करने के बजाय abs(a-b)/max(a, b) < eps, हम करते हैं abs(a-b)/2**exponent(max(a, b)) < eps, जो बहुत अधिक मात्र में मंटिसा को छोड़ देता है max(a, b), इसलिए मेरी राय में यह अंतर नगण्य है।
ओंडे Oertík

5

वैकल्पिक रूप से गोल आकार वाले असमान संख्याओं में वास्तव में उच्च सापेक्ष त्रुटि हो सकती है। (फ्लशिंग यह कहते हुए कि शून्य करने के लिए अभी भी एक रिश्तेदार त्रुटि भ्रामक है।)

लेकिन शून्य के करीब, सापेक्ष क्षरण की गणना व्यर्थ है।

इसलिए, इससे पहले कि आप असंबद्ध संख्याओं तक पहुंचें, आपको संभवतः पूर्ण सटीकता पर स्विच करना चाहिए (अर्थात इस मामले में आप जो गारंटी देना चाहते हैं)।

इसलिए मैं एक सूत्र की वैधता की जाँच करके वास्तविक खिलाफ गणना किए गए का परीक्षण करने का सुझाव जैसे कि | relacc = 1e-12 और absacc = 1e-150 के साथ कहें।yx|yx|absacc+relaccmax(|x|,|y|)

तब आपके कोड के उपयोगकर्ता ठीक से जानते हैं कि उनके पास वास्तव में कितनी सटीकता है।


क्या आप सुनिश्चित हैं कि शून्य के करीब रिश्तेदार त्रुटियों की गणना करना व्यर्थ है? मुझे लगता है कि यह तभी निरर्थक है जब सटीकता की हानि (जो भी कारण हो)। यदि उदाहरण के लिए कुछ संख्यात्मक मुद्दों (जैसे दो बड़ी संख्याओं को घटाना) के कारण x <1e-150 के लिए सटीकता की हानि होती है, तो आप सही हैं। मेरे मामले में हालांकि संख्या शून्य से नीचे सभी तरह से सटीक प्रतीत होती है, सिवाय इसके कि जब यह असामान्य संख्या को हिट करे। तो मेरे मामले में absacc = 1e-320 या तो और मैं सिर्फ abs(a-b) < tiny(1._dp)ऊपर बताए अनुसार जाँच कर सकता हूँ।
ओंडे Oertík

@ Ond thatejČertík: उस स्थिति में 1e-150 को 1e-300 से बदल दें या जो कुछ भी आप सत्यापित कर सकते हैं। किसी भी मामले में शून्य के बहुत करीब से आप एक पूर्ण त्रुटि करते हैं, और आपके त्रुटि दावे को सापेक्ष त्रुटि को शून्य घोषित करने के बजाय इसे प्रतिबिंबित करना चाहिए।
अर्नोल्ड न्यूमैयर

समझा। मैं सत्यापित कर सकता हूं, कि सभी संख्याओं से अधिक के लिए काम करता है tiny(1._dp)=2.22507385850720138E-308(मैंने अपनी पिछली टिप्पणी में गलती की, यह 2e-308 है, न कि 1e-320)। तो यह मेरी पूर्ण त्रुटि है। फिर मुझे सापेक्ष त्रुटि की तुलना करने की आवश्यकता है। मैं आपकी बात देखता हूं, मुझे लगता है कि आप सही हैं। धन्यवाद!
ओडिन्ज íertík

1
@ Ond findejČertík: अनुपस्थित दी गई अतिरिक्त सापेक्ष त्रुटि का पता लगाने के लिए, अधिकतम की निगरानी करें । |yx|absaccmax(|x|,|y|)
अर्नोल्ड न्यूमैयर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.