फ्लोटिंग पॉइंट वैल्यू की तुलना करना कितना खतरनाक है?


391

मुझे पता है कि संकल्प स्वतंत्र समन्वय प्रणाली के कारण UIKitउपयोग करता CGFloatहै।

लेकिन हर बार अगर मैं उदाहरण के लिए जाँच करना चाहता हूँ कि frame.origin.xक्या 0यह मुझे बीमार महसूस कर रहा है:

if (theView.frame.origin.x == 0) {
    // do important operation
}

नहीं है CGFloatझूठे सकारात्मक की चपेट में साथ तुलना करते समय ==, <=, >=, <, >? यह एक फ्लोटिंग पॉइंट है और उनके पास अनुपलब्ध समस्याएं हैं: 0.0000000000041उदाहरण के लिए।

क्या Objective-Cतुलना करते समय यह आंतरिक रूप से है या ऐसा हो सकता है कि origin.xजो शून्य के रूप में पढ़ता है वह 0सच के रूप में तुलना नहीं करता है?

जवाबों:


466

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

सबसे पहले, यदि आप फ्लोटिंग पॉइंट के साथ प्रोग्राम करना चाहते हैं, तो आपको इसे पढ़ना चाहिए:

फ्लोटिंग-पॉइंट अंकगणित के बारे में हर कंप्यूटर वैज्ञानिक को क्या जानना चाहिए

हाँ, यह सब पढ़ें। यदि यह बहुत अधिक बोझ है, तो आपको अपनी गणना के लिए पूर्णांक / निश्चित बिंदु का उपयोग करना चाहिए जब तक कि आपके पास इसे पढ़ने के लिए समय न हो। :-)

अब, कहा गया है कि, सटीक फ़्लोटिंग पॉइंट तुलना के साथ सबसे बड़े मुद्दे नीचे आते हैं:

  1. तथ्य यह है कि बहुत सारे मूल्य आप स्रोत में लिख सकते हैं, या साथ पढ़ सकते हैं scanfया strtod, अस्थायी बिंदु मानों के रूप में मौजूद नहीं हैं और चुपचाप निकटतम सन्निकटन में परिवर्तित हो जाते हैं। यह वही है जो dem9733 के जवाब के बारे में बात कर रहा था।

  2. तथ्य यह है कि वास्तविक परिणाम का प्रतिनिधित्व करने के लिए पर्याप्त सटीकता नहीं होने के कारण कई परिणाम गोल हो जाते हैं। एक आसान उदाहरण जहां आप देख सकते हैं कि यह जोड़ रहा है x = 0x1fffffeऔर y = 1तैरता है। यहां, xमंटिसा (ओके) में 24 बिट्स की सटीकता है और yसिर्फ 1 बिट है, लेकिन जब आप उन्हें जोड़ते हैं, तो उनके बिट्स ओवरलैपिंग स्थानों में नहीं होते हैं, और परिणाम में 25 बिट्स सटीक की आवश्यकता होती है। इसके बजाय, यह गोल हो जाता है ( 0x2000000डिफ़ॉल्ट राउंडिंग मोड में)।

  3. तथ्य यह है कि कई परिणाम सही मूल्य के लिए असीम रूप से कई स्थानों की आवश्यकता के कारण गोल हो जाते हैं। इसमें 1/3 (जैसे कि आप दशमलव से परिचित हैं, जहां यह कई स्थानों पर होता है) जैसे दोनों तर्कसंगत परिणाम शामिल हैं, लेकिन यह भी 1/10 (जो कि बाइनरी में भी कई जगह लेता है, क्योंकि 5 में 2 की शक्ति नहीं है) किसी भी वर्ग के मूल की तरह तर्कहीन परिणाम जैसे कि एक पूर्ण वर्ग नहीं है।

  4. दोहरा गोलाई। कुछ प्रणालियों (विशेष रूप से x86) पर, अस्थायी बिंदु अभिव्यक्तियों का मूल्यांकन उनके नाममात्र प्रकारों की तुलना में उच्च परिशुद्धता में किया जाता है। इसका मतलब यह है कि जब उपरोक्त प्रकार के राउंडिंग में से एक होता है, तो आपको दो राउंडिंग चरण मिलेंगे, पहले परिणाम का एक राउंडिंग उच्च-सटीक प्रकार, फिर अंतिम प्रकार के लिए एक राउंडिंग। एक उदाहरण के रूप में, विचार करें कि दशमलव में क्या होता है यदि आप 1.49 पूर्णांक (1) के पास होते हैं, बनाम क्या होता है यदि आप इसे पहले एक दशमलव स्थान (1.5) पर गोल करते हैं तो उस परिणाम को पूर्णांक (2) के रूप में गोल करते हैं। यह वास्तव में फ्लोटिंग पॉइंट से निपटने के लिए सबसे निचले क्षेत्रों में से एक है, क्योंकि कंपाइलर का व्यवहार (विशेष रूप से छोटी गाड़ी के लिए, जीसीसी जैसी गैर-अनुरूपता वाले कंपाइलर) अप्रत्याशित है।

  5. ट्रान्सेंडैंटल कार्य ( trig, exp, log, आदि) सही ढंग से गोल परिणाम के लिए निर्दिष्ट नहीं हैं; परिणाम केवल सटीक के अंतिम स्थान में एक इकाई के भीतर सही होने के लिए निर्दिष्ट है (आमतौर पर 1ulp के रूप में संदर्भित )।

