जब जावा को बाइट में परिवर्तित किया जाता है तो अजीब व्यवहार?


130
int i =132;

byte b =(byte)i; System.out.println(b);

डरावना। आउटपुट क्यों है -124?

जवाबों:


172

जावा में, एक int32 बिट्स है। A byte8 है bits

जावा में सबसे आदिम प्रकार प्रवेश किया हुआ है, और byte, short, int, और longदो के पूरक में इनकोड। ( charप्रकार अहस्ताक्षरित है, और एक संकेत की अवधारणा इसके लिए लागू नहीं है boolean।)

इस संख्या योजना में सबसे महत्वपूर्ण बिट संख्या के संकेत को निर्दिष्ट करता है। यदि अधिक बिट्स की आवश्यकता होती है, तो सबसे महत्वपूर्ण बिट ("एमएसबी") बस नए एमएसबी में कॉपी किया जाता है।

इसलिए यदि आपके पास बाइट है 255: 11111111 और आप इसे एक int(32 बिट्स) के रूप में प्रस्तुत करना चाहते हैं तो आप बस 1 को बाएं 24 बार कॉपी करते हैं।

अब, एक नकारात्मक दो की पूरक संख्या को पढ़ने का एक तरीका कम से कम महत्वपूर्ण बिट के साथ शुरू करना है, बाएं चलना जब तक आप पहले 1 को नहीं पाते हैं, तब तक प्रत्येक बिट को उल्टा कर दें। परिणामी संख्या उस संख्या का सकारात्मक संस्करण है

उदाहरण के लिए: = पर 11111111जाता है । यह वह है जो जावा मान के रूप में प्रदर्शित करेगा।00000001-1

जो आप शायद करना चाहते हैं, वह बाइट का अहस्ताक्षरित मूल्य है।

आप इसे एक बिटमास्क के साथ पूरा कर सकते हैं जो सब कुछ हटा देता है लेकिन कम से कम महत्वपूर्ण 8 बिट्स। (0xff)

इसलिए:

byte signedByte = -1;
int unsignedByte = signedByte & (0xff);

System.out.println("Signed: " + signedByte + " Unsigned: " + unsignedByte);

प्रिंट आउट होगा: "Signed: -1 Unsigned: 255"

वास्तव में यहां क्या हो रहा है?

हम बिटविन एंड का उपयोग कर रहे हैं और सभी बाहरी साइन बिट्स (कम से कम 8 महत्वपूर्ण बिट्स में से 1 के बाईं ओर) को मास्क करने के लिए। जब ​​एक इंट एक बाइट में परिवर्तित होता है, तो जावा सबसे बाएं 24 बिट्स को काट देता है।

1111111111111111111111111010101
&
0000000000000000000000001111111
=
0000000000000000000000001010101

चूँकि 32 वां बिट अब 8 बिट के बजाय साइन बिट है (और हम साइन बिट को 0 पर सेट करते हैं जो सकारात्मक है), बाइट से मूल 8 बिट्स को पॉजिटिव मान के रूप में जावा द्वारा पढ़ा जाता है।


1
अच्छी तरह से किया, इस विषय पर सबसे अच्छा विवरण, वेन! मैं सिर्फ गणित की औपचारिकता की तलाश कर रहा हूं कि दो के पूरक प्रतिनिधित्व में बिट को जोड़ने के लिए साइन बिट को दाईं ओर कॉपी किया जा सकता है। यह समझना आसान है कि किसी नियम को कैसे प्राप्त किया जाए। वह है: दाईं से बाईं ओर के सभी बिट्स पर विचार करें और उन्हें पहले 1 तक अपरिवर्तित लिखें। फिर बाद के बिट्स को उल्टा करें। यदि मैं लापता बिट को 0s मानता हूं, तो यह समझना आसान है कि वे सभी 1 पर जाते हैं। लेकिन मैं अधिक 'गणित' स्पष्टीकरण की तलाश कर रहा था।
एगोस्टीनोएक्स

व्हाट हैपनिंग यहाँ signedByte & (0xff)एक इंटरफेरल 0xffशाब्दिक है, इस प्रकार हस्ताक्षर किए गए बिट को ऑपरेशन के पूर्ण होने से पहले एक पूर्णांक में पदोन्नत कर दिया जाता है।
केविन व्हीलर

यह 0xFF नहीं है, यह आपके उदाहरण में 0x7E है!
जॉनीटेक्स

89

132अंकों में ( आधार 10 ) 1000_0100बिट्स ( बेस 2 ) और जावा स्टोर में हैint 32 बिट्स में है:

0000_0000_0000_0000_0000_0000_1000_0100

