2012-05-02 5 views
8

के लिए भिन्न होते हैं निम्नलिखित दो ऑपरेशन जावा में x = 31 या 32 के लिए अलग-अलग परिणाम क्यों प्राप्त करते हैं लेकिन x=3 के लिए समान परिणाम क्यों हैं?जावा परिणाम (int) Math.pow (2, x) और 1 << x

int x=3; 
int b = (int) Math.pow(2,x); 
int c = 1<<x; 

परिणाम:

x=32: b=2147483647; c=1; 
x=31: b=2147483647; c=-2147483648; 
x=3: b=8   ; c=8 
+1

एक सूक्ष्म अंतर यह है कि पॉव() ** बहुत ** धीमा है, भले ही उत्तर समान हो। पाउ() में गोलाकार त्रुटि है, जबकि 'int' में अतिप्रवाह है। आप '1L << 32' का प्रयास कर सकते हैं जो' 2147483648' –

उत्तर

18

चलन प्रक्रिया में कई मुद्दे हैं:

  • एक int कर सकते हैं -2147483648 और 2147483647 के बीच केवल दुकान मूल्यों।
  • 1 << x केवल uses the lowest five bits of x। इस प्रकार, 1 << 32 परिभाषा के अनुसार 1 << 0 है।
  • शिफ्ट ऑपरेशंस two's-complement integer representation of the value of the left operand पर किया जाता है; यह बताता है कि क्यों 1 << 31 नकारात्मक है।
  • Math.pow(2, 32)double देता है।
  • (int)(d), जहां d एक double2147483647 से अधिक रिटर्न है 2147483647 ("the largest representable value of type int")।

क्या इस साक्षात्कार सवाल करता है पता चलता है कि (int)Math.pow(2, x) और 1 << x0 ... 30 सीमा के बाहर x के मूल्यों के लिए बराबर नहीं हैं।

पीएस यह शायद दिलचस्प है कि longint (और 1L1 के स्थान पर) का उपयोग करके अन्य परिणामों से अलग परिणामों का एक और सेट प्रदान करेगा। यह तब भी होता है जब अंतिम परिणाम int में परिवर्तित हो जाते हैं।

+2

विशेष रूप से अंतिम बिंदु बहुत महत्वपूर्ण है। –

2

प्रकार int की सीमा पर विचार करें। यह कितनी बड़ी संख्या में हो सकता है?

+0

के बराबर है। प्रश्न बाएं शिफ्ट और 2. –

+1

की स्पष्ट शक्तियों के बीच अंतर के बारे में है और इस तथ्य को 'int' की सीमा में जोड़ें कि यह एक हस्ताक्षरित प्रकार है। –

3

प्रलेखन के अनुसार Math.pow दोहराए जाने और दोबारा लौटने के लिए अपने दोनों तर्कों को बढ़ावा देगा। जाहिर है जब लौटाया गया परिणाम दोगुना होता है और आप इसे int में डाल देते हैं तो आपको केवल 32 बिट्स मिलेंगे और शेष को छोटा कर दिया जाएगा - इसलिए आपको हमेशा (int) Math.pow(2,x); मान मिलता है। जब आप बिट्सफिफ्ट करते हैं तो आप हमेशा इनट्स के साथ काम करते हैं और इसलिए एक ओवरफ्लो होता है।

+0

मैं मंथिसा के उच्चतम 32 बिट्स का अनुमान लगा रहा हूं। हालांकि मैं गलत हो सकता है। – asenovm

+0

एचएम, ठीक है, यह सच हो सकता है। मुझे बस याद आया कि यह हमेशा '2^31-1' लौटाता है। टिप्पणी हटा दी :) –

0

int आकार में 32 बिट्स है और चूंकि यह हस्ताक्षरित है (डिफ़ॉल्ट रूप से), पहली बिट साइन के लिए उपयोग की जाती है। जब आप बाएं 31 बिट्स को स्थानांतरित करते हैं, तो आपको Two's Compliment मिलता है, जो है - (2^32)। जब आप बाएं 32 बिट्स को स्थानांतरित करते हैं, तो यह लगभग 1 तक वापस आ जाता है। यदि आप इनट्स की बजाय लम्बे समय से स्थानांतरण करना चाहते हैं, तो आपको वह जवाब मिलेंगे जो आप उम्मीद करते हैं (तब तक जब तक आप 63+ बिट्स नहीं बदलते)।

0

यहां लंबे समय के मामले के लिए माइक्रो-बेंचमार्क है। मेरे लैपटॉप (2.8GHz) पर, Math.pow की बजाय शिफ्ट का उपयोग 7x से अधिक तेज है।

int limit = 50_000_000; 
@Test 
public void testPower() { 
    Random r = new Random(7); 
    long t = System.currentTimeMillis(); 
    for (int i = 0; i < limit; i++) { 
     int p = r.nextInt(63); 
     long l = (long)Math.pow(2,p); 
    } 
    long t1 = System.currentTimeMillis(); 
    System.out.println((t1-t)/1000.0); // 3.758 s 
} 
@Test 
public void testShift() { 
    Random r = new Random(7); 
    long t = System.currentTimeMillis(); 
    for (int i = 0; i < limit; i++) { 
     int p = r.nextInt(63); 
     long l = 1L << p; 
    } 
    long t1 = System.currentTimeMillis(); 
    System.out.println((t1-t)/1000.0); // 0.523 s 
}