जावा में फ़्लोट्स की तुलना करने के लिए == का उपयोग करने में क्या गलत है?


177

इस java.sun पृष्ठ के अनुसार ==जावा में फ्लोटिंग पॉइंट नंबरों के लिए समानता तुलना ऑपरेटर है।

हालाँकि, जब मैं यह कोड टाइप करता हूँ:

if(sectionID == currentSectionID)

मेरे संपादक में और स्थिर विश्लेषण चलाएं, मुझे मिलता है: "== की तुलना में JAVA0078 फ़्लोटिंग पॉइंट मान"

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


29
क्योंकि फ्लोट की तुलना == समस्याग्रस्त है, उन्हें आईडी के रूप में उपयोग करना नासमझी है; आपके उदाहरण कोड के नाम बताते हैं कि आप क्या कर रहे हैं; लंबे पूर्णांक (लंबे) को प्राथमिकता दी जाती है, और आईडी के लिए वास्तविक मानक।
कार्ल मैन्स्टर जूल 6'09


4
हाँ, यह सिर्फ एक यादृच्छिक उदाहरण था या क्या आप वास्तव में ID के रूप में फ़्लोट का उपयोग करते हैं? क्या कोई कारण है?
प्रति विकलैंडर

5
"फ्लोट फ़ील्ड्स के लिए, फ़्लैट डॉट कॉम विधि का उपयोग करें; और डबल फ़ील्ड्स के लिए, डबल.कॉमफ़ेयर का उपयोग करें। फ़्लोट और डबल फ़ील्ड्स के विशेष उपचार को फ्लोट के अस्तित्व द्वारा आवश्यक बना दिया जाता है। एनएएन, -0.0 एफ और अनुरूप डबल स्थिरांक; विवरण के लिए Float.equals प्रलेखन देखें। " (यहोशू बलोच: प्रभावी जावा)
lbalazscs

जवाबों:


211

'समानता' के लिए तैरने का परीक्षण करने का सही तरीका है:

if(Math.abs(sectionID - currentSectionID) < epsilon)

वांछित सटीकता के आधार पर, एप्सिलॉन 0.00000001 जैसी एक बहुत छोटी संख्या है।


26
एक निश्चित एप्सिलोन हमेशा एक अच्छा विचार क्यों नहीं है , इसके लिए स्वीकृत उत्तर में लिंक देखें ( cygnus-software.com/papers/comparingfloats/comparingfloats.htm )। विशेष रूप से, जैसा कि फ्लोट्स के मूल्यों में बड़े (या छोटे) मिलते हैं, एप्सिलॉन अब उपयुक्त नहीं है। (एप्सिलॉन का उपयोग करना ठीक है यदि आप जानते हैं कि आपके फ्लोट मूल्य सभी अपेक्षाकृत उचित हैं, हालांकि।)
पीटी

