पायथन में लगभग-समानता के लिए फ़्लोट्स की तुलना करने का सबसे अच्छा तरीका क्या है?


331

यह सर्वविदित है कि समानता के लिए फ्लोट्स की तुलना करना गोल और सटीक मुद्दों के कारण थोड़ा फीका है।

उदाहरण के लिए: https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/

पायथन में इससे निपटने के लिए अनुशंसित तरीका क्या है?

निश्चित रूप से इसके लिए कहीं एक मानक पुस्तकालय समारोह है?


@tolomea: चूँकि यह आपके एप्लिकेशन और आपके डेटा और आपके समस्या डोमेन पर निर्भर करता है - और यह कोड की केवल एक पंक्ति है - "मानक लाइब्रेरी फ़ंक्शन" क्यों होगा?
S.Lott

9
@ S.Lott: all, any, max, minप्रत्येक मूल रूप से एक-लाइनर्स हैं, और वे सिर्फ एक पुस्तकालय में उपलब्ध नहीं कराया जाता है, वे कार्यों में निर्मित कर रहे हैं। तो BDFL के कारण यह नहीं हैं। अधिकांश लोगों द्वारा लिखे जाने वाले कोड की एक पंक्ति बहुत ही अपरिष्कृत है और अक्सर काम नहीं करती है, जो कुछ बेहतर प्रदान करने का एक मजबूत कारण है। बेशक किसी भी अन्य रणनीति प्रदान करने वाले मॉड्यूल को भी वर्णन करना होगा कि वे कब उपयुक्त हैं, और अधिक महत्वपूर्ण बात यह है कि जब वे नहीं हैं। संख्यात्मक विश्लेषण कठिन है, यह कोई बहुत बड़ा अपमान नहीं है कि भाषा डिजाइनर आमतौर पर इसके साथ मदद करने के लिए उपकरणों का प्रयास नहीं करते हैं।
स्टीव जेसोप

@ जेसपॉप। उन संग्रह-उन्मुख कार्यों में आवेदन, डेटा और समस्या डोमेन निर्भरता नहीं है जो फ्लोट-पॉइंट करता है। तो "वन-लाइनर" स्पष्ट रूप से वास्तविक कारणों जितना महत्वपूर्ण नहीं है। न्यूमेरिक विश्लेषण कठिन है, और सामान्य-प्रयोजन भाषा पुस्तकालय का प्रथम श्रेणी का हिस्सा नहीं हो सकता है।
S.Lott

6
@ S.Lott: मैं शायद सहमत हूँ अगर मानक पायथन वितरण XML इंटरफेस के लिए कई मॉड्यूल के साथ नहीं आया । स्पष्ट रूप से तथ्य यह है कि अलग-अलग अनुप्रयोगों को कुछ अलग करने की आवश्यकता होती है, यह एक या दूसरे तरीके से करने के लिए आधार सेट में मॉड्यूल लगाने के लिए बिल्कुल भी कोई पट्टी नहीं है। निश्चित रूप से फ़्लोट्स की तुलना करने के लिए तरकीबें हैं जो फिर से उपयोग की जाती हैं, सबसे बुनियादी एक निर्दिष्ट संख्या में अल्सर है। इसलिए मैं केवल आंशिक रूप से सहमत हूं - समस्या यह है कि संख्यात्मक विश्लेषण कठिन है। पायथन सिद्धांत रूप में कुछ आसान बनाने के लिए उपकरण प्रदान कर सकता है, कुछ समय के लिए। मुझे लगता है कि किसी ने स्वेच्छा से नहीं किया है।
स्टीव जेसोप Steve

4
इसके अलावा, "यह कोड की एक हार्ड-टू-डिज़ाइन लाइन को उबालता है" - यदि यह अभी भी एक-लाइनर है, तो एक बार इसे ठीक से करने के बाद, मुझे लगता है कि आपका मॉनिटर मेरा ;-) से अधिक व्यापक है। वैसे भी, मुझे लगता है कि पूरा क्षेत्र काफी विशिष्ट है, इस अर्थ में कि अधिकांश प्रोग्रामर (मेरे सहित) बहुत कम ही इसका उपयोग करते हैं। कठिन होने के साथ संयुक्त, यह अधिकांश भाषाओं में कोर पुस्तकालयों के लिए "सबसे अधिक वांछित" सूची में शीर्ष पर नहीं जा रहा है।
स्टीव जेसोप Steve