इंट-टू-बाइट के लिए एल्गोरिदम बाएं-छोटा है; के लिए एल्गोरिथ्म System.out.printlnहै two's-पूरक (Two's-पूरक अगर वाम-पंथी सा है 1, नकारात्मक रूप में व्याख्या one's-पूरक (बिट्स की विपरीत) शून्य से एक।); इस प्रकार System.out.println(int-to-byte( ))है:

  • व्याख्या-के रूप में (यदि-सबसे बाईं ओर-बिट -1 [नकारात्मक (इनवर्ट-बिट्स (माइनस-वन)) बाएं-ट्रंकट (0000_0000_0000_0000_0000_0000_1000_0100 ) [)))])
  • = व्याख्या-के रूप में (यदि-वाम-बिट-is-1 [नकारात्मक (इनवर्ट-बिट्स (माइनस-वन)] 1000_0100 ) [))]]
  • = व्याख्या-के रूप में (नकारात्मक (उलट-बिट्स (शून्य से एक (1000_0100 ))))
  • = व्याख्या-के रूप में (नकारात्मक (उलट-बिट्स (1000_0011 )))
  • = व्याख्या-के रूप में (नकारात्मक (0111_1100 ))
  • = व्याख्या-के रूप में (नकारात्मक (124))
  • = व्याख्या-के रूप में (-124)
  • = -124 टाडा !!!

7
बहुत अच्छी तरह से समझाया
ZAJ

1
तो अब दशमलव में 132 बाइट में -124 है। रिवर्स कैसे काम करता है?
निलेश देओकर

@ निलेशडेकर, पोला द्वारा उलटा है क्योंकि वे फिट हैं (; cf JLS 5.1.2 ); उत्पादन साइन-लेफ्टपैड ( 0सकारात्मक और 1नकारात्मक के लिए) के साथ मेल खाता है ।
पचेरियर

POLA क्या है? intएक से रूपांतरण byteएक हानिपूर्ण रूपांतरण है (यानी जानकारी खो जाती है)। इसलिए, इसे वापस अपने मूल intमूल्य में बदलने का कोई तरीका नहीं है ।
14

23

जावा में बाइट पर हस्ताक्षर किए गए हैं, इसलिए इसकी सीमा -2 ^ 7 से 2 ^ 7-1 - यानी -128 से 127 है। चूंकि 132 127 से ऊपर है, आप अंत में 132-256 = -124 के आसपास लपेटते हैं। अर्थात अनिवार्य रूप से 256 (2 ^ 8) को जोड़ा या घटाया जाता है जब तक कि यह सीमा में न आ जाए।

अधिक जानकारी के लिए, आप दो के पूरक पर पढ़ना चाह सकते हैं ।


16

132 एक बाइट की सीमा के बाहर है जो -128 से 127 (बाइट.मिन_वैल्यू से बाइट.मैक्स_वैल्यू) है इसके बजाय 8-बिट मान के शीर्ष बिट को हस्ताक्षरित माना जाता है जो इंगित करता है कि यह इस मामले में नकारात्मक है। तो संख्या 132 - 256 = -124 है।


5

यहाँ विचलित सिद्धांतों के बिना एक बहुत ही यांत्रिक विधि है:

  1. संख्या को बाइनरी प्रतिनिधित्व में परिवर्तित करें (कैलकुलेटर का उपयोग करें ठीक है?)
  2. केवल सही 8 बिट्स (LSB) की प्रतिलिपि बनाएँ और बाकी को छोड़ दें।
  3. चरण # 2 के परिणाम से, यदि सबसे बाईं ओर 0 है, तो संख्या को दशमलव में बदलने के लिए एक कैलकुलेटर का उपयोग करें। यह आपका जवाब है।
  4. वरना (यदि सबसे बाईं ओर 1 है) तो आपका उत्तर नकारात्मक है। सभी सही शून्य और पहले गैर-शून्य बिट को अपरिवर्तित छोड़ दें। और बाकी को उलट दिया, अर्थात् 1 के 0 से बदल दिया और 0 के 1 के 1 से। फिर दशमलव में कनवर्ट करने के लिए एक कैलकुलेटर का उपयोग करें और मूल्य नकारात्मक है इंगित करने के लिए एक नकारात्मक चिह्न जोड़ें।

यह अधिक व्यावहारिक तरीका ऊपर दिए गए सैद्धांतिक उत्तरों के अनुसार है। इसलिए, वे अभी भी उन जावा पुस्तकों को पढ़ रहे हैं जो मोडुलो का उपयोग करने के लिए कह रहे हैं, यह निश्चित रूप से गलत है क्योंकि मैं ऊपर उल्लिखित 4 चरणों निश्चित रूप से एक मोडुलो ऑपरेशन नहीं हूं।


जावा किताबें 'मोडुलो' का उपयोग करने के लिए क्या कह रही हैं? मैंने कभी भी कोई सीएस पुस्तक नहीं देखी है जो कहती है कि 46 वर्षों में, किसी भी जावा पुस्तक को अकेले छोड़ दें। क्या 'मोडुलो'? जावा में कोई मॉडुलो ऑपरेशन नहीं है। केवल एक शेष ऑपरेटर।
लोर्ने

कड़ा करना http://iiti.ac.in/people/~tanimad/JavaTheCompleteReference.pdfपृष्ठ ५ ९
१४:०४

4

दो के पूरक समीकरण:

यहाँ छवि विवरण दर्ज करें


जावा में, byte(N = 8) और int(N = 32) को ऊपर दिखाए गए 2s-supplement द्वारा दर्शाया गया है।