1
@PT क्या वह एक अंक के साथ एप्सिलॉन को गुणा कर सकता है और if(Math.abs(sectionID - currentSectionID) < epsilon*sectionIDउस समस्या से निपटने के लिए फ़ंक्शन बदल सकता है ?
उत्साही

3
यह अब तक का सबसे अच्छा जवाब हो सकता है, लेकिन यह अभी भी त्रुटिपूर्ण है। आप एप्सिलॉन कहाँ से प्राप्त करते हैं?
माइकल पिफेल

1
@MichaelPiefel यह पहले से ही कहता है: "वांछित सटीकता के आधार पर"। उनकी प्रकृति के अनुसार झंडे भौतिक मूल्यों की तरह होते हैं: आप कुल अशुद्धि के आधार पर कुछ सीमित संख्या में पदों में रुचि रखते हैं, इससे परे किसी भी मतभेद को मूट माना जाता है।
ivan_pozdeev

लेकिन ओपी वास्तव में केवल समानता के लिए परीक्षण करना चाहता था, और चूंकि यह अविश्वसनीय माना जाता है, इसलिए एक अलग विधि का उपयोग करना पड़ता है। फिर भी, मैं नहीं जानता कि वह जानता है कि उसकी "वांछित परिशुद्धता" क्या है; इसलिए यदि आप चाहते हैं कि एक अधिक विश्वसनीय समानता परीक्षण हो, तो सवाल यह है कि आप एप्सिलॉन को कहां से प्राप्त करते हैं? मैंने Math.ulp()इस प्रश्न के उत्तर में अपने प्रस्ताव का उपयोग किया।
माइकल पिफेल

53

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

रजिस्टर पर यह लेख एक अच्छा अवलोकन देता है कि यह मामला क्यों है; उपयोगी और रोचक पठन।


@kevindtimm: तो आप अपनी समानता के परीक्षण जैसे कि तब करेंगे (यदि संख्या == 6.099999904632568359375) किसी भी समय आप संख्या के बारे में जानना चाहते हैं, 6.1 के बराबर है ... हाँ आप सही हैं ... कंप्यूटर में सब कुछ सख्ती से नियतात्मक है, सिर्फ यह कि झांकियों के लिए इस्तेमाल किए जाने वाले अंदाज गणित की समस्याओं को करते समय प्रति-सहज होते हैं।
न्यूटॉपियन

फ्लोटिंग पॉइंट वैल्यू बहुत विशिष्ट हार्डवेयर पर केवल nondeterministically imprecise हैं ।
स्टुअर्ट पी। बेंटले

1
@ स्टुअर्ट मैं गलत हो सकता है, लेकिन मुझे नहीं लगता कि FDIV बग गैर-नियतात्मक था। हार्डवेयर द्वारा दिए गए उत्तर विनिर्देश के अनुरूप नहीं थे, लेकिन वे निर्धारक थे, जिसमें एक ही गणना हमेशा एक ही गलत परिणाम उत्पन्न करती थी
ग्रेविटी

@ गुरुत्व आप तर्क दे सकते हैं कि कोई भी व्यवहार नियतात्मक होता है जो एक विशिष्ट समुच्चय का संकेत देता है।
स्टुअर्ट पी। बेंटले

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

22

बस इसके पीछे कारण क्या है जो हर कोई कह रहा है।

फ्लोट का बाइनरी प्रतिनिधित्व एक तरह का कष्टप्रद है।

बाइनरी में, अधिकांश प्रोग्रामर 1 बी = 1 डी, 10 बी = 2 डी, 100 बी = 4 डी, 1000 बी = 8 डी के बीच संबंध को जानते हैं।

वैसे यह दूसरे तरीके से भी काम करता है।

.1 बी = .5 डी, .01 बी = .25 डी, .001 बी = .125, ...

समस्या यह है कि अधिकांश दशमलव संख्याओं जैसे कि .1, .2, .3, आदि का प्रतिनिधित्व करने का कोई सटीक तरीका नहीं है जो आप कर सकते हैं। जब नंबर प्रिंट होता है, तो सिस्टम .10000000000001 या .9999999999 के बजाय .1 प्रिंट करता है, जो कि संभवतः केवल 1 के रूप में संग्रहीत प्रतिनिधित्व के करीब है।

टिप्पणी से संपादित करें: इस समस्या का कारण हमारी अपेक्षाएं हैं। हम पूरी तरह से उम्मीद करते हैं कि जब हम दशमलव में परिवर्तित करते हैं, तो हम 7/3 को .7 या .67 या .666667 किसी भी बिंदु पर पूरी तरह से फ़्यूज़ होने की उम्मीद करेंगे। लेकिन हम स्वचालित रूप से उम्मीद नहीं करते हैं ।1 को 2/3 के समान गोल किया जाना चाहिए। - और यही हाल है।

वैसे, यदि आप उत्सुक हैं कि यह कितनी संख्या में आंतरिक रूप से संग्रहीत है एक द्विआधारी "वैज्ञानिक संकेतन" का उपयोग करके शुद्ध बाइनरी प्रतिनिधित्व है। इसलिए यदि आपने इसे दशमलव संख्या 10.75d स्टोर करने के लिए कहा है, तो यह 10 के लिए 1010b और दशमलव के लिए .11b संग्रहीत करेगा। तो यह स्टोर करेगा ।101011 फिर यह कहने के लिए कुछ बिट्स को बचाता है: दशमलव बिंदु को चार स्थानों पर ले जाएँ।

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


1
@ मट्ट के - उम, निश्चित बिंदु नहीं; अगर आप "दशमलव बिंदु [N] बिट्स को दाईं ओर ले जाते हैं" कहने के लिए अंत में कुछ बिट्स को बचाते हैं, तो वह अस्थायी बिंदु है। फिक्स्ड पॉइंट रेडिक्स पॉइंट की स्थिति को अच्छी तरह से तय करता है। इसके अलावा, सामान्य तौर पर, बिनमाल (?) बिंदु को स्थानांतरित करने के बाद से आपको हमेशा सबसे बाईं स्थिति में '1' के साथ छोड़ने के लिए बनाया जा सकता है, आपको कुछ सिस्टम मिलेंगे जो अग्रणी '1' को छोड़ देते हैं, इस प्रकार रिक्त स्थान को समर्पित करते हैं (1) बिट!) घातांक की सीमा का विस्तार करने के लिए।
JustJeff

