2013-07-01 28 views
11

a_float == b_float जैसे कुछ फ़्लोटिंग पॉइंट नंबर की तुलना करना a_float/3.0 * 3.0 से परेशानी की तलाश में है क्योंकि a_float के विपरीत राउंड ऑफ त्रुटि के कारण नहीं हो सकता है।फ़्लोटिंग पॉइंट समानता और सहिष्णुता

कोई सामान्य रूप से fabs(a_float - b_float) < tol जैसा कुछ करता है।

tol की गणना कैसे करता है?

आदर्श रूप से सहिष्णुता कम से कम महत्वपूर्ण आंकड़ों में से एक या दो के मूल्य से बड़ी होनी चाहिए। तो यदि एकल परिशुद्धता फ़्लोटिंग पॉइंट नंबर tol = 10E-6 का उपयोग सही है, तो सही होना चाहिए। हालांकि यह सामान्य मामले के लिए अच्छा काम नहीं करता है जहां a_float बहुत छोटा हो सकता है या बहुत बड़ा हो सकता है।

सभी सामान्य मामलों के लिए tol सही तरीके से गणना कैसे करता है? मुझे विशेष रूप से सी या सी ++ मामलों में दिलचस्पी है।

+1

आप पढ़ी [इस] (http://en.wikibooks.org/wiki/Floating_Point/Epsilon)? – NINCOMPOOP

+0

यदि आप सही परिशुद्धता चाहते हैं, तो आप तर्कसंगत संख्या पुस्तकालयों में से एक का उपयोग कर सकते हैं। –

+3

प्रश्न: सभी सामान्य मामलों के लिए सही ढंग से 'tol' की गणना कैसे करता है? ए: एक नहीं करता है। इस तरह की तुलना सहिष्णुता मूल्य (और एफडब्ल्यूआईडब्ल्यू) के बावजूद सभी मामलों के लिए उपयुक्त नहीं है, * क्या आप * सबसे अच्छी तरह से जानते हैं कि आपके द्वारा परीक्षण की जाने वाली चीज़ * के लिए उचित सहिष्णुता क्या है?) –

उत्तर

15

इस ब्लॉग पोस्ट ताकि आप हमेशा अधिक पढ़ सकते हैं, इसके पीछे http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ यह भी एक श्रृंखला में से एक है एक उदाहरण है, काफी सरल कार्यान्वयन, और विस्तृत सिद्धांत शामिल हैं। संक्षेप में: अधिकांश संख्याओं के लिए यूएलपी का उपयोग करें, शून्य के पास संख्याओं के लिए ईपीएसलॉन का उपयोग करें, लेकिन अभी भी चेतावनी हैं। यदि आप अपने फ़्लोटिंग पॉइंट गणित के बारे में सुनिश्चित होना चाहते हैं तो मैं पूरी श्रृंखला पढ़ने की सलाह देता हूं।

+0

डाउनवोट के कारण? – aryjczyk

+0

यह एक अच्छा लेख है - एक डाउनवोट से सहमत न हों। – chux

+2

जबकि सटीक फ्लोट तुलना * आमतौर पर * परेशानी की तलाश में होती है, यह हमेशा मामला नहीं है। ऐसे समय होते हैं जब सटीक तुलना से कम कुछ भी कमजोर होता है, जैसा कि मैं यहां दस्तावेज़ करता हूं: https://randomascii.wordpress.com/2014/01/27/theres-only-four-billion-floatsso-test-them-all/ यह सब संदर्भ पर निर्भर करता है। दूसरे शब्दों में, कभी-कभी 'tol' के लिए सही मान शून्य होता है। –

9

जहाँ तक मुझे पता है, कोई नहीं करता है।

कोई सामान्य "सही उत्तर" नहीं है, क्योंकि यह परिशुद्धता के लिए आवेदन की आवश्यकता पर निर्भर कर सकता है।

उदाहरण के लिए, स्क्रीन-पिक्सेल में काम करने वाला 2 डी भौतिकी सिमुलेशन यह तय कर सकता है कि पिक्सेल का 1/4 पर्याप्त अच्छा है, जबकि 3 डी सीएडी सिस्टम परमाणु संयंत्र आंतरिक डिजाइन करने के लिए उपयोग किया जाता है।

मैं प्रोग्राम से इसे बाहर से तय करने का कोई तरीका नहीं देख सकता।

+0

