2008-08-21 9 views
9

समानता के लिए आईईईई फ्लोट और युगल की तुलना करने के लिए सबसे अच्छी विधि क्या है? मैंने कई तरीकों के बारे में सुना है, लेकिन मैं देखना चाहता था कि समुदाय ने क्या सोचा था।समानता के लिए आईईईई फ्लोट और युगल की तुलना

+0

चेकआउट इस [जवाब] (http://stackoverflow.com/questions/17333/most-effective-way-for-float-and-double-comparison#17467) एक ऐसी ही सवाल का। – grom

उत्तर

7

मुझे लगता है कि सबसे अच्छा तरीका ULPs की तुलना करना है।

bool is_nan(float f) 
{ 
    return (*reinterpret_cast<unsigned __int32*>(&f) & 0x7f800000) == 0x7f800000 && (*reinterpret_cast<unsigned __int32*>(&f) & 0x007fffff) != 0; 
} 

bool is_finite(float f) 
{ 
    return (*reinterpret_cast<unsigned __int32*>(&f) & 0x7f800000) != 0x7f800000; 
} 

// if this symbol is defined, NaNs are never equal to anything (as is normal in IEEE floating point) 
// if this symbol is not defined, NaNs are hugely different from regular numbers, but might be equal to each other 
#define UNEQUAL_NANS 1 
// if this symbol is defined, infinites are never equal to finite numbers (as they're unimaginably greater) 
// if this symbol is not defined, infinities are 1 ULP away from +/- FLT_MAX 
#define INFINITE_INFINITIES 1 

// test whether two IEEE floats are within a specified number of representable values of each other 
// This depends on the fact that IEEE floats are properly ordered when treated as signed magnitude integers 
bool equal_float(float lhs, float rhs, unsigned __int32 max_ulp_difference) 
{ 
#ifdef UNEQUAL_NANS 
    if(is_nan(lhs) || is_nan(rhs)) 
    { 
     return false; 
    } 
#endif 
#ifdef INFINITE_INFINITIES 
    if((is_finite(lhs) && !is_finite(rhs)) || (!is_finite(lhs) && is_finite(rhs))) 
    { 
     return false; 
    } 
#endif 
    signed __int32 left(*reinterpret_cast<signed __int32*>(&lhs)); 
    // transform signed magnitude ints into 2s complement signed ints 
    if(left < 0) 
    { 
     left = 0x80000000 - left; 
    } 
    signed __int32 right(*reinterpret_cast<signed __int32*>(&rhs)); 
    // transform signed magnitude ints into 2s complement signed ints 
    if(right < 0) 
    { 
     right = 0x80000000 - right; 
    } 
    if(static_cast<unsigned __int32>(std::abs(left - right)) <= max_ulp_difference) 
    { 
     return true; 
    } 
    return false; 
} 

एक समान तकनीक का उपयोग युगल के लिए किया जा सकता है। यह चाल फ्लोट को कन्वर्ट करना है ताकि उन्हें ऑर्डर किया जा सके (जैसे कि पूर्णांक) और फिर देखें कि वे कितने अलग हैं।

मुझे नहीं पता कि यह डरावनी चीज मेरे अंडरस्कोर को खराब क्यों कर रही है। संपादित करें: ओह, शायद यह सिर्फ पूर्वावलोकन का एक आर्टेफैक्ट है। यह ठीक है तो।

+0

यह परिशुद्धता के लिए हाथ से नीचे जीतता है। लेकिन प्रदर्शन के लिए ... आपको गति सुधार के लिए उस सटीकता का थोड़ा सा व्यापार करना होगा। माना? –

+1

यदि आपको युगल या पोर्टेबिलिटी की आवश्यकता है: मुझे इस बारे में एक महान क्रॉस-प्लेटफ़ॉर्म कार्यान्वयन मिला है जो Google टेस्ट में युगल और फ्लोट दोनों से निपट सकता है और इसे यहां पोस्ट किया गया है: http://stackoverflow.com/questions/17333/most-effective- रास्ता-के-फ्लोट-एंड-डबल-तुलना/3423299 # 3423299 – skrebbel

0

ओह प्रिय भगवान कृपया जब तक आप पी 6 या उससे पहले नहीं चल रहे हों, तब तक फ्लैट बिट्स को इंट्स के रूप में न समझें।

0

ओह प्रिय भगवान कृपया जब तक आप पी 6 या उससे पहले नहीं चल रहे हों, तब तक फ्लैट बिट्स को इंट्स के रूप में न समझें।

यहां तक ​​कि अगर यह वेक्टर से कॉपी करने के लिए यह कारण बनता है स्मृति के माध्यम से रजिस्टर पूर्णांक पंजीकरण करता है, और यहां तक ​​कि अगर यह पाइपलाइन रुक जाता है, यह यह करने के लिए है कि मैं का सामना करना पड़ा सबसे अच्छा तरीका है, जहां तक ​​यह सबसे प्रदान करता है फ्लोटिंग पॉइंट त्रुटियों के चेहरे में भी मजबूत तुलना।

यानी यह भुगतान करने योग्य मूल्य है।

+0

मुझे संदेह है कि '(ए == बी || (ए! = ए एंड बी बी! = बी))' कई प्रोसेसर पर फ्लोट से जुड़े किसी भी चीज़ से तेज़ होगा -बिट-टू-इंट कास्ट, हालांकि यह वास्तव में मुझे पीड़ा देता है कि उपर्युक्त की तरह अभिव्यक्ति की आवश्यकता है। मुझे आश्चर्य है कि नैन! = NaN निर्णय कितना लाभ उठाता है, और बर्बाद कोड और डिबगिंग समय में कितना खर्च होता है? – supercat

3

वर्तमान संस्करण मैं उपयोग कर रहा हूँ इस

bool is_equals(float A, float B, 
       float maxRelativeError, float maxAbsoluteError) 
{ 

    if (fabs(A - B) < maxAbsoluteError) 
    return true; 

    float relativeError; 
    if (fabs(B) > fabs(A)) 
    relativeError = fabs((A - B)/B); 
    else 
    relativeError = fabs((A - B)/A); 

    if (relativeError <= maxRelativeError) 
    return true; 

    return false; 
} 

यह सापेक्ष और निरपेक्ष त्रुटि सहिष्णुता के संयोजन से सबसे समस्याओं की देखभाल करने के लिए लगता है। क्या यूएलपी दृष्टिकोण बेहतर है? यदि हां, तो क्यों?

0

यह ऐसा करने का सबसे अच्छा तरीका है जो मैंने पार किया है, क्योंकि यह फ्लोटिंग पॉइंट त्रुटियों के मुकाबले सबसे मजबूत तुलना प्रदान करता है।

यदि आपके पास फ्लोटिंग पॉइंट त्रुटियां हैं तो आपको इससे भी अधिक समस्याएं हैं। हालांकि मुझे लगता है कि व्यक्तिगत परिप्रेक्ष्य पर निर्भर है।

+1

आपको हमेशा फ़्लोटिंग पॉइंट त्रुटियां होंगी। – BCS

0

यह सापेक्ष और पूर्ण त्रुटि सहनशीलता के संयोजन से अधिकांश समस्याओं का ख्याल रखना प्रतीत होता है। क्या यूएलपी दृष्टिकोण बेहतर है? यदि हां, तो क्यों?

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

0

यदि आपके पास फ्लोटिंग पॉइंट त्रुटियां हैं तो आपको इससे भी अधिक समस्याएं हैं। हालांकि मुझे लगता है कि व्यक्तिगत परिप्रेक्ष्य पर निर्भर है। (हम क्योंकि

यहां तक ​​कि अगर हम त्रुटि के संचय को कम करने के संख्यात्मक विश्लेषण करते हैं, हम इसे खत्म नहीं कर सकते हैं और हम परिणाम के साथ छोड़ा जा सकता है कि समान होना चाहिए (यदि हम reals के साथ की गणना कर रहे थे), लेकिन अलग-अलग असली के साथ गणना नहीं कर सकते हैं)।

0

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

+0

(लगभग) समानता से निपटने के लिए लूपों में एक आम मामला है जहां आप चीजों को "पर्याप्त पास" करते समय रोकना चाहते हैं, लेकिन जहां आप उन्हें कभी भी अभिसरण करने की उम्मीद नहीं करते हैं। – BCS

0

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

शायद हम इस तरह के दृष्टिकोण को लेकर सीमा या प्रदर्शन के नुकसान का जोखिम नहीं उठा सकते हैं।

0

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

शायद मुझे समस्या को बेहतर समझा जाना चाहिए। सी ++ में, निम्नलिखित कोड:

#include <iostream> 

using namespace std; 


int main() 
{ 
    float a = 1.0; 
    float b = 0.0; 

    for(int i=0;i<10;++i) 
    { 
    b+=0.1; 
    } 

    if(a != b) 
    { 
    cout << "Something is wrong" << endl; 
    } 

    return 1; 
} 

वाक्यांश "कुछ गलत है" प्रिंट करता है। क्या आप कह रहे हैं कि इसे चाहिए?

+0

फ़्लोटिंग पॉइंट सटीकता और गोल करने वाली त्रुटियों के कारण आप लगभग हमेशा एक = = बी प्राप्त करेंगे। –

0

@DrPizza: मैं कोई प्रदर्शन गुरु नहीं हूं लेकिन मैं निश्चित बिंदु संचालन फ्लोटिंग पॉइंट ऑपरेशंस (ज्यादातर मामलों में) से तेज होने की अपेक्षा करता हूं।

@ क्रेग एच: निश्चित। मैं इसे प्रिंट करने के साथ पूरी तरह से ठीक हूँ। यदि कोई या बी स्टोर स्टोर करता है तो उन्हें निश्चित बिंदु में प्रदर्शित किया जाना चाहिए। मैं एक असली दुनिया के उदाहरण के बारे में सोचने के लिए संघर्ष कर रहा हूं जहां इस तरह के तर्क को तैरने के लिए संबद्ध होना चाहिए। तैरता के लिए उपयुक्त बातें:

  • वजन
  • रैंकों
  • दूरी (एक एडीसी से की तरह)
  • असली दुनिया मूल्यों

इन सब बातों के लिए, या तो आप ज्यादा तो नंबर और बस मानव व्याख्या के लिए उपयोगकर्ता को परिणाम प्रस्तुत करें, या आप एक तुलनात्मक बयान देते हैं (भले ही ऐसा कथन है, "यह बात इस अन्य चीज़ के 0.001 के भीतर है")। मेरा जैसे तुलनात्मक बयान एल्गोरिदम के संदर्भ में केवल उपयोगी है: "0.001 के भीतर" भाग भौतिक प्रश्न पर निर्भर करता है जो आप पूछ रहे हैं। वह मेरा 0.02। या मुझे 2/100 वें कहना चाहिए?

1

@DrPizza: मैं कोई प्रदर्शन गुरु नहीं हूं लेकिन मैं निश्चित बिंदु संचालन फ्लोटिंग पॉइंट ऑपरेशंस (ज्यादातर मामलों में) से तेज होने की अपेक्षा करता हूं।

यह इस बात पर निर्भर करता है कि आप उनके साथ क्या कर रहे हैं। एक आईईईई फ्लोट के समान सीमा वाला एक निश्चित बिंदु प्रकार कई बार धीमा (और कई बार बड़ा) होगा।

तैरता के लिए उपयुक्त बातें:

3 डी ग्राफिक्स, भौतिकी/इंजीनियरिंग, सिमुलेशन, जलवायु सिमुलेशन ....

0

यह इस बात पर निर्भर करता है कि आप उनके साथ क्या कर रहे हैं। आईईईई फ्लोट के समान सीमा के साथ एक निश्चित-बिंदु प्रकार कई बार धीमा (और कई बार बड़ा) होगा।

ठीक है, लेकिन अगर मैं infinitesimally छोटे बिट-रिज़ॉल्यूशन चाहता हूं तो यह मेरे मूल बिंदु पर वापस आ गया है: == और! = इस तरह की समस्या के संदर्भ में कोई मतलब नहीं है।

एक int मुझे ~ 10^9 मानों (सीमा के बावजूद) व्यक्त करने देता है जो किसी भी परिस्थिति के लिए पर्याप्त लगता है जहां मैं उनमें से दो के बराबर होने की परवाह करता हूं। और यदि यह पर्याप्त नहीं है, तो 64-बिट ओएस का उपयोग करें और आपके पास लगभग 10^1 9 विशिष्ट मान हैं।

मैं मूल्यों को 0 से 10^200 (उदाहरण के लिए) में एक int में व्यक्त कर सकता हूं, यह केवल थोड़ा-रिज़ॉल्यूशन है जो पीड़ित है (संकल्प 1 से बड़ा होगा, लेकिन फिर, कोई भी एप्लीकेशन उस तरह का नहीं है रेंज के साथ ही उस तरह के संकल्प)।

संक्षेप में, मुझे लगता है कि सभी मामलों में एक या तो मूल्यों की निरंतरता का प्रतिनिधित्व कर रहा है, इस मामले में! = और == अप्रासंगिक हैं, या कोई मानों के एक निश्चित सेट का प्रतिनिधित्व कर रहा है, जिसे एक int (या एक और निश्चित सटीक प्रकार)।

0

एक पूर्णांक मुझे (चाहे रेंज के) जो किसी भी स्थिति है जहाँ मैं उन्हें जा रहा है बराबर का लगभग दो चाहेंगे के लिए पर्याप्त तरह लगता है व्यक्त ~ 10^9 मूल्यों सुविधा देता है। और यदि यह पर्याप्त नहीं है, तो 64-बिट ओएस का उपयोग करें और आपके पास लगभग 10^1 9 विशिष्ट मान हैं।

मैंने वास्तव में उस सीमा को मारा है ... मैं एक सिमुलेशन में घड़ी चक्रों में पीएस और समय में समय उलझाने की कोशिश कर रहा था जहां आप आसानी से 10^10 चक्रों को मारा। कोई फर्क नहीं पड़ता कि मैंने क्या किया है, मैंने 64-बिट पूर्णांक की दंडनीय सीमा को बहुत जल्दी से भर दिया ... 10^1 जितना आप सोचते हैं उतना नहीं है, अब 128 बिट्स कंप्यूटिंग करें!

फ़्लोट्स ने मुझे गणितीय मुद्दों का समाधान प्राप्त करने की अनुमति दी, क्योंकि मूल्य कम अंत में बहुत शून्य से बहते हैं। इसलिए मूल रूप से सटीक रूप से कोई नुकसान नहीं होने के कारण संख्या में एक दशमलव बिंदु फ्लोटिंग अरुण था (मैं 64-बिट int की तुलना में फ्लोट के मंटिसा में अनुमत मूल्यों की सीमित सीमित संख्या के साथ पसंद कर सकता था, लेकिन बेहद जरूरी था कि सीमा!)।

और फिर चीजों की तुलना करने के लिए आदि

कष्टप्रद पूर्णांकों को वापस परिवर्तित, और अंत में मैं पूरी प्रयास खत्म कर दिया और बस तैरता और < और> काम किया जाना पर भरोसा किया। सही नहीं है, लेकिन उपयोग के मामले के लिए काम करता है।

1

संख्यात्मक सॉफ़्टवेयर में आप अक्सर परीक्षण करना चाहते हैं कि दो फ़्लोटिंग पॉइंट नंबर बिल्कुल बराबर हैं। LAPACK ऐसे मामलों के उदाहरणों से भरा है। बेशक, सबसे आम मामला यह है कि आप यह जांचना चाहते हैं कि फ़्लोटिंग पॉइंट नंबर "शून्य", "वन", "टू", "हाफ" के बराबर है या नहीं। यदि कोई दिलचस्पी लेता है तो मैं कुछ एल्गोरिदम चुन सकता हूं और विस्तार से अधिक जा सकता हूं।

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

  • y = बीटा * y + अल्फा के संचालन की गणना कर सकता * एक * x
  • y = बीटा * y + अल्फा * एक^टी * x
  • y = बीटा * वाई + अल्फा * ए^एच * एक्स

तो यदि बीटा बराबर है तो आपके पास "प्लस असाइनमेंट" है और बीटा के लिए ज़ीरो को "सरल असाइनमेंट" के बराबर बराबर किया जाता है। इसलिए यदि आप इन (सामान्य) मामलों को एक विशेष उपचार देते हैं तो आप निश्चित रूप से कम्प्यूटेशनल लागत में कटौती कर सकते हैं।

निश्चित रूप से, आप बीएलएएस दिनचर्या को इस तरह से डिजाइन कर सकते हैं कि आप सटीक तुलना (उदाहरण के लिए कुछ झंडे का उपयोग कर सकते हैं) से बच सकते हैं। हालांकि, LAPACK उन उदाहरणों से भरा है जहां यह संभव नहीं है।

पी.एस .:

  • निश्चित रूप से कई मामलों जहां जाँच "बिल्कुल बराबर है" के लिए नहीं करना चाहते हैं। कई लोगों के लिए यह एकमात्र मामला भी हो सकता है जिसे उन्हें कभी निपटना पड़ता है। मैं बस यह इंगित करना चाहता हूं कि अन्य मामले भी हैं।

  • हालांकि लापैक फोरट्रान में लिखा गया है, तो तर्क समान है यदि आप संख्यात्मक सॉफ्टवेयर के लिए अन्य प्रोग्रामिंग भाषाओं का उपयोग कर रहे हैं।

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