समस्या का बाइनरी बनाम दशमलव प्रतिनिधित्व से कोई लेना-देना नहीं है। दशमलव फ़्लोटिंग-पॉइंट के साथ, आपके पास अभी भी (1/3) * 3 == 0.9999999999999999999999999999 जैसी चीजें हैं।
dan04

2
@ dan04 हाँ, क्योंकि 1/3 में कोई दशमलव या बाइनरी प्रतिनिधित्व नहीं है, इसमें एक त्रिकोणीय प्रतिनिधित्व है और यह सही तरीके से परिवर्तित होगा :)। जिन संख्याओं को मैंने सूचीबद्ध किया है (.1, .25, आदि) सभी में पूर्ण दशमलव निरूपण है लेकिन कोई बाइनरी प्रतिनिधित्व नहीं है - और लोगों का उपयोग "सटीक" अभ्यावेदन करने के लिए किया जाता है। बीसीडी उन्हें पूरी तरह से संभाल लेगी। यही अंतर है।
बिल के

1
इस तरह से अधिक upvotes होना चाहिए, क्योंकि यह मुद्दे के पीछे वास्तविक समस्या का वर्णन करता है।
लेवित

19

अस्थायी बिंदु मानों की तुलना करने के लिए == का उपयोग करने में क्या गलत है?

क्योंकि यह सच नहीं है 0.1 + 0.2 == 0.3


7
किस बारे में Float.compare(0.1f+0.2f, 0.3f) == 0?
कुंभ राशि

0.1f + 0.2f == 0.3f लेकिन 0.1d + 0.2d! = 0.3d। डिफ़ॉल्ट रूप से, 0.1 + 0.2 एक डबल है। 0.3 एक डबल के रूप में अच्छी तरह से है।
burnabyRails

12

मुझे लगता है कि फ़्लोट्स (और डबल्स) के आसपास बहुत भ्रम है, इसे साफ़ करना अच्छा है।

  1. मानक-अनुरूप JVM [*] में ID के रूप में फ़्लोट्स का उपयोग करने में कुछ भी गलत नहीं है । यदि आप बस फ्लोट आईडी को x पर सेट करते हैं, तो इसके साथ कुछ भी न करें (यानी कोई अंकगणित नहीं) और बाद में y == x के लिए परीक्षण करें, तो आप ठीक हो जाएंगे। इसके अलावा एक हाशप में कुंजियों के रूप में उनका उपयोग करने में कुछ भी गलत नहीं है। आप जो नहीं कर सकते हैं x == (x - y) + y, जैसे समानताएं आदि। यह कहा जा रहा है, लोग आमतौर पर आईडी के रूप में पूर्णांक प्रकारों का उपयोग करते हैं, और आप देख सकते हैं कि यहां ज्यादातर लोगों को इस कोड द्वारा बंद कर दिया गया है, इसलिए व्यावहारिक कारणों से, सम्मेलनों का पालन करना बेहतर है। । ध्यान दें कि doubleलंबे समय के रूप में कई अलग-अलग मूल्य हैं values, इसलिए आप उपयोग करके कुछ भी नहीं हासिल करते हैं double। इसके अलावा, "अगली उपलब्ध आईडी" बनाने से डबल्स के साथ मुश्किल हो सकती है और फ्लोटिंग-पॉइंट अंकगणित के कुछ ज्ञान की आवश्यकता होती है। मुसीबत के लायक नहीं।

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

