2017-01-12 10 views
12

मैं कुछ अन्य कोड/मेरी समझ का परीक्षण करने के लिए अनंत लूप बनाने के आसपास झुका रहा था, और इस अजीब व्यवहार में आया। नीचे दिए गए कार्यक्रम में, 0 से 2^24 तक की गिनती < मेरी मशीन पर 100ms लेती है, लेकिन 2^25 की गिनती अधिक समय के आदेश (लेखन के समय, यह अभी भी निष्पादित हो रही है) लेती है।2^24 को गिनती क्यों जल्दी से निष्पादित करती है, लेकिन 2^25 की गिनती बहुत अधिक समय लेती है?

ऐसा क्यों है?

यह जावा 1.8.0_101 के तहत किया गया, विंडोज 10

की एक 64-बिट प्रति पर

TestClass.java

public class TestClass { 
    public static void main(String[] args) { 
     addFloats((float) Math.pow(2.0, 24.0)); 
     addFloats((float) Math.pow(2.0, 25.0)); 
    } 

    private static void addFloats(float number) { 
     float f = 0.0f; 
     long startTime = System.currentTimeMillis(); 

     while(true) { 
      f += 1.0f; 
      if (f >= number) { 
       System.out.println(f); 
       System.out.println(number + " took " + (System.currentTimeMillis() - startTime) + " msecs"); 
       break; 
      } 
     } 
    } 
} 
+0

क्या आपने केवल addFloats ((float) Math.pow (2.0, 25.0)) चलाने की कोशिश की है ?? –

+5

क्योंकि कुछ पल में एफ + 1.0 == एफ। –

+0

@ ओलेगस्टेखिन आह, यह होगा। मैं बेवकूफ़ हूँ। धन्यवाद! –

उत्तर

16

इसका कारण यह है float रों एक न्यूनतम परिशुद्धता कि प्रदर्शित किया जा सकता है, जो float का मान बड़ा हो गया है। कहीं 2^24 और 2^25 के बीच, एक जोड़ना अब अगले सबसे बड़े प्रतिनिधित्व योग्य संख्या में मूल्य बदलने के लिए पर्याप्त नहीं है। उस बिंदु पर, लूप के माध्यम से हर बार, f केवल वही मान रखता है, क्योंकि f += 1.0f अब इसे बदलता नहीं है।

आप इस के लिए अपने पाश को बदलते हैं:

while(true) { 
    float newF = f + 1.0f; 
    if(newF == f) System.out.println(newF); 
    f += 1.0f; 
    if (f >= number) { 
     System.out.println(f); 
     System.out.println(number + " took " + (System.currentTimeMillis() - startTime) + " msecs"); 
     break; 
    } 
} 

आप हो रहा देख सकते हैं। ऐसा लगता है जैसे यह f तक पहुंचता है जैसे ही 2^24 तक पहुंचता है।

यदि आप इसे 2^25 के साथ चलाते हैं तो उपरोक्त कोड का आउटपुट "1.6777216E7" की अंतहीन संख्या होगी।

आप Math.nextAfter function का उपयोग कर इस मूल्य का परीक्षण कर सकते हैं, जो आपको अगले प्रतिनिधित्व योग्य मूल्य बताता है। आप इस कोड चलाने की कोशिश करते हैं:

float value = (float)Math.pow(2.0, 24.0); 
System.out.println(Math.nextAfter(value, Float.MAX_VALUE) - value); 

आप देख सकते हैं कि 2 अगले प्रदर्शनीय मूल्य के बाद^24 2^24 + 2.

क्यों ऐसा होता है की एक उत्कृष्ट विश्लेषण के लिए है, और क्यों यह शुरू होता है इससे कोई फर्क नहीं पड़ता कि यह कहता है, this answer

+5

दूसरे शब्दों में, दूसरा व्यक्ति केवल अधिक समय नहीं लेता है - यह एक अनंत लूप है! – yshavit

+1

जब आप डोमेन में 2^24 से 2^25 तक होते हैं, जहां प्रतिनिधित्व करने योग्य 'फ्लोट' बिल्कुल पूर्णांक होते हैं, जब आप 'f + = 1.0f;' करते हैं, तो सटीक गणितीय परिणाम एक विषम पूर्णांक होगा। चूंकि यह दो निकटतम प्रतिनिधित्व करने योग्य संख्याओं के बीच बिल्कुल सही है, इसलिए अधिकांश कार्यान्वयन [दोगुना भी] (https://en.wikipedia.org/wiki/Singly_and_doubly_even) एक (यानी चार से विभाजित) चुनेंगे। यदि मामला '16777216.0f + 1.0f'' 16777216.0f' (कोई वृद्धि नहीं) होगा, जबकि '16777218.0f + 1.0f'' 16777220.0f' होगा (वास्तविक वृद्धि +2 है)। –

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