2010-11-04 17 views
10

यह आईईईई 754 मानक प्रश्न है। मैं इसके पीछे यांत्रिकी को पूरी तरह से समझ नहीं पा रहा हूं।यह सच क्यों है?

public class Gray { 
    public static void main(String[] args){ 
     System.out.println((float) (2000000000) == (float) (2000000000 + 50)); 
    } 
} 
+6

वैसे, इस "समस्या" जावा तक सीमित नहीं है; आईईईई 754 मानक द्वारा परिभाषित अनुसार, बाइनरी में फ्लोट्स का प्रतिनिधित्व कैसे किया जाता है इसके साथ यह करना है। –

उत्तर

29

क्योंकि एक float ही के बारे में 7 से 8 महत्वपूर्ण अंक पकड़ कर सकते हैं।

  • संकेत बिट (1 बिट: यह एक float तीन हिस्से होते हैं यह वास्तव में संख्या २०००००००५० का प्रतिनिधित्व करने के लिए पर्याप्त बिट्स नहीं है, है, इसलिए यह 2000000000.

    विशेष रूप से बोल तक पूर्ण हो जाता है,)

  • प्रतिपादक (8 बिट)
  • significand (24 बिट, लेकिन केवल 23 बिट्स significand की MSB के बाद से जमा हो जाती है हमेशा 1 है)

आप टी कर सकते हैं कम्प्यूटर के तरीके के रूप में फ्लोटिंग पॉइंट का संकेत वैज्ञानिक संकेत कर रहा है, लेकिन बाइनरी में।

परिशुद्धताlog(2^number of significand bits) के बराबर है। इसका मतलब है कि floatlog(2^24) = 7.225 महत्वपूर्ण अंक रख सकता है।

संख्या 2,000,000,050 में 9 महत्वपूर्ण अंक हैं। उपर्युक्त गणना हमें बताती है कि 24-बिट महत्व और कई महत्वपूर्ण अंक नहीं रख सकते हैं। कारण 2,000,000,000 काम करता है क्योंकि केवल 1 महत्वपूर्ण अंक है, इसलिए यह महत्व में फिट बैठता है।

समस्या को हल करने के लिए, आप double का उपयोग करेंगे क्योंकि इसमें 52-बिट महत्व है, जो हर संभव 32-बिट संख्या का प्रतिनिधित्व करने के लिए पर्याप्त है।

+0

मुझे यह कथन नहीं समझा: कारण 2,000,000,000 काम करता है क्योंकि केवल 1 महत्वपूर्ण अंक है, इसलिए यह महत्व में फिट बैठता है। – fabrizioM

+0

@fabrizioM: क्या आप समझते हैं कि संख्या 2,000,000,000 में केवल 1 महत्वपूर्ण अंक है, लेकिन संख्या 2,000,000,050 में 9 महत्वपूर्ण अंक हैं? –

+0

ठीक है इसलिए 2^9 (2 = महत्व 2 बिट्स) में विभाजित है (9 = एक्सपोनेंट 4 बिट्स) – fabrizioM

3

सादा ने कहा - 50 एक गोलिंग त्रुटि है जब एक फ्लोट के पास दो अरब का मूल्य होता है।

+1

सादा, लेकिन गलत तरीके से :-) –

+0

@ स्टीफन - क्या आप विस्तार से बता सकते हैं? –

+1

क्योंकि 50 बस संख्या 50 है। क्योंकि वास्तविक राउंडिंग त्रुटियां '200000000.0' और' असली ((फ्लोट) 200000000) और '200000050.0' और' असली ((फ्लोट) 200000050 के बीच अंतर 'हैं। –

2

यदि आप नीचे एक प्रोग्राम (सी ++) मानते हैं तो यह स्थिति को समझने में आपकी मदद कर सकता है। यह लगातार पूर्णांकों के समूह है कि एक ही नाव मूल्य के लिए गोल करने के प्रदर्शित करता है:

#include <iostream>                
#include <iomanip>                

int main()                  
{                    
    float prev = 0;                
    int count = 0;                
    double from;                 
    for (double to = 2000000000 - 150; count < 10; to += 1.0)     
    {                   
     float now = to;               
     if (now != prev)               
     {                  
      if (count)               
       std::cout << std::setprecision(20) << from << ".." << to - 1 << " ==> " << prev << '\n';               
      prev = now;               
      from = to;               
      ++count;                
     }                  
    }                   
} 

आउटपुट:

1999999850..1999999935 ==> 1999999872 
1999999936..2000000064 ==> 2000000000 
2000000065..2000000191 ==> 2000000128 
2000000192..2000000320 ==> 2000000256 
2000000321..2000000447 ==> 2000000384 
2000000448..2000000576 ==> 2000000512 
2000000577..2000000703 ==> 2000000640 
2000000704..2000000832 ==> 2000000768 
2000000833..2000000959 ==> 2000000896 

यह बताता है कि चल बिन्दु केवल पर्याप्त सटीक 1999999935 करने के लिए 1999999850 से सभी पूर्णांकों का प्रतिनिधित्व करने के लिए है, गलत रूप से उनके मूल्य को 199 99 99872 के रूप में रिकॉर्ड कर रहा है। तो अन्य मूल्यों के लिए। यह उपर्युक्त सीमित भंडारण स्थान का वास्तविक परिणाम है।

+0

प्रश्न टैग नहीं किया गया है C++ – JeremyP

+0

@ जेरेमीपी: मुझे पता है, लेकिन फ्लोटिंग पॉइंट प्रारूप आमतौर पर हार्डवेयर आधार पर मानकीकृत होते हैं और इसलिए भाषाओं में आम हैं, अवधारणाओं को लागू करते हैं। मैं बस सी ++ पसंद करता हूं और जावा नहीं जानता। –

+0

हां, लेकिन जावा प्रोग्रामर को यह जानने के लिए उचित नहीं है कि 'std :: cout << something' जैसी चीजें वास्तव में क्या हैं। – JeremyP

3

आपको यह अनुमान मिल सकता है कि अगले प्रतिनिधित्व योग्य मूल्य दिलचस्प हो।

float f = 2000000000; 
int binaryValue = Float.floatToRawIntBits(f); 
int nextBinaryValue = binaryValue+1; 
float nextFloat = Float.intBitsToFloat(nextBinaryValue); 
System.out.printf("The next float value after %.0f is %.0f%n", f, nextFloat); 

double d = 2000000000; 
long binaryValue2 = Double.doubleToRawLongBits(d); 
long nextBinaryValue2 = binaryValue2+1; 
double nextDouble = Double.longBitsToDouble(nextBinaryValue2); 
System.out.printf("The next double value after %.7f is %.7f%n", d, nextDouble); 

प्रिंट

The next float value after 2000000000 is 2000000128 
The next double value after 2000000000.0000000 is 2000000000.0000002 
+0

साफ। लगता है कि int (कम से कम सिलिको के जवाब में) int पर कम से कम महत्वपूर्ण बिट्स में निर्भर करता है। मुझे यकीन नहीं है कि यह विभिन्न आर्किटेक्चर पर कैसे निर्भर करता है, लेकिन शायद जावा लगातार इसे संभालता है? –

+0

यह सभी आईईईई फ्लोटिंग पॉइंट के लिए सच होना चाहिए। –

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