जब आप फ़्लोटिंग पॉइंट कोड लिख रहे हों, तो आपको यह ध्यान रखना होगा कि आप उन नंबरों के साथ क्या कर रहे हैं जो परिणाम को अक्षम कर सकते हैं और तदनुसार तुलना कर सकते हैं। अक्सर बार यह एक "एप्सिलॉन" के साथ तुलना करने के लिए समझ में आता है, लेकिन यह एप्सिलॉन उन संख्याओं के परिमाण पर आधारित होना चाहिए जो आप तुलना कर रहे हैं , न कि निरपेक्ष स्थिर। (ऐसे मामलों में जहां निरपेक्ष स्थिर एप्सिलॉन काम करेगा, यह दृढ़ता से संकेत देता है कि फिक्स्ड पॉइंट, फ़्लोटिंग पॉइंट नहीं, नौकरी के लिए सही उपकरण है!)

संपादित करें: विशेष रूप से, परिमाण-सापेक्ष एप्सिलॉन जांच कुछ इस तरह दिखनी चाहिए:

if (fabs(x-y) < K * FLT_EPSILON * fabs(x+y))

कहाँ FLT_EPSILONसे स्थिर है float.h(के साथ बदलने DBL_EPSILONके लिए doubleया LDBL_EPSILONके लिए long double) और Kएक निरंतर आप इस तरह है कि आपके संगणना के संचित त्रुटि निश्चित रूप से से घिरा है चुनें है Kअंतिम स्थान पर इकाइयों (और यदि आप सुनिश्चित नहीं हैं कि आप त्रुटि मिली बाध्य गणना सही है, Kजो आपकी गणना कहती है उससे कुछ गुना बड़ा करें)।

अंत में, ध्यान दें कि यदि आप इसका उपयोग करते हैं, तो शून्य के पास कुछ विशेष देखभाल की आवश्यकता हो सकती है, क्योंकि FLT_EPSILONdenormals के लिए कोई मतलब नहीं है। इसे बनाने के लिए एक त्वरित सुधार होगा:

if (fabs(x-y) < K * FLT_EPSILON * fabs(x+y) || fabs(x-y) < FLT_MIN)

और इसी तरह DBL_MINडबल्स का उपयोग करने पर विकल्प ।


25
fabs(x+y)समस्याग्रस्त है अगर ( xऔर y) अलग संकेत हो सकता है। फिर भी, कार्गो-पंथ की तुलना के ज्वार के खिलाफ एक अच्छा जवाब।
डैनियल फिशर

27
अगर xऔर yअलग संकेत है, तो यह कोई समस्या नहीं है। दाहिनी ओर का हिस्सा "बहुत छोटा" होगा, लेकिन चूंकि xऔर yअलग-अलग संकेत हैं, इसलिए उन्हें किसी भी तरह की तुलना नहीं करनी चाहिए। (जब तक कि वे इतने छोटे न हों कि वे असामान्य हों, लेकिन तब दूसरा मामला इसे पकड़ लेता है)
आर .. गिटहब स्टॉप हेल्पिंग ICE

4
मैं आपके बयान के बारे में उत्सुक हूं: "विशेष रूप से छोटी गाड़ी, गैर-अनुरूपक संकलक जैसे कि जीसीसी"। क्या वास्तव में जीसीसी छोटी गाड़ी है और गैर-अनुरूप भी है?
निकोलस ओजिमिका