जवाबों:


323

Python 3.5 PEP 485 में वर्णित कार्यों math.iscloseऔर cmath.iscloseकार्यों को जोड़ता है ।

यदि आप पायथन के पुराने संस्करण का उपयोग कर रहे हैं, तो दस्तावेज़ में समकक्ष फ़ंक्शन दिया गया है ।

def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
    return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)

rel_tolएक रिश्तेदार सहिष्णुता है, यह दो तर्कों के परिमाण से कई गुना अधिक है; जैसे-जैसे मूल्य बड़े होते जाते हैं, वैसे-वैसे उन्हें बराबर समझते हुए भी उनके बीच अनुमत अंतर बढ़ता है।

abs_tolएक पूर्ण सहिष्णुता है जिसे सभी मामलों में लागू किया जाता है। यदि अंतर उन सभी सहिष्णुताओं से कम है, तो मूल्यों को समान माना जाता है।


26
ध्यान दें कि जब aया bएक है numpy array, numpy.iscloseकाम करता है।
dbliss

6
@ मार्श rel_tolएक रिश्तेदार सहिष्णुता है , यह दो तर्कों के परिमाण से कई गुना अधिक है; जैसे-जैसे मूल्य बड़े होते जाते हैं, वैसे-वैसे उन्हें बराबर समझते हुए भी उनके बीच अनुमत अंतर बढ़ता है। abs_tolएक पूर्ण सहिष्णुता है जिसे सभी मामलों में लागू किया जाता है। यदि अंतर उन सभी सहिष्णुताओं से कम है, तो मूल्यों को समान माना जाता है।
मार्क रैनसम

5
इस उत्तर के मूल्य को कम करने के लिए नहीं (मुझे लगता है कि यह एक अच्छा है), यह ध्यान देने योग्य है कि प्रलेखन यह भी कहता है: "मोडुलो त्रुटि जाँच, आदि, फ़ंक्शन का परिणाम वापस आ जाएगा ..." दूसरे शब्दों में, iscloseफ़ंक्शन (ऊपर) पूर्ण कार्यान्वयन नहीं है ।
राकेश १४'१६

5
एक पुराने धागे को पुनर्जीवित करने के लिए माफी, लेकिन यह इंगित करने के लायक था कि iscloseहमेशा कम रूढ़िवादी मानदंड का पालन ​​करता है । मैं केवल इसका उल्लेख करता हूं क्योंकि यह व्यवहार मेरे लिए प्रतिगामी है। क्या मैं दो मानदंड निर्दिष्ट करने के लिए था, मैं हमेशा बड़ी सहिष्णुता के लिए छोटे सहिष्णुता की अपेक्षा करूंगा।
मैकी मेसर

3
@MackieMesser आप निश्चित रूप से आपकी राय के हकदार हैं, लेकिन इस व्यवहार ने मेरे लिए सही अर्थ बनाया। आपकी परिभाषा से कुछ भी कभी भी "शून्य के करीब" नहीं हो सकता है, क्योंकि शून्य से गुणा एक रिश्तेदार सहिष्णुता हमेशा शून्य होती है।
मार्क रैनसम

71

निम्नलिखित के रूप में सरल रूप में कुछ अच्छा पर्याप्त नहीं है?

return abs(f1 - f2) <= allowed_error

8
जैसा कि मैंने लिंक प्रदान किया है, घटाना केवल तभी काम करता है जब आप संख्याओं के अनुमानित परिमाण को पहले से जानते हों।
गॉर्डन Wrigley

8
मेरे अनुभव में, तैरता की तुलना के लिए सबसे अच्छा तरीका है: abs(f1-f2) < tol*max(abs(f1),abs(f2))। इस तरह की सापेक्ष सहिष्णुता सामान्य रूप से फ़्लोट्स की तुलना करने का एकमात्र सार्थक तरीका है, क्योंकि वे आमतौर पर छोटे दशमलव स्थानों में राउंडऑफ़ त्रुटि से प्रभावित होते हैं।
सेशेक्विलेडल

