2012-10-26 17 views
7

मैं समझने के लिए जावा double प्रकार जावा में स्मृति में अपने मूल्य स्टोर करेगा चाहते हैं। जब मैं निम्नलिखित कोड चलाने मैं अप्रत्याशित आउटपुट प्राप्त:अप्रत्याशित व्यवहार

public static void main(String[] args) { 

    float a = 1.5f; 
    float b= 0.5f; 
    double c= 1.5; 
    double d = 0.5; 

    float a1 = 1.4f; 
    float b1= 0.5f; 
    double c1= 1.4; 
    double d1 = 0.5; 

    System.out.println(" a- b is " + (a-b)); 
    System.out.println(" c- d is " + (c-d)); 
    System.out.println("a1-b1 is " + (a1-b1)); 
    System.out.println("c1-d1 is " + (c1-d1)); 

}

आउटपुट:

 
a- b is 1.0 
c- d is 1.0 
a1-b1 is 0.9 
c1-d1 is 0.8999999999999999 

c1-d10.9 के बराबर नहीं क्यों है?

मैं भी अन्य विभिन्न मूल्यों की कोशिश की लेकिन कुछ समय यह नहीं उम्मीद परिणाम और कुछ समय लौटें।

+4

इसी http://stackoverflow.com/questions/322749/retain-precision-with-doubles-in-java – tjg184

+1

इसमें http मदद मिल सकती है: //epramono.blogspot .com/2005/01/double-vs-bigdecimal.html – kosa

+0

यह भी देखें http://mindprod.com/jgloss/floatingpoint.html –

उत्तर

3

जबकि आपने त्रुटियों को गोल करने के बारे में सुना होगा, तो हो सकता है कि आप सोच रहे हों कि आपको यहां एक गोल करने की त्रुटि क्यों है।

float a1 = 1.4f; 
float b1 = 0.5f; 
double c1 = 1.4; 
double d1 = 0.5; 

System.out.println(new BigDecimal(a1) + " - " + new BigDecimal(b1) + " is " + 
     new BigDecimal(a1).subtract(new BigDecimal(b1)) + " or as a float is " + (a1 - b1)); 
System.out.println(new BigDecimal(c1) + " - " + new BigDecimal(d1) + " is " + 
     new BigDecimal(c1).subtract(new BigDecimal(d1)) + " or as a double is " + (c1 - d1)); 

प्रिंट

1.39999997615814208984375 - 0.5 is 0.89999997615814208984375 or as a float is 0.9 
1.399999999999999911182158029987476766109466552734375 - 0.5 is 
    0.899999999999999911182158029987476766109466552734375 
    or as a double is 0.8999999999999999 

आप देख सकते हैं, न तो float है और न ही double वास्तव में इन मूल्यों का प्रतिनिधित्व कर सकते हैं, और जब नाव या डबल छपा है, कुछ राउंडिंग आप से छिपाने के लिए होता है। फ्लोट के इस मामले में, 7 दशमलव स्थानों पर गोल करने से आपके द्वारा अपेक्षित संख्या उत्पन्न होती है। डबल के मामले में जिसमें परिशुद्धता के 16 अंक हैं, राउंडिंग त्रुटि दिखाई दे रही है।

@Eric Postpischil के रूप में, नोटों float या double आपरेशन एक गोलाई त्रुटि है कि क्या पूरी तरह से इस्तेमाल किया मूल्यों पर निर्भर करता है। इस स्थिति में, यह फ्लोट था जो प्रतिनिधित्व मूल्य के माध्यम से भी अधिक सटीक प्रतीत होता था, दो अंकों से 0.9 से आगे था।

संक्षेप में: यदि आप float या double का उपयोग करने जा रहे हैं तो आपको एक समझदार गोल रणनीति का उपयोग करना चाहिए। यदि आप ऐसा नहीं कर सकते हैं, तो BigDecimal का उपयोग करें।

System.out.printf("a1 - b1 is %.2f%n", (a1 - b1)); 
System.out.printf("c1 - d1 is %.2f%n", (c1 - d1)); 

प्रिंट

a1 - b1 is 0.90 
c1 - d1 is 0.90 

जब आप एक नाव या डबल प्रिंट, यह मानता है कि निकटतम लघु दशमलव मान एक तुम सच में चाहते हैं। यानी 0.5 उल के भीतर।

उदा।

double d = 1.4 - 0.5; 
float f = d; 
System.out.println("d = " + d + " f = " + f); 

प्रिंट

d = 0.8999999999999999 f = 0.9 
+2

वाक्य "डबल के मामले में जिसमें परिशुद्धता के 16 अंक हैं, राउंडिंग त्रुटि दिखाई दे रही है" सुझाव देता है कि डबल मान अधिक अंकों के साथ प्रदर्शित किया गया था क्योंकि डबल में अधिक सटीकता है। बात वह नहीं है। प्रत्येक प्रकार के लिए, फ्लोट और डबल, चाहे घटाने का परिणाम .5 भी सटीक परिणाम (जब मूल अंक का उपयोग किया जाता है) के निकट प्रतिनिधित्व मूल्य है प्रभावी ढंग से होता है। यह एक कार्य है कि गोलियों की स्थिति का पालन करने के लिए बिट्स क्या होता है, न कि कितने बिट्स का उपयोग किया जाता है। उदाहरण के लिए, "1.2f - .5f" और "1.2 - .5" आज़माएं। –

+0

@EricPostpischil धन्यवाद। जैसा कि लिखा गया था, यह स्पष्ट नहीं था कि मेरा क्या मतलब था। –

1

println के लिए जावा प्रलेखन toString के लिए प्रलेखन में (कई लिंक के माध्यम से) संदर्भित करता है। documentation for toString का कहना है कि float या double के लिए मुद्रित अंकों की संख्या संख्या अनन्य एक ही प्रकार के लिए निकटवर्ती प्रदर्शनीय मूल्यों से मूल्य भेद करने के लिए की जरूरत है।

जब "1.4 एफ" फ्लोट में परिवर्तित हो जाता है, तो परिणाम 1.399 99 997615814208984375 (हेक्साडेसिमल फ़्लोटिंग पॉइंट, 0x1.666666p + 0 में) होता है। जब .5 घटाया जाता है, परिणाम .89999997615814208984375 (0x1.ccccccp -1) है। जैसे ही होता है, यह फ्लोट भी फ्लोट है जो 9 के करीब है। इसलिए, जब इसे मुद्रित किया जाता है, तो ".9" मुद्रित होता है।

जब "1.4" को दो बार परिवर्तित किया जाता है, तो परिणाम 1.3 99 99 99 99 99 99 991111182158029987476766109466552734375 (0x1.6666666666666p + 0) होता है। जब .5 घटाया जाता है, परिणाम 0.899999999999999911182158029987476766109466552734375 (0x1.cccccccccccccp -1) है। यह नहीं है जो कि 9 00 के करीब है, 0.90000000000000002220446049250313080847263336181640625 (0x1.ccccccccccccdp-1) करीब है। इसलिए, जब यह छपा है, जावा विनिर्देश की आवश्यकता है कि मूल्य को और भी बारीकी मुद्रित किया, .9 से यह भेद। परिणाम, "0.8 99 99 99 99 99 99 999", वास्तविक मूल्य का सटीक रूप से प्रतिनिधित्व करता है।

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