3
चूंकि प्रश्न आईओएस को टैग किया गया है, यह ध्यान देने योग्य है कि ऐप्पल के संकलक (दोनों क्लैंग और ऐप्पल के जीसीसी बिल्ड्स) ने हमेशा FLT_EVAL_METHOD = 0 का उपयोग किया है, और अतिरिक्त परिशुद्धता नहीं ले जाने के बारे में पूरी तरह से सख्त होने का प्रयास किया है। यदि आपको इसका कोई उल्लंघन लगता है, तो कृपया बग रिपोर्ट दर्ज करें।
स्टीफन कैनन

17
"सबसे पहले, फ़्लोटिंग पॉइंट वैल्यू उनके व्यवहार में" यादृच्छिक "नहीं हैं। सटीक तुलना वास्तविक दुनिया के उपयोग के बहुत सारे तरीकों से कर सकती है और इसका मतलब है।" - सिर्फ दो वाक्य और पहले से ही अर्जित +1! फ्लोटिंग पॉइंट्स के साथ काम करने के दौरान लोगों को सबसे अधिक परेशान करने वाली गलतफहमी में से एक है।
ईसाई रौ

36

चूँकि 0 IEEE754 फ़्लोटिंग-पॉइंट संख्या के रूप में बिल्कुल प्रतिनिधित्व योग्य है (या मैंने कभी भी काम किया है fp संख्याओं के किसी अन्य कार्यान्वयन का उपयोग करके) 0 के साथ तुलना करना संभवतः सुरक्षित है। आप काट सकते हैं, हालांकि, यदि आपका कार्यक्रम एक मान (जैसे theView.frame.origin.x) है, जिस पर आपको विश्वास करना चाहिए कि 0 होना चाहिए, लेकिन जो आपकी गणना 0 होने की गारंटी नहीं दे सकता है।

थोड़ा स्पष्ट करने के लिए, एक संगणना जैसे:

areal = 0.0

वसीयत (जब तक आपकी भाषा या सिस्टम टूटा हुआ नहीं है) एक मान बनाएं (जैसे कि (= = ०.०)) सही लेकिन दूसरी गणना जैसे

areal = 1.386 - 2.1*(0.66)

शायद नहीं।

यदि आप अपने आप को आश्वस्त कर सकते हैं कि आपकी गणनाएँ मानों का उत्पादन करती हैं जो 0 हैं (और सिर्फ इतना नहीं कि वे उन मूल्यों का उत्पादन करते हैं जो 0 होना चाहिए) तो आप आगे जा सकते हैं और fp मूल्यों की तुलना 0. कर सकते हैं। यदि आप आवश्यक डिग्री के लिए खुद को आश्वस्त नहीं कर सकते हैं। , 'सहिष्णुता समानता' के सामान्य दृष्टिकोण के लिए सबसे अच्छा छड़ी।

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

एंग्री बर्ड के लिए, इतना खतरनाक नहीं।


11
वास्तव में, 1.30 - 2*(0.65)एक अभिव्यक्ति का एक आदर्श उदाहरण है जो स्पष्ट रूप से 0.0 का मूल्यांकन करता है यदि आपका कंपाइलर IEEE 754 को लागू करता है, क्योंकि डबल्स को समान महत्व दिया गया है 0.65और 1.30इसका महत्व है, और दो से गुणा स्पष्ट रूप से सटीक है।
पास्कल क्यूक

7
अभी भी इस एक से दोहराव हो रहा है, इसलिए मैंने दूसरा उदाहरण स्निपेट बदल दिया।
उच्च प्रदर्शन मार्क

22

मैं दूसरों की तुलना में थोड़ा अलग जवाब देना चाहता हूं। वे आपके प्रश्न का उत्तर देने के लिए बहुत अच्छे हैं, लेकिन शायद आपके लिए नहीं कि आपको क्या जानना है या आपकी वास्तविक समस्या क्या है।

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

इसलिए यदि आप परीक्षण करना चाहते हैं कि क्या आपका बिंदु एक [0.. उपलब्धता] सीमा के बाहर है तो यह ठीक है। बस सुनिश्चित करें कि आप लगातार समावेश को परिभाषित करते हैं। उदाहरण के लिए हमेशा अंदर परिभाषित है (x> = 0 && x <चौड़ाई)। वही चौराहे या हिट परीक्षणों के लिए जाता है।

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