[*] जब मैंने कहा "मानक-अनुरूप JVM" मैं कुछ मस्तिष्क-क्षतिग्रस्त JVM कार्यान्वयन को बाहर करना चाहता था। देखें इस


फ्लोट्स को आईडी के रूप में उपयोग करते समय, किसी को यह सुनिश्चित करने के लिए सावधान रहना चाहिए कि उनकी तुलना में उपयोग ==करने की तुलना में है equals, या फिर यह सुनिश्चित करें कि कोई भी फ्लोट जो असमान की तुलना में खुद को एक तालिका में संग्रहीत नहीं करता है। अन्यथा, एक प्रोग्राम जो उदाहरण के लिए गिनने की कोशिश करता है कि अभिव्यक्ति से कितने अनूठे परिणाम उत्पन्न हो सकते हैं जब विभिन्न इनपुटों को खिलाया जाता है, प्रत्येक NaN मान को अद्वितीय मान सकता है।
सुपरकैट

ऊपर संदर्भित करता है Float, को नहीं float
मात्रा_देव

क्या बात कर रहा है Float? यदि कोई अनन्य floatमानों की तालिका बनाने का प्रयास करता है और उनके साथ तुलना करता है ==, तो भयानक IEEE-754 तुलना नियमों के परिणामस्वरूप तालिका को NaNमूल्यों से भर दिया जाएगा ।
सुपरकैट

floatप्रकार में equalsविधि नहीं है ।
क्वांट_देव

आह - मेरा मतलब equalsउदाहरण विधि से नहीं था , बल्कि स्थैतिक विधि से (मुझे लगता है कि Floatकक्षा के भीतर ) दो प्रकार के मूल्यों की तुलना करता है float
सुपरकैट

9

यह एक समस्या है जो जावा के लिए विशिष्ट नहीं है। दो फ्लोट्स / डबल्स / किसी भी दशमलव प्रकार की संख्या की तुलना करने के लिए == का उपयोग करने से संभावित रूप से उनके स्टोर किए जाने के तरीके के कारण समस्या हो सकती है। एक एकल-सटीक फ्लोट (IEEE मानक 754 के अनुसार) में 32 बिट्स हैं, जिन्हें निम्नानुसार वितरित किया गया है:

1 बिट - साइन (0 = सकारात्मक, 1 = नकारात्मक)
8 बिट्स - एक्सपेन्सर (एक विशेष (पूर्वाग्रह -127) 2 एक्स में एक्स का प्रतिनिधित्व)
23 बिट्स - मंटिसा। एक्टुअल नंबर जो संग्रहित है।

मंटिसा क्या समस्या का कारण बनता है। यह वैज्ञानिक संकेतन की तरह है, केवल आधार 2 (बाइनरी) में संख्या 1.110011 x 2 ^ 5 या कुछ समान दिखती है। लेकिन बाइनरी में, पहले 1 हमेशा 1 होता है (0 के प्रतिनिधित्व को छोड़कर)

इसलिए, मेमोरी स्पेस (उद्देश्य के अनुसार) को बचाने के लिए, IEEE ने निर्णय लिया कि 1 को ग्रहण किया जाना चाहिए। उदाहरण के लिए, 1011 का एक मंत्र वास्तव में 1.1011 है।

यह तुलना के साथ कुछ मुद्दों का कारण बन सकता है, 0 के साथ Essp तौर पर 0 से संभवतः एक फ्लोट में बिल्कुल प्रतिनिधित्व नहीं किया जा सकता है। यह मुख्य कारण == हतोत्साहित किया जाता है, इसके अलावा अन्य उत्तरों द्वारा वर्णित फ्लोटिंग पॉइंट गणित मुद्दों के अलावा।

जावा में एक अनोखी समस्या है कि भाषा कई अलग-अलग प्लेटफार्मों पर सार्वभौमिक है, जिनमें से प्रत्येक का अपना अनूठा फ़्लोट प्रारूप हो सकता है। इससे == बचना और भी महत्वपूर्ण हो जाता है।