मैं यथासंभव यथासंभव सटीकता चाहता हूं। गोलाकार त्रुटि की अनुमति देने के लिए भंडारण प्रकार शून्य से एक या दो के लिए महत्वपूर्ण अंकों की पूर्ण संख्या है। – doron

+0

यदि आप उस पर किए गए सटीक परिचालनों को नहीं जानते हैं तो फ़्लोटिंग पॉइंट त्रुटि बाध्य नहीं है। यदि आपके पास 'a == 3e10000' है और आप' 1' 100000 समय घटाते हैं तो आपको 'a == 2 ...' नहीं मिल सकता है। – urzeit

+2

@urzeit मुझे यकीन है कि फ्लोटिंग-पॉइंट त्रुटि के बावजूद '3e10000 - 100000'' 2' नहीं है। –

-2

जब मैं तैरता तुलना करने की आवश्यकता है, मैं की तरह जाल, जाल और खामियों की दुनिया को यह

bool same(double a, double b, double error) { 
    double x; 
    if(a == 0) { 
     x = b; 
    } else if(b == 0) { 
     x = a; 
    } else { 
     x = (a-b)/a; 
    } 
    return fabs(x) < error; 
} 
3

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

fabs(a_float - b_float) < tol में संक्षिप्त ओपी का उल्लेख है: "सामान्य मामले के लिए अच्छा काम नहीं करता है जहां एफ्लोट बहुत छोटा हो सकता है या बहुत बड़ा हो सकता है।" fabs(a_float - ref_float) <= fabs(ref_float * tol) संस्करण के साथ copes बहुत बेहतर है।

ओ पी के "एकल परिशुद्धता चल बिन्दु संख्या उपयोग सहने = 10E-6" ++ इतनी आसानी से double को float गणित को बढ़ावा देने के सी और सी के लिए थोड़ा चिंताजनक है और फिर इसे double, नहीं float की "सहनशीलता" है, कि में आता है प्ले। float f = 1.0; printf("%.20f\n", f/7.0); पर विचार करें बहुत से नए प्रोग्रामर यह नहीं समझते कि 7.0 ने double सटीक गणना की है। double का उपयोग करके अपने कोड को छोड़कर सिफारिश करें, जहां बड़ी मात्रा में डेटा float छोटे आकार की आवश्यकता है।