13

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

पूरी तरह से प्रतिनिधित्व करने योग्य मूल्यों पर बात करते हुए, आपको पावर-ऑफ-टू धारणा (एकल परिशुद्धता) में 24 बिट्स की सीमा मिलती है। तो 1, 2, 4 पूरी तरह से प्रतिनिधित्व करने योग्य हैं, जैसे कि .5, .25, और .125 हैं। जब तक आपके सभी महत्वपूर्ण बिट्स 24-बिट्स में हैं, तब तक आप सुनहरे हैं। तो 10.625 को फिर से ठीक किया जा सकता है।

यह बहुत अच्छा है, लेकिन जल्दी से दबाव में गिर जाएगा। दो परिदृश्य वसंत को ध्यान में रखते हैं: 1) जब एक गणना शामिल होती है। विश्वास मत करो कि sqrt (3) * sqrt (3) == 3. यह सिर्फ इस तरह नहीं होगा। और यह शायद एक एप्सिलॉन के भीतर नहीं होगा, जैसा कि कुछ अन्य उत्तर बताते हैं। 2) जब कोई भी गैर-शक्ति -2 (NPOT) शामिल हो। तो यह अजीब लग सकता है, लेकिन 0.1 बाइनरी में एक अनंत श्रृंखला है और इसलिए किसी भी संख्या में इस तरह की गणना शुरू से ही लागू होगी।

(ओह और मूल प्रश्न में शून्य की तुलना का उल्लेख किया गया है। यह मत भूलो कि -0.0 भी पूरी तरह से वैध फ्लोटिंग-पॉइंट वैल्यू है।)


11

['सही जवाब' का चयन करने पर चमकती है K। चयन करना Kसिर्फ़ तदर्थ के रूप में चयन के रूप में समाप्त हो रहा है VISIBLE_SHIFTलेकिन चयन Kकरना कम स्पष्ट है क्योंकि इसके विपरीत VISIBLE_SHIFTयह किसी भी प्रदर्शन संपत्ति पर आधारित नहीं है। इस प्रकार अपना जहर चुनें - चयन करें Kया चुनें VISIBLE_SHIFT। यह उत्तर चयन की वकालत करता है VISIBLE_SHIFTऔर फिर चयन में कठिनाई को दर्शाता है K]

संभवतः गोल त्रुटियों के कारण, आपको तार्किक संचालन के लिए 'सटीक' मानों की तुलना का उपयोग नहीं करना चाहिए। दृश्य डिस्प्ले पर स्थिति के आपके विशिष्ट मामले में, यह संभवतया कोई फर्क नहीं पड़ता कि स्थिति 0.0 या 0.0000000003 है - अंतर आंख के लिए अदृश्य है। तो आपका तर्क कुछ इस तरह होना चाहिए:

#define VISIBLE_SHIFT    0.0001        // for example
if (fabs(theView.frame.origin.x) < VISIBLE_SHIFT) { /* ... */ }

हालांकि, अंत में, 'आंख के लिए अदृश्य' आपके प्रदर्शन गुणों पर निर्भर करेगा। यदि आप डिस्प्ले को ऊपरी बाँध सकते हैं (आपको सक्षम होना चाहिए); फिर VISIBLE_SHIFTउस ऊपरी बाउंड का एक हिस्सा होना चुनें ।

अब, 'सही उत्तर' इस पर टिकी हुई है Kकि चलो उठाकर देखें K। ऊपर 'सही उत्तर' कहता है:

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

तो हमें जरूरत है K। यदि Kअधिक कठिन हो रहा है, मेरे चयन से कम सहज है VISIBLE_SHIFTतो आप तय करेंगे कि आपके लिए क्या काम करता है। खोजने के लिए Kहम एक परीक्षण कार्यक्रम लिखने जा रहे हैं जो Kमूल्यों के एक समूह को देखता है ताकि हम देख सकें कि यह कैसे व्यवहार करता है। स्पष्ट होना चाहिए कि कैसे चुनना है K, अगर 'सही जवाब' प्रयोग करने योग्य है। नहीं?

हम 'सही उत्तर' विवरण के रूप में उपयोग करने जा रहे हैं:

if (fabs(x-y) < K * DBL_EPSILON * fabs(x+y) || fabs(x-y) < DBL_MIN)

आइए K के सभी मानों को आज़माएँ:

#include <math.h>
#include <float.h>
#include <stdio.h>

void main (void)
{
  double x = 1e-13;
  double y = 0.0;

  double K = 1e22;
  int i = 0;

  for (; i < 32; i++, K = K/10.0)
    {
      printf ("K:%40.16lf -> ", K);

      if (fabs(x-y) < K * DBL_EPSILON * fabs(x+y) || fabs(x-y) < DBL_MIN)
        printf ("YES\n");
      else
        printf ("NO\n");
    }
}
ebg@ebg$ gcc -o test test.c
ebg@ebg$ ./test
K:10000000000000000000000.0000000000000000 -> YES
K: 1000000000000000000000.0000000000000000 -> YES
K:  100000000000000000000.0000000000000000 -> YES
K:   10000000000000000000.0000000000000000 -> YES
K:    1000000000000000000.0000000000000000 -> YES
K:     100000000000000000.0000000000000000 -> YES
K:      10000000000000000.0000000000000000 -> YES
K:       1000000000000000.0000000000000000 -> NO
K:        100000000000000.0000000000000000 -> NO
K:         10000000000000.0000000000000000 -> NO
K:          1000000000000.0000000000000000 -> NO
K:           100000000000.0000000000000000 -> NO
K:            10000000000.0000000000000000 -> NO
K:             1000000000.0000000000000000 -> NO
K:              100000000.0000000000000000 -> NO
K:               10000000.0000000000000000 -> NO
K:                1000000.0000000000000000 -> NO
K:                 100000.0000000000000000 -> NO
K:                  10000.0000000000000000 -> NO
K:                   1000.0000000000000000 -> NO
K:                    100.0000000000000000 -> NO
K:                     10.0000000000000000 -> NO
K:                      1.0000000000000000 -> NO
K:                      0.1000000000000000 -> NO
K:                      0.0100000000000000 -> NO
K:                      0.0010000000000000 -> NO
K:                      0.0001000000000000 -> NO
K:                      0.0000100000000000 -> NO
K:                      0.0000010000000000 -> NO
K:                      0.0000001000000000 -> NO
K:                      0.0000000100000000 -> NO
K:                      0.0000000010000000 -> NO

आह, तो K को 1e16 या बड़ा होना चाहिए अगर मैं 1e-13 को 'शून्य' चाहता हूं।

तो, मैं कहूंगा कि आपके पास दो विकल्प हैं:

  1. जैसा कि मैंने सुझाव दिया है, 'epsilon' के मूल्य के लिए अपने इंजीनियरिंग निर्णय का उपयोग करते हुए एक साधारण एप्सिलॉन संगणना करें । यदि आप ग्राफिक्स कर रहे हैं और 'शून्य' का मतलब आपकी दृश्य संपत्ति (छवियों, आदि) की जांच करने और एप्सिलॉन क्या हो सकता है की तुलना में एक 'दृश्यमान परिवर्तन' है।
  2. जब तक आप गैर-कार्गो-पंथ के उत्तर के संदर्भ को नहीं पढ़ते (और प्रक्रिया में अपना पीएचडी प्राप्त कर लेते हैं) तब तक किसी भी फ्लोटिंग पॉइंट कंप्यूटेशन का प्रयास न करें और फिर चयन करने के लिए अपने गैर-सहज ज्ञान युक्त निर्णय का उपयोग करें K

10
संकल्प-स्वतंत्रता का एक पहलू यह है कि आप यह सुनिश्चित करने के लिए नहीं बता सकते हैं कि "दृश्यमान शिफ्ट" संकलन-समय पर क्या है। सुपर-एचडी स्क्रीन पर जो अदृश्य है, वह एक छोटे गधे की स्क्रीन पर बहुत अच्छी तरह से स्पष्ट हो सकता है। कम से कम इसे स्क्रीन के आकार का एक फ़ंक्शन बनाना चाहिए। या इसे कुछ और नाम दें।
रोमेन

1
लेकिन कम से कम 'दृश्यमान बदलाव' का चयन आसानी से समझे जाने वाले प्रदर्शन (या फ्रेम) गुणों पर आधारित है - इसके विपरीत <सही उत्तर का> Kजो चयन करने के लिए मुश्किल और गैर-सहज है।
GoZoner