समानता के लिए दो झांकियों (नहीं भाषा विशिष्ट मन) की तुलना करने का उचित तरीका इस प्रकार है:

if(ABS(float1 - float2) < ACCEPTABLE_ERROR)
    //they are approximately equal

जहां ACCEPTABLE_ERROR #defined है या 0.000000001 के बराबर कुछ अन्य स्थिरांक या जो भी सटीकता की आवश्यकता है, वह पहले से ही स्वागत योग्य है।

कुछ भाषाओं में यह कार्यक्षमता है या यह निरंतर निर्मित है, लेकिन आमतौर पर यह एक अच्छी आदत है।


3
जावा में फ्लोट्स के लिए एक परिभाषित व्यवहार है। यह मंच पर निर्भर नहीं है।
यिशै

9

आज के रूप में, यह करने के लिए त्वरित और आसान तरीका है:

if (Float.compare(sectionID, currentSectionID) == 0) {...}

हालाँकि, डॉक्स स्पष्ट रूप से मार्जिन अंतर ( @Victor के उत्तर से एक एप्सिलॉन ) के मूल्य को निर्दिष्ट नहीं करता है जो हमेशा फ़्लोट पर गणना में मौजूद होता है, लेकिन यह कुछ उचित होना चाहिए क्योंकि यह मानक भाषा पुस्तकालय का एक हिस्सा है।

फिर भी यदि एक उच्च या अनुकूलित परिशुद्धता की आवश्यकता है, तो

float epsilon = Float.MIN_NORMAL;  
if(Math.abs(sectionID - currentSectionID) < epsilon){...}

एक और समाधान विकल्प है।


1
डॉक्स जिसे आपने लिंक किया था "मान 0 अगर एफ 1 संख्यात्मक रूप से एफ 2 के बराबर है" जो इसे वही करता है (sectionId == currentSectionId)जो फ्लोटिंग पॉइंट के लिए सटीक नहीं है। एप्सिलॉन विधि बेहतर दृष्टिकोण है, जो इस उत्तर में है: stackoverflow.com/a/1088271/4212710
टाइपोप्रॉप

8

राउंडऑफ़ त्रुटि के कारण फ़ोटिंग पॉइंट मान विश्वसनीय नहीं हैं।

के रूप में इस तरह वे शायद खंड के रूप में प्रमुख मूल्यों के लिए इस्तेमाल नहीं किया जाना चाहिए। इसके बजाय पूर्णांक का उपयोग करें, या longयदि intसंभव संभव मान नहीं है।


2
माना। यह देखते हुए कि ये आईडी हैं, फ्लोटिंग पॉइंट अंकगणित के साथ चीजों को जटिल करने का कोई कारण नहीं है।
योहानी

2
या एक लंबा। भविष्य में कितने विशिष्ट आईडी प्राप्त होते हैं, इस पर निर्भर करते हुए, एक इंट काफी बड़ा नहीं हो सकता है।
वेन हार्टमैन

फ्लोट की तुलना में डबल कितना सटीक है?
अरविंद मणि

1
@ArvindhMani doubleरों बहुत अधिक सटीक हैं, लेकिन वे भी अंक मान तैर रहे हैं, तो मेरा उत्तर दोनों शामिल करना चाहिए था floatऔर double
एरिक विल्सन

7

पिछले उत्तरों के अलावा, आपको पता होना चाहिए कि ( -0.0fऔर +0.0fवे ==नहीं हैं equals) के साथ जुड़े अजीब व्यवहार हैं और Float.NaN(यह है, equalsलेकिन नहीं ==) (आशा है कि मुझे वह सही है - argh, यह मत करो!)।

संपादित करें: चलो जाँच करें!

import static java.lang.Float.NaN;
public class Fl {
    public static void main(String[] args) {
        System.err.println(          -0.0f   ==              0.0f);   // true
        System.err.println(new Float(-0.0f).equals(new Float(0.0f))); // false
        System.err.println(            NaN   ==               NaN);   // false
        System.err.println(new Float(  NaN).equals(new Float( NaN))); // true
    }
} 

IEEE / 754 में आपका स्वागत है।


यदि कुछ == है, तो वे बिट के समान हैं। उनकी बराबरी कैसे नहीं हो सकती ()? हो सकता है कि आपके पास यह पीछे की ओर हो?
mkb