2
बस एक साधारण उदाहरण जोड़ना कि यह काम क्यों नहीं कर सकता है: >>> abs(0.04 - 0.03) <= 0.01यह पैदावार देता है False। मैं उपयोग करता हूंPython 2.7.10 [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
schatten

3
@ उचित होने के लिए, उदाहरण के लिए विशेष बराबरी की तुलना में मशीन बाइनरी सटीक / प्रारूपों के साथ अधिक करना है। जब आप सिस्टम में 0.03 दर्ज करते हैं, तो यह वास्तव में सीपीयू को बनाने वाली संख्या नहीं है।
एंड्रयू व्हाइट

2
@AndrewWhite वह उदाहरण दिखाता है जो abs(f1 - f2) <= allowed_errorअपेक्षा के अनुरूप काम नहीं करता है।
Schatten

44

मैं इस बात से सहमत हूं कि गैरेथ का उत्तर शायद हल्के फंक्शन / समाधान के रूप में सबसे उपयुक्त है।

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

numpy.isclose(a, b, rtol=1e-05, atol=1e-08, equal_nan=False)

हालांकि थोड़ा सा अस्वीकरण: NumPy स्थापित करना आपके प्लेटफॉर्म के आधार पर एक गैर-तुच्छ अनुभव हो सकता है।


1
"आपके प्लेटफॉर्म के आधार पर सुपी को स्थापित करना एक गैर-तुच्छ अनुभव हो सकता है।" ... उम क्या? सुन्नत स्थापित करने के लिए यह "गैर-तुच्छ" कौन सा मंच है? क्या वास्तव में यह गैर तुच्छ बना दिया?
जॉन

10
@ जॉन: विंडोज के लिए 64-बिट बाइनरी प्राप्त करना कठिन है। pipविंडोज के माध्यम से सुन्न पाने के लिए मुश्किल ।
बेन बोल्कर

@Ternak: मैं करता हूं, लेकिन मेरे कुछ छात्र विंडोज का उपयोग करते हैं, इसलिए मुझे इस सामान से निपटना होगा।
बेन बोलकर

4
@BenBolker आप अजगर द्वारा संचालित खुले डेटा विज्ञान मंच स्थापित करने के लिए है, तो सबसे अच्छा तरीका है एनाकोंडा है continuum.io/downloads (पांडा, numpy और बॉक्स से बाहर अधिक)
jrovegno

एनाकोंडा को स्थापित करना तुच्छ है
एंडोलिथ

13

पायथन के decimalमॉड्यूल का उपयोग करें , जो Decimalकक्षा प्रदान करता है ।

टिप्पणियों से:

यह ध्यान देने योग्य है कि यदि आप गणित-भारी काम कर रहे हैं और आपको दशमलव से सटीक की आवश्यकता नहीं है, तो यह वास्तव में चीजों को कम कर सकता है। फ्लोट्स रास्ता है, जिस तरह से तेजी से निपटने के लिए, लेकिन imprecise। दशमलव बेहद सटीक लेकिन धीमा है।


11

मैं पायथन मानक पुस्तकालय (या कहीं और) में कुछ भी अवगत नहीं हूं जो डॉसन के AlmostEqual2sComplementकार्य को लागू करता है। यदि आप चाहते हैं कि इस तरह का व्यवहार है, तो आपको इसे स्वयं लागू करना होगा। (किस मामले में, डॉसन की चतुर बिटवाइन्स हैक का उपयोग करने के बजाय आप फॉर्म if abs(a-b) <= eps1*(abs(a)+abs(b)) + eps2या समान के अधिक पारंपरिक परीक्षणों का उपयोग करना बेहतर करेंगे । डॉसन-जैसा व्यवहार पाने के if abs(a-b) <= eps*max(EPS,abs(a),abs(b))लिए आप कुछ छोटे फिक्स्ड के लिए ऐसा कुछ कह सकते हैं EPS; यह बिल्कुल नहीं है। डॉसन के समान, लेकिन यह आत्मा में समान है।


मैं यहाँ पर आप जो कर रहे हैं, वह काफी नहीं है, लेकिन यह दिलचस्प है। Eps, eps1, eps2 और EPS में क्या अंतर है?
गॉर्डन Wrigley

eps1और eps2एक रिश्तेदार और एक पूर्ण सहिष्णुता को परिभाषित करें: आप अनुमति aदेने के bलिए तैयार हैं और eps1समय के हिसाब से अलग-अलग हैं कि वे कितने बड़े हैं eps2epsएक सहिष्णुता है; आप अनुमति aदेने के bलिए तैयार हैं और इस बात से अलग हैं epsकि वे कितने बड़े हैं, इस बात के साथ कि आकार EPSया छोटे आकार का कुछ भी माना जाता है EPS। यदि आप EPSअपने फ्लोटिंग-पॉइंट प्रकार का सबसे छोटा गैर-असमान मूल्य लेते हैं , तो यह डॉसन के तुलनित्र (2 ^ # बिट के एक कारक को छोड़कर) के समान है क्योंकि डॉसन अल्सर में सहिष्णुता को मापता है)।
गैरेथ मैककॉघन

2
संयोग से, मैं एस। लोट से सहमत हूं कि राइट थिंग हमेशा आपके वास्तविक एप्लिकेशन पर निर्भर करता है, यही कारण है कि आपकी सभी फ्लोटिंग-पॉइंट तुलना आवश्यकताओं के लिए एक भी मानक लाइब्रेरी फ़ंक्शन नहीं है।
गैरेथ मैककॉघन

@ गैरेथ-मैक्गथन, अजगर के लिए "आपके फ्लोटिंग-पॉइंट प्रकार के सबसे छोटे गैर-असमान मूल्य" का निर्धारण कैसे किया जाता है?
गॉर्डन Wrigley

यह पृष्ठ docs.python.org/tutorial/floatingpoint.html कहता है कि लगभग सभी अजगर कार्यान्वयन IEEE-754 दोहरी परिशुद्धता फ़्लोट का उपयोग करते हैं और यह पृष्ठ en.wikipedia.org/wiki/IEEE_754-1985 सामान्यीकृत संख्याओं को शून्य से निकटतम कहता है: ± 2 * * -1022।
गॉर्डन Wrigley

11

समानता के लिए फ्लोटिंग-पॉइंट नंबरों की सामान्य ज्ञान की तुलना गलत नहीं की जा सकती है। फ़्लोटिंग-पॉइंट नंबर पूर्णांकों से अलग नहीं हैं: यदि आप "a == b" का मूल्यांकन करते हैं, तो आप सत्य होंगे यदि वे समान संख्याएँ और झूठे हों अन्यथा (इस समझ के साथ कि दो NaN समान संख्या में नहीं हैं)।

वास्तविक समस्या यह है: अगर मैंने कुछ गणनाएँ की हैं और मुझे यकीन नहीं है कि मुझे जिन दो नंबरों की तुलना करनी है, वे बिल्कुल सही हैं, तो क्या? यह समस्या फ्लोटिंग-पॉइंट के लिए समान है क्योंकि यह पूर्णांकों के लिए है। यदि आप पूर्णांक अभिव्यक्ति "7/3 * 3" का मूल्यांकन करते हैं, तो यह "7 * 3/3" के बराबर नहीं होगा।

तो मान लीजिए हमने पूछा "मैं समानता के लिए पूर्णांक की तुलना कैसे करूं?" ऐसी स्थिति में। एक भी उत्तर नहीं है; आपको क्या करना चाहिए यह विशिष्ट स्थिति पर निर्भर करता है, विशेष रूप से आपके पास किस प्रकार की त्रुटियां हैं और आप क्या हासिल करना चाहते हैं।

यहाँ कुछ संभावित विकल्प दिए गए हैं।

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

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

यदि आप गणितीय रूप से "गलत" परिणाम प्राप्त करना चाहते हैं यदि गणितीय रूप से सटीक संख्याएं असमान होंगी, तो आपको यह साबित करने की आवश्यकता है कि यदि गणितीय रूप से सटीक संख्याएं असमान होंगी तो संख्याओं का आपका मूल्यांकन अलग-अलग संख्याओं को उत्पन्न करता है। कई सामान्य स्थितियों में व्यावहारिक उद्देश्यों के लिए यह असंभव हो सकता है। तो आइए एक विकल्प पर विचार करें।

एक उपयोगी आवश्यकता यह हो सकती है कि यदि हमें गणितीय रूप से सटीक संख्या एक निश्चित राशि से अधिक हो तो "गलत" परिणाम मिलता है। उदाहरण के लिए, शायद हम यह गणना करने जा रहे हैं कि कंप्यूटर गेम में फेंकी गई एक गेंद कहां गई, और हम जानना चाहते हैं कि क्या इसने बल्ले को मारा। इस मामले में, हम निश्चित रूप से "सच" प्राप्त करना चाहते हैं यदि गेंद बल्ले से टकराती है, और यदि गेंद बल्ले से दूर है, तो हम "झूठा" प्राप्त करना चाहते हैं, और यदि गेंद अंदर है तो हम गलत "सही" उत्तर स्वीकार कर सकते हैं। गणितीय रूप से सटीक अनुकार बल्ले से चूक गया लेकिन बल्ले से टकराने के मिलीमीटर के भीतर है। उस मामले में, हमें यह साबित करने (या अनुमान / अनुमान) करने की आवश्यकता है कि गेंद की स्थिति और बल्ले की स्थिति की हमारी गणना में एक मिलीमीटर (ब्याज के सभी पदों के लिए) की संयुक्त त्रुटि है। यह हमें हमेशा लौटने की अनुमति देगा ”

तो, आप कैसे तय करते हैं कि फ्लोटिंग-पॉइंट नंबरों की तुलना करते समय क्या लौटना है यह आपकी विशिष्ट स्थिति पर बहुत निर्भर करता है।

जैसा कि आप गणनाओं के लिए त्रुटि सीमा साबित करने के बारे में कैसे जाते हैं, यह एक जटिल विषय हो सकता है। IEEE 754 मानक के राउंड-पास मोड में उपयोग करने वाला कोई भी फ्लोटिंग-पॉइंट कार्यान्वयन किसी भी बेसिक ऑपरेशन (विशेष रूप से गुणा, विभाजन, जोड़, घटाव, वर्गमूल) के लिए सटीक परिणाम के निकटतम फ्लोटिंग-पॉइंट नंबर देता है। (टाई के मामले में, राउंड कम बिट सम है।) (वर्गमूल और विभाजन के बारे में विशेष रूप से सावधान रहें; आपकी भाषा कार्यान्वयन उन विधियों का उपयोग कर सकती है जो उन लोगों के लिए IEEE 754 के अनुरूप नहीं हैं।) इस आवश्यकता के कारण, हम जानते हैं। एक परिणाम में त्रुटि सबसे कम महत्वपूर्ण बिट के मूल्य के 1/2 से अधिक है। (यदि यह अधिक होता, तो गोलाई एक अलग संख्या में चली जाती जो 1/2 मान के भीतर होती है।)

वहाँ से जाने पर बहुत अधिक जटिल हो जाता है; अगला चरण एक ऑपरेशन कर रहा है, जहां इनपुट में से एक में पहले से ही कुछ त्रुटि है। सरल अभिव्यक्तियों के लिए, अंतिम त्रुटि पर एक सीमा तक पहुंचने के लिए गणना के माध्यम से इन त्रुटियों का पालन किया जा सकता है। व्यवहार में, यह केवल कुछ स्थितियों में किया जाता है, जैसे उच्च गुणवत्ता वाले गणित पुस्तकालय पर काम करना। और, निश्चित रूप से, आपको सटीक नियंत्रण की आवश्यकता है कि कौन से ऑपरेशन किए जाते हैं। उच्च-स्तरीय भाषाएं अक्सर कंपाइलर को बहुत सुस्त कर देती हैं, इसलिए आपको पता नहीं चलता कि किस क्रम में ऑपरेशन किए जाते हैं।

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


3
गैरेथ मैककॉघन के साथ ऊपर चर्चा से, एक रिश्तेदार त्रुटि के साथ सही ढंग से तुलना करने पर अनिवार्य रूप से "एब्स (एबी) <= ईपीएस अधिकतम (2 * -1022, एब्स (ए), एब्स (बी))", यह कुछ ऐसा नहीं है जिसका मैं वर्णन करूंगा। के रूप में सरल और निश्चित रूप से कुछ नहीं है जो मैंने खुद से काम किया होगा। जैसा कि स्टीव जेसोप बताते हैं कि यह अधिकतम, न्यूनतम, किन्हीं और सभी के लिए समान जटिलता है, जो सभी निर्मित हैं। इसलिए मानक गणित मॉड्यूल में एक सापेक्ष त्रुटि तुलना प्रदान करना एक अच्छा विचार है।
गॉर्डन Wrigley

(7/3 * 3 == 7 * 3/3) अजगर में सच का मूल्यांकन करता है।
xApple

@xApple: मैंने अभी OS X 10.8.3 पर पायथन 2.7.2 चलाया और प्रवेश किया (7/3*3 == 7*3/3)। यह छपा False
एरिक पोस्टपिसिल

3
आप शायद टाइप करना भूल गए from __future__ import division। यदि आप ऐसा नहीं करते हैं, तो कोई फ़्लोटिंग पॉइंट नंबर नहीं हैं और तुलना दो पूर्णांकों के बीच है।
XApple

3
यह एक महत्वपूर्ण चर्चा है, लेकिन अविश्वसनीय रूप से सहायक नहीं है।
डैन हुल्मे

6

यदि आप इसे परीक्षण / TDD संदर्भ में उपयोग करना चाहते हैं, तो मैं कहूंगा कि यह एक मानक तरीका है:

from nose.tools import assert_almost_equals

assert_almost_equals(x, y, places=7) #default is 7

5

उसके ( स्रोत कोड ) के लिए Python 3.5 में math.isclose () जोड़ा गया है । यहाँ इसका एक भाग है पायथन 2. मार्क रैनसम के वन-लाइनर से यह अंतर है कि यह "inf" और "-inf" को ठीक से हैंडल कर सकता है।

def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
    '''
    Python 2 implementation of Python 3.5 math.isclose()
    https://hg.python.org/cpython/file/tip/Modules/mathmodule.c#l1993
    '''
    # sanity check on the inputs
    if rel_tol < 0 or abs_tol < 0:
        raise ValueError("tolerances must be non-negative")

    # short circuit exact equality -- needed to catch two infinities of
    # the same sign. And perhaps speeds things up a bit sometimes.
    if a == b:
        return True

    # This catches the case of two infinities of opposite sign, or
    # one infinity and one finite number. Two infinities of opposite
    # sign would otherwise have an infinite relative tolerance.
    # Two infinities of the same sign are caught by the equality check
    # above.
    if math.isinf(a) or math.isinf(b):
        return False

    # now do the regular computation
    # this is essentially the "weak" test from the Boost library
    diff = math.fabs(b - a)
    result = (((diff <= math.fabs(rel_tol * b)) or
               (diff <= math.fabs(rel_tol * a))) or
              (diff <= abs_tol))
    return result

2

मुझे निम्नलिखित तुलना उपयोगी लगी:

str(f1) == str(f2)

यह दिलचस्प है, लेकिन str (.1 + .2) == .3 के कारण बहुत व्यावहारिक नहीं है
गॉर्डन Wrigley

str (.1 + .2) == str (.3) रिटर्न सही
हेनरिख कैंतुनी

यह f1 == f2 से कैसे अलग है - यदि वे दोनों पास हैं लेकिन फिर भी सटीक होने के कारण अलग हैं, तो स्ट्रिंग प्रतिनिधित्व भी असमान होगा।
श्रीमती मास

2
.1 + .2 == .3 रिटर्न गलत जबकि स्ट्रॉस (.1 + .2) == स्ट्रैट (.3) रिटर्न ट्रू
क्रेसिमिर

4
पायथॉन 3.7.2 में, str(.1 + .2) == str(.3)गलत रिटर्न देता है। ऊपर वर्णित विधि केवल पायथन 2 के लिए काम करती है
दानिबिक्स

1

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

देखें अंश अंशों जानकारी के लिए मॉड्यूल से।


1

मुझे @Sesquipedal का सुझाव पसंद आया लेकिन संशोधन के साथ (एक विशेष उपयोग मामला जब दोनों मान 0 रिटर्न गलत हैं)। मेरे मामले में मैं पायथन 2.7 पर था और बस एक साधारण फ़ंक्शन का उपयोग किया था:

if f1 ==0 and f2 == 0:
    return True
else:
    return abs(f1-f2) < tol*max(abs(f1),abs(f2))

1

उस मामले के लिए उपयोगी जहाँ आप यह सुनिश्चित करना चाहते हैं कि 2 संख्याएँ 'सटीक तक' समान हों, सहिष्णुता को निर्दिष्ट करने की आवश्यकता नहीं है:

  • 2 नंबरों की न्यूनतम सटीकता का पता लगाएं

  • दोनों को न्यूनतम परिशुद्धता के लिए गोल करें और तुलना करें

def isclose(a,b):                                       
    astr=str(a)                                         
    aprec=len(astr.split('.')[1]) if '.' in astr else 0 
    bstr=str(b)                                         
    bprec=len(bstr.split('.')[1]) if '.' in bstr else 0 
    prec=min(aprec,bprec)                                      
    return round(a,prec)==round(b,prec)                               

जैसा कि लिखा गया है, केवल उनके स्ट्रिंग प्रतिनिधित्व में 'ई' के बिना संख्याओं के लिए काम करता है (जिसका अर्थ है 0.9999999999995e-4 <संख्या <= 0.9999999999995e11)

उदाहरण:

>>> isclose(10.0,10.049)
True
>>> isclose(10.0,10.05)
False

घनिष्ठ की अबाधित अवधारणा आपको अच्छी सेवा नहीं देगी। isclose(1.0, 1.1)पैदा करता है False, और isclose(0.1, 0.000000000001)लौटता है True
kfsone

1

बिना दिए गए दशमलव की तुलना करने के लिए atol/rtol:

def almost_equal(a, b, decimal=6):
    return '{0:.{1}f}'.format(a, decimal) == '{0:.{1}f}'.format(b, decimal)

print(almost_equal(0.0, 0.0001, decimal=5)) # False
print(almost_equal(0.0, 0.0001, decimal=4)) # True 

1

यह शायद थोड़ा बदसूरत हैक है, लेकिन यह बहुत अच्छी तरह से काम करता है जब आपको डिफ़ॉल्ट फ्लोट सटीक (लगभग 11 डेसीमल) से अधिक की आवश्यकता नहीं होती है।

Round_to फ़ंक्शन का उपयोग करता प्रारूप विधि से निर्मित एक स्ट्रिंग है जरूरत दशमलव की संख्या के साथ नाव का प्रतिनिधित्व करता है, और उसके बाद करने के लिए नाव को ख़त्म कर लिए str वर्ग पर लागू होता है eval गोल नाव स्ट्रिंग वापस पाने के लिए करने के लिए निर्मित समारोह फ्लोट न्यूमेरिक प्रकार के लिए।

Is_close समारोह सिर्फ गोल अप नाव के लिए एक सरल सशर्त लागू होता है।

def round_to(float_num, prec):
    return eval("'{:." + str(int(prec)) + "f}'.format(" + str(float_num) + ")")

def is_close(float_a, float_b, prec):
    if round_to(float_a, prec) == round_to(float_b, prec):
        return True
    return False

>>>a = 10.0
10.0
>>>b = 10.0001
10.0001
>>>print is_close(a, b, prec=3)
True
>>>print is_close(a, b, prec=4)
False

अपडेट करें:

जैसा कि @stepehjfox ने सुझाव दिया है, "eval" से बचने के लिए एक rount_to फ़ंक्शन का निर्माण करने के लिए एक क्लीनर तरीका नीचे दिए गए प्रारूप का उपयोग कर रहा है :

def round_to(float_num, prec):
    return '{:.{precision}f}'.format(float_num, precision=prec)

एक ही विचार के बाद, कोड को नए बढ़िया तार (पायथन 3.6+) का उपयोग करके और भी सरल बनाया जा सकता है :

def round_to(float_num, prec):
    return f'{float_num:.{prec}f}'

इसलिए, हम इसे एक सरल और स्वच्छ 'is_close' फ़ंक्शन में भी लपेट सकते हैं :

def is_close(a, b, prec):
    return f'{a:.{prec}f}' == f'{b:.{prec}f}'

1
आपको eval()पैरामीटराइज्ड फॉर्मेटिंग प्राप्त करने के लिए उपयोग करने की आवश्यकता नहीं है । कुछ ऐसा return '{:.{precision}f'.format(float_num, precision=decimal_precision) करना चाहिए
स्टीफनजापॉक्स

1
मेरी टिप्पणी और अधिक उदाहरणों के लिए स्रोत: pyformat.info/#param_align
stephenjfox

1
धन्यवाद @stephenjfox मुझे नेस्टेड स्वरूपण के बारे में नहीं पता था। Btw, आपके नमूना कोड में अंतिम घुंघराले ब्रेसिज़ की कमी है:return '{:.{precision}}f'.format(float_num, precision=decimal_precision)
अल्बर्ट अलोमार

1
अच्छी पकड़, और विशेष रूप से अच्छी तरह से वृद्धि के साथ एफ-स्ट्रिंग्स। कोने के आसपास अजगर 2 की मौत के साथ, शायद यह आदर्श बन जाएगा
स्टीफनजापोक्स

0

पूर्ण त्रुटि के संदर्भ में, आप बस जांच कर सकते हैं

if abs(a - b) <= error:
    print("Almost equal")

पायथन में अजीब क्यों काम करते हैं इसकी कुछ जानकारी https://youtu.be/v4HhvoNLILk?t1.19

आप सापेक्ष त्रुटियों के लिए math.isclose का भी उपयोग कर सकते हैं

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.