समीकरण से, एक 7 नकारात्मक है, byteलेकिन सकारात्मक है int

coef:   a7    a6  a5  a4  a3  a2  a1  a0
Binary: 1     0   0   0   0   1   0   0
----------------------------------------------
int:    128 + 0 + 0 + 0 + 0 + 4 + 0 + 0 =  132
byte:  -128 + 0 + 0 + 0 + 0 + 4 + 0 + 0 = -124

2

अक्सर किताबों में आप मॉडुलेट डिवीजन द्वारा किए जा रहे इंट से बाइट के कास्टिंग का विवरण पाएंगे। यह कड़ाई से सही नहीं है जैसा कि नीचे दिखाया गया है कि वास्तव में क्या होता है इंट संख्या के द्विआधारी मूल्य से 24 सबसे महत्वपूर्ण बिट्स को भ्रम छोड़ दिया जाता है यदि शेष बाईं ओर का बिट सेट होता है जो संख्या को नकारात्मक के रूप में नामित करता है

public class castingsample{

public static void main(String args[]){

    int i;
    byte y;
    i = 1024;
    for(i = 1024; i > 0; i-- ){

      y = (byte)i;
      System.out.print(i + " mod 128 = " + i%128 + " also ");
      System.out.println(i + " cast to byte " + " = " + y);

    }

}

}

2
मैंने 46 साल में कभी किसी किताब में ऐसा नहीं देखा।
लोर्ने

2

एक त्वरित एल्गोरिथ्म जो इस तरह से काम करता है कि निम्नलिखित अनुकरण करता है:

public int toByte(int number) {
    int tmp = number & 0xff
    return (tmp & 0x80) == 0 ? tmp : tmp - 256;
}

यह कैसा काम? देखो daixtr जवाब। उनके उत्तर में उल्लिखित सटीक एल्गोरिदम का कार्यान्वयन निम्नलिखित है:

public static int toByte(int number) {
    int tmp = number & 0xff;
    if ((tmp & 0x80) == 0x80) {
        int bit = 1;
        int mask = 0;
        for(;;) {
            mask |= bit;
            if ((tmp & bit) == 0) {
                bit <<=1;
                continue;
            }
            int left = tmp & (~mask);
            int right = tmp & mask;
            left = ~left;
            left &= (~mask);
            tmp = left | right;
            tmp = -(tmp & 0xff);
            break;
        }
    }
    return tmp;
}

1

यदि आप इसे गणितीय रूप से समझना चाहते हैं, जैसे कि यह कैसे काम करता है

इसलिए मूल रूप से b / w -128 से 127 को उनके दशमलव मान के समान लिखा जाएगा, इसके ऊपर (आपकी संख्या - 256)।

जैसे। 132, उत्तर 132 - 256 = - 124 होगा

256 + नंबर + (-124) में आपका जवाब 132 है

एक और उदाहरण

double a = 295.04;
int b = 300;
byte c = (byte) a;
byte d = (byte) b; System.out.println(c + " " + d);

आउटपुट 39 44 होगा

(295 - 256) (300 - 256)

नोट: यह दशमलव के बाद संख्याओं पर विचार नहीं करेगा।


0

अवधारणात्मक रूप से, 256 का बार-बार घटाना आपकी संख्या से बना होता है, जब तक कि यह -128 -127 + की सीमा में न हो। तो आपके मामले में, आप 132 से शुरू करते हैं, फिर एक चरण में -124 के साथ समाप्त होते हैं।

कम्प्यूटेशनल रूप से, यह आपकी मूल संख्या से 8 सबसे कम महत्वपूर्ण बिट्स निकालने से मेल खाती है। (और ध्यान दें कि इन 8 में से सबसे महत्वपूर्ण बिट साइन बिट बन जाता है।)

ध्यान दें कि अन्य भाषाओं में यह व्यवहार परिभाषित नहीं है (उदाहरण C और C ++)।


स्पष्ट होने के लिए, आपको जो परिणाम मिलता है वह वैसा ही होता है जैसे कि बार-बार घटाया गया हो। व्यवहार में, जेवीएम वास्तव में इस तरह से नहीं करता है। (यह बहुत ही अयोग्य होगा!)
स्टीफन सी।

वास्तव में। मुझे उम्मीद है कि मेरा दूसरा पैराग्राफ कवर करता है कि जेवीएम वास्तव में ऐसा कैसे करता है। लेकिन मैंने अपनी भाषा के साथ थोड़ी सी फीलिंग की है।
बथशेबा

1
हाँ। "अनिवार्य रूप से" "वैचारिक रूप से" का परिवर्तन एक बड़ा अंतर बनाता है!
स्टीफन सी।

-1
 N is input number
case 1: 0<=N<=127  answer=N;
case 2: 128<=N<=256 answer=N-256 
case 3: N>256   
        temp1=N/256;
        temp2=N-temp*256;
        if temp2<=127   then answer=temp2;
        else if temp2>=128  then answer=temp2-256;
case 4: negative  number input
        do same procedure.just change the sign of the solution           

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