@Matt NaN खास है। जावा में Double.isNaN (डबल x) वास्तव में {return x! = X के रूप में कार्यान्वित किया जाता है; } ...
क्वांट_देव

1
फ्लोट्स के साथ, ==इसका मतलब यह नहीं है कि संख्या "बिट के समान है" (समान संख्या को विभिन्न बिट पैटर्न के साथ दर्शाया जा सकता है, हालांकि उनमें से केवल एक ही सामान्यीकृत रूप है)। के रूप में अच्छी तरह से, -0.0fऔर 0.0fविभिन्न बिट पैटर्न (संकेत बिट अलग है) द्वारा प्रतिनिधित्व किया जाता है, लेकिन साथ बराबर ==(लेकिन नहीं के साथ equals) की तुलना करें । आपकी धारणा जो कि ==बिटवाइस की तुलना है, सामान्यतया गलत है।
पावेल मिनाएव

6

इस बारे में बहुत लंबी (लेकिन उम्मीद है कि उपयोगी) चर्चा है और कई अन्य फ़्लोटिंग पॉइंट मुद्दे आपके सामने आ सकते हैं: फ्लोटिंग-पॉइंट अंकगणित के बारे में हर कंप्यूटर वैज्ञानिक को क्या पता होना चाहिए


5

आप Float.floatToIntBits () का उपयोग कर सकते हैं।

Float.floatToIntBits(sectionID) == Float.floatToIntBits(currentSectionID)

1
आप सही रास्ते पर हैं। floatToIntBits () जाने का सही तरीका है, लेकिन फ्लोट के बिल्ट इन बराबरी () फ़ंक्शन का उपयोग करना आसान होगा। यहाँ देखें: stackoverflow.com/a/3668105/2066079 । आप देख सकते हैं कि डिफ़ॉल्ट बराबरी () फ्लोटटाइऑनबीट्स का आंतरिक रूप से उपयोग करता है।
dberm22

1
हां अगर वे फ्लोट ऑब्जेक्ट हैं। आप प्राइमरी के लिए उपरोक्त समीकरण का उपयोग कर सकते हैं।
आमदमी

4

सबसे पहले, वे फ्लोट या फ्लोट हैं? यदि उनमें से एक फ्लोट है, तो आपको बराबर () विधि का उपयोग करना चाहिए। इसके अलावा, स्थैतिक फ्लोट.कॉमप विधि का उपयोग करने के लिए शायद सबसे अच्छा।


4

निम्नलिखित स्वचालित रूप से सर्वोत्तम परिशुद्धता का उपयोग करता है:

/**
 * Compare to floats for (almost) equality. Will check whether they are
 * at most 5 ULP apart.
 */
public static boolean isFloatingEqual(float v1, float v2) {
    if (v1 == v2)
        return true;
    float absoluteDifference = Math.abs(v1 - v2);
    float maxUlp = Math.max(Math.ulp(v1), Math.ulp(v2));
    return absoluteDifference < 5 * maxUlp;
}

बेशक, आप 5 से अधिक ULP ('अंतिम स्थान पर इकाई') चुन सकते हैं।

आप अपाचे कॉमन्स पुस्तकालय में कर रहे हैं, Precisionवर्ग है compareTo()और equals()दोनों एप्सिलॉन और ULP साथ।


जब फ्लोट को डबल में बदलते हुए, यह विधि isDoubleEqual (0.1 + 0.2-0.3, 0.0) == असत्य के रूप में काम नहीं करती है
hychou

ऐसा लगता है कि आपको इसे doubleकवर करने के लिए 10_000_000_000_000_000L जैसे कारक की आवश्यकता है ।
माइकल पीफेल


3

यदि आपके पास * फ़्लैट का उपयोग करना है, तो सख्त कीवर्ड उपयोगी हो सकता है।

http://en.wikipedia.org/wiki/strictfp


या विभिन्न आर्किटेक्चर के लिए और भी अधिक उपयोगी हो सकता है।
जॉय रोहन

2

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


2

क्या आप आउटसोर्स कोड के साथ काम कर रहे हैं जो कि सेक्शनिड और करंटसाइड नाम की चीजों के लिए फ्लोट्स का उपयोग करेगा? बस उत्सुक।

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