सी 99 nextafter() प्रदान करता है जो "सहिष्णुता" को मापने में मदद करने में उपयोगी हो सकता है। इसका उपयोग करके, कोई अगली प्रतिनिधित्व योग्य संख्या निर्धारित कर सकता है। यह ओपी के साथ मदद करेगा "...भंडारण प्रकार शून्य से एक के लिए महत्वपूर्ण अंक ... से भरा संख्या roundoff त्रुटि के लिए अनुमति देने के लिए। "if ((nextafter(x, -INF) <= y && (y <= nextafter(x, +INF))) ...

तरह tol की या" सहिष्णुता "का इस्तेमाल किया अक्सर बात की जड़ है। अक्सर (IMHO) एक रिश्तेदार सहिष्णुता महत्वपूर्ण है। उदाहरण के लिए? कभी-कभी कोई पूर्ण सहिष्णुता की जरूरत है "एक्स और 0.0001% के भीतर y हैं"। जैसे?

सहिष्णुता की मूल्य "एक्स और 0.0001 के भीतर y हैं" अक्सर सर्वोत्तम मूल्य के लिए बहस योग्य होता है अक्सर स्थिति निर्भर होती है। 0.01 के भीतर तुलना करना काम कर सकता है डॉलर के लिए एक वित्तीय आवेदन के लिए लेकिन येन नहीं। (संकेत:। एक कोडन शैली है कि आसान अद्यतन की अनुमति देता है का उपयोग सुनिश्चित करें)

5

सी हेडर फाइल <float.h> और आप स्थिरांक देता FLT_EPSILONDBL_EPSILON है, जो 1.0 और सबसे छोटी संख्या 1.0 की तुलना में बड़ा अंतर है कि यदि एक नाव/डबल प्रतिनिधित्व कर सकते हैं। आपको लगता है कि माप सकते हैं अपनी संख्या के आकार और गोलाई त्रुटि से आप को सहन करने की इच्छा:

#include <float.h> 
#ifndef DBL_TRUE_MIN 
/* DBL_TRUE_MIN is a common non-standard extension for the minimum denorm value 
* DBL_MIN is the minimum non-denorm value -- use that if TRUE_MIN is not defined */ 
#define DBL_TRUE_MIN DBL_MIN 
#endif 

/* return the difference between |x| and the next larger representable double */ 
double dbl_epsilon(double x) { 
    int exp; 
    if (frexp(x, &exp) == 0.0) 
     return DBL_TRUE_MIN; 
    return ldexp(DBL_EPSILON, exp-1); 
} 
+0

यह तकनीक ठोस है, हालांकि यह शून्य के आसपास संख्याओं के लिए विफल रहता है। यह एक मौलिक समस्या है क्योंकि सापेक्ष त्रुटियां शून्य पर व्यर्थ हैं। उदाहरण के लिए पाप (एमएफआई) 'शून्य होना चाहिए' लेकिन नहीं है। सापेक्ष त्रुटि अनंत है। विवरण के लिए यह आलेख देखें: http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ –

0

हालांकि सहिष्णुता के मूल्य स्थिति पर निर्भर करता है, तो आप देख रहे हैं सटीक comparasion के लिए आप सहिष्णुता के रूप में इस्तेमाल कर सकता है मशीन ईपीएसलॉन मान, न्यूमेरिक_लिमिट्स :: ईपीएसलॉन() (लाइब्रेरी सीमाएं)। फ़ंक्शन 1 के बीच का अंतर देता है और डेटा प्रकार के लिए प्रतिनिधित्व करने योग्य 1 से अधिक का सबसे छोटा मान देता है। http://msdn.microsoft.com/en-us/library/6x7575x3.aspx

यदि आप फ्लोट या युगल की तुलना कर रहे हैं तो ईपीएसलॉन का मूल्य अलग-अलग होता है। उदाहरण के लिए, मेरे कंप्यूटर में, यदि फ्लोट की तुलना में ईपीएसलॉन का मान 1.1 9 20 9 2 9-007 है और यदि युगल की तुलना ईपीएसलॉन का मान 2.2204460492503131e-016 है।

एक्स और वाई के बीच एक सापेक्ष तुलना के लिए, एक्स और वाई के अधिकतम पूर्ण मूल्य से ईपीएसलॉन गुणा करें।

उपरोक्त परिणाम उलप्स (अंतिम स्थान पर इकाइयों) द्वारा गुणा किया जा सकता है जो आपको परिशुद्धता के साथ खेलने की अनुमति देता है।

#include <iostream> 
#include <cmath> 
#include <limits> 

template<class T> bool are_almost_equal(T x, T y, int ulp) 
{ 
    if(std::abs(x-y) <= std::numeric_limits<T>::epsilon() * std::max(std::abs(x), std::abs(y)) * ulp){ 
     return true; 
    }else{ 
     return false; 
    }   
} 
+0

यह पिछले उत्तर का डुप्लिकेट है। –

+0

मैंने थोड़ा सा जानकारी और कोड जोड़ा @brusDawson – MartaF

+0

'if (cond) सत्य को लिखना अनावश्यक है; और झूठी वापसी '। आप 'रिटर्न कंड' क्यों नहीं लिखते? – 0xbadf00d

1

गोल करने की त्रुटि संचालन के लिए उपयोग किए गए मानों के अनुसार भिन्न होती है।

एक निश्चित सहिष्णुता के बजाय

, तो आप शायद की तरह एप्सिलॉन का एक पहलू का उपयोग कर सकते हैं:

bool nearly_equal(double a, double b, int factor /* a factor of epsilon */) 
{ 
    double min_a = a - (a - std::nextafter(a, std::numeric_limits<double>::lowest())) * factor; 
    double max_a = a + (std::nextafter(a, std::numeric_limits<double>::max()) - a) * factor; 

    return min_a <= b && max_a >= b; 
} 
+0

मुझे लगता है कि अवधारणा का एक अच्छा सामान्यीकरण यह होगा कि "लगभग बराबर" व्यक्तिपरक है: लगभग दूसरे ऑपरेटर/ऑपरेशन के संबंध में लगभग बराबर। आखिरकार, ईपीएसलॉन का उपयोग निकटता, विपरीत दूरी से वर्गीकृत करने के लिए किया जाता है, और आपको 'दूरी' के लिए एक मीट्रिक परिभाषित करने के साथ-साथ 'उलटा' को परिभाषित/परिभाषित करने की आवश्यकता होती है। यदि ईपीएसलॉन "हैंड-वेविंग" है तो संदर्भ के बिना ईपीएसलॉन सीधे जेदी मस्तिष्क की चाल है। –

संबंधित मुद्दे