5

सही सवाल: कोई व्यक्ति कोको टच में अंकों की तुलना कैसे करता है?

सही उत्तर: CGPointEqualToPoint ()।

एक अलग सवाल: क्या दो गणना मूल्य समान हैं?

यहां पोस्ट किया गया उत्तर: वे नहीं हैं।

अगर वे पास हैं तो कैसे जांचें? यदि आप जांचना चाहते हैं कि क्या वे पास हैं, तो CGPointEqualToPoint () का उपयोग न करें। लेकिन, यह देखने के लिए जांचें कि क्या वे पास नहीं हैं। कुछ ऐसा करें जो वास्तविक दुनिया में समझ में आता है, जैसे कि यह देखने के लिए कि क्या एक बिंदु एक रेखा से परे है या अगर एक बिंदु एक गोले के अंदर है।


4

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

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


1

शून्य के साथ फ्लोट की तुलना के लिए आप ऐसे कोड का उपयोग कर सकते हैं:

if ((int)(theView.frame.origin.x * 100) == 0) {
    // do important operation
}

यह 0.1 सटीकता के साथ तुलना करेगा, जो इस मामले में CGFloat के लिए पर्याप्त है।


intबिना बीमा के कास्टिंग करना, अनिर्धारित व्यवहार (यूबी) theView.frame.origin.xकी intओर जाता है - या इस मामले में, 1/100 वीं सीमा होती है int
chux - मोनिका

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

0
-(BOOL)isFloatEqual:(CGFloat)firstValue secondValue:(CGFloat)secondValue{

BOOL isEqual = NO;

NSNumber *firstValueNumber = [NSNumber numberWithDouble:firstValue];
NSNumber *secondValueNumber = [NSNumber numberWithDouble:secondValue];

isEqual = [firstValueNumber isEqualToNumber:secondValueNumber];

return isEqual;

}


0

मैं दशमलव स्थानों की संख्या की तुलना करने के लिए निम्नलिखित तुलना फ़ंक्शन का उपयोग कर रहा हूं:

bool compare(const double value1, const double value2, const int precision)
{
    int64_t magnitude = static_cast<int64_t>(std::pow(10, precision));
    int64_t intValue1 = static_cast<int64_t>(value1 * magnitude);
    int64_t intValue2 = static_cast<int64_t>(value2 * magnitude);
    return intValue1 == intValue2;
}

// Compare 9 decimal places:
if (compare(theView.frame.origin.x, 0, 9)) {
    // do important operation
}

-6

मैं कहूंगा कि सही बात यह है कि प्रत्येक संख्या को एक वस्तु के रूप में घोषित किया जाए, और फिर उस वस्तु में तीन चीजों को परिभाषित करें: 1) एक समानता ऑपरेटर। 2) एक setAcceptableDifference विधि। 3) मूल्य ही। यदि दो मानों का पूर्ण अंतर स्वीकार्य मूल्य से कम है तो समानता ऑपरेटर सही साबित होता है।

आप समस्या के अनुरूप वस्तु को उपवर्गित कर सकते हैं। उदाहरण के लिए, 1 और 2 इंच के बीच की धातु की गोल पट्टियों को समान व्यास का माना जा सकता है यदि उनके व्यास 0.0001 इंच से कम भिन्न होते हैं। इसलिए आप पैरामीटर 0.0001 के साथ setAcceptableDifference को कॉल करेंगे, और फिर विश्वास के साथ समानता ऑपरेटर का उपयोग करेंगे।


1
यह एक अच्छा जवाब नहीं है। सबसे पहले, पूरी "वस्तु वस्तु" आपके मुद्दे को हल करने के लिए कुछ भी नहीं करती है। और दूसरा, "समानता" का आपका वास्तविक कार्यान्वयन वास्तव में सही नहीं है।
टॉम Swirly

3
टॉम, शायद आप फिर से "वस्तु" के बारे में सोचेंगे। वास्तविक संख्याओं के साथ, उच्च परिशुद्धता का प्रतिनिधित्व करते हुए, समानता शायद ही कभी होती है। लेकिन किसी के समानता का विचार आपके अनुरूप हो सकता है। यह एक अच्छा 'लगभग बराबर' ऑपरेटर था, लेकिन अच्छा नहीं होगा, लेकिन यह अच्छा होगा।
जॉन व्हाइट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.