1

जैसा कि अन्य उत्तरों में बताया गया है, डबल्स में छोटे विचलन हो सकते हैं। और आप "स्वीकार्य" विचलन का उपयोग करके उनकी तुलना करने के लिए अपनी खुद की विधि लिख सकते हैं। तथापि ...

युगल की तुलना करने के लिए एक अपाचे वर्ग है: org.apache.commons.math3.util.Preaches

इसमें कुछ दिलचस्प स्थिरांक शामिल हैं: SAFE_MINऔर EPSILON, जो साधारण अंकगणितीय संचालन के अधिकतम संभव विचलन हैं।

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


1

एक पंक्ति में उत्तर मैं कह सकता हूं, आपको उपयोग करना चाहिए:

Float.floatToIntBits(sectionID) == Float.floatToIntBits(currentSectionID)

आपको संबंधित ऑपरेटरों का सही तरीके से उपयोग करने के बारे में अधिक जानने के लिए, मैं यहां कुछ मामलों को विस्तृत कर रहा हूं: आम तौर पर, जावा में स्ट्रिंग्स का परीक्षण करने के तीन तरीके हैं। आप ==, .equals (), या Objects.equals () का उपयोग कर सकते हैं।

वे कैसे अलग हैं? == स्ट्रिंग्स में संदर्भ गुणवत्ता के लिए परीक्षण का अर्थ यह पता लगाना है कि क्या दोनों वस्तुएं समान हैं। दूसरी ओर, असमानता () परीक्षण करती है कि क्या दो तार तार्किक रूप से समान मूल्य के हैं। अंत में, दो स्ट्रिंग्स में किसी भी नल के लिए Objects.equals () परीक्षण फिर निर्धारित करते हैं कि क्या .equals () को कॉल करें।

उपयोग करने के लिए आदर्श ऑपरेटर

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

हालाँकि, आपको जो मिलता है वह एक गिरता हुआ मूल्य है क्योंकि जावा एक भ्रम पैदा करता है कि आप मूल्यों की तुलना कर रहे हैं लेकिन वास्तविक अर्थों में आप नहीं हैं। नीचे दो मामलों पर विचार करें:

मामला एक:

String a="Test";
String b="Test";
if(a==b) ===> true

केस 2:

String nullString1 = null;
String nullString2 = null;
//evaluates to true
nullString1 == nullString2;
//throws an exception
nullString1.equals(nullString2);

इसलिए, प्रत्येक ऑपरेटर का उपयोग करना बेहतर होता है जब इसके लिए डिज़ाइन की गई विशिष्ट विशेषता का परीक्षण किया जाता है। लेकिन लगभग सभी मामलों में, Objects.equals () एक अधिक सार्वभौमिक ऑपरेटर है, इस प्रकार वेब डेवलपर इसका अनुभव करते हैं।

यहाँ आप अधिक जानकारी प्राप्त कर सकते हैं: http://fluentthemes.com/use-compare-strings-java/


-2

सही तरीका होगा

java.lang.Float.compare(float1, float2)

7
Float.compare (float1, float2) एक इंट लौटाता है, इसलिए इसे ifat1 == float2 के बजाय ifat कंडीशन में उपयोग नहीं किया जा सकता है। इसके अलावा, यह वास्तव में अंतर्निहित समस्या को हल नहीं करता है जो इस चेतावनी का उल्लेख कर रहा है - कि अगर फ्लोट संख्यात्मक गणना के परिणाम हैं, float1! = Float2 केवल राउंडिंग त्रुटियों के कारण हो सकता है।
क्वांट_देव

1
दाईं ओर, आप पेस्ट कॉपी नहीं कर सकते हैं, आपको पहले डॉक्टर की जांच करनी होगी।
एरिक

2
आप float1 के बजाय क्या कर सकते हैं == float2 Float.compare (फ्लोट 1, फ्लोट 2) == 0.
deterb

29
यह आपको कुछ भी नहीं खरीदता है - आप अभी भी मिलते हैंFloat.compare(1.1 + 2.2, 3.3) != 0
पावेल मिनावे

-2

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

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