簡體   English   中英

Java 將 int 轉換為 byte 時的奇怪行為?

[英]Odd behavior when Java converts int to byte?

int i =132;

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

令人難以置信。 為什么輸出-124

在 Java 中, int是 32 位。 一個byte是 8 bits

Java 中的大多數原始類型都是有符號的,並且byteshortintlong以二進制補碼進行編碼。 char類型是無符號的,符號的概念不適用於boolean 。)

在此數字方案中,最高有效位指定數字的符號。 如果需要更多位,則將最高有效位(“MSB”)簡單地復制到新的 MSB。

因此,如果您有字節255 : 11111111並且您想將其表示為int (32 位),您只需將 1 向左復制 24 次。

現在,讀取負二進制補碼的一種方法是從最低有效位開始,向左移動直到找到第一個 1,然后反轉每一位。 結果數字是該數字的正數

例如: 11111111轉到00000001 = -1 這是 Java 將顯示為值的內容。

您可能想要做的是知道字節的無符號值。

您可以使用位掩碼來完成此操作,該位掩碼會刪除除最低有效 8 位之外的所有內容。 (0xff)

所以:

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

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

將打印出: "Signed: -1 Unsigned: 255"

這里究竟發生了什么?

我們使用按位 AND 來屏蔽所有無關的符號位(最低有效 8 位左側的 1)。當 int 轉換為字節時,Java 會砍掉最左側的 24 位

1111111111111111111111111010101
&
0000000000000000000000001111111
=
0000000000000000000000001010101

由於第 32 位現在是符號位而不是第 8 位(並且我們將符號位設置為 0,這是正數),因此 Java 將字節中的原始 8 位讀取為正值。

132位(基數 10 )是1000_0100位(基數 2 ),Java 以 32 位存儲int

0000_0000_0000_0000_0000_0000_1000_0100

int-to-byte 的算法是左截斷的; System.out.println算法是二進制補碼(二進制補碼是如果最左邊的位是1 ,則解釋為負的補碼(反轉位)減一。); 因此System.out.println(int-to-byte( ))是:

  • 解釋為(if-leftmost-bit-is-1[negative(invert-bits(minus-one(] left-truncate( 0000_0000_0000_0000_0000_0000_1000_0100 ) [)))] )
  • = 解釋為(如果最左位是 1[ 負(反轉位(減一(] 1000_0100 [)))] )
  • =解釋為(負(反轉位(減一( 1000_0100 ))))
  • =解釋為(負(反轉位( 1000_0011 )))
  • =解釋為(否定( 0111_1100 ))
  • =解釋為(否定(124))
  • =解釋為(-124)
  • =-124多田!!!

Java 中的字節是有符號的,因此它的范圍是 -2^7 到 2^7-1 - 即 -128 到 127。由於 132 大於 127,所以最終會環繞到 132-256=-124。 也就是說,本質上增加或減少了 256 (2^8) 次,直到它落入范圍內。

有關更多信息,您可能需要閱讀二進制補碼

132 超出了 -128 到 127(Byte.MIN_VALUE 到 Byte.MAX_VALUE)的字節范圍,而是將 8 位值的最高位視為有符號的,這表明在這種情況下它是負數。 所以數字是 132 - 256 = -124。

這是一個非常機械的方法,沒有分散注意力的理論:

  1. 將數字轉換為二進制表示(使用計算器好嗎?)
  2. 只復制最右邊的 8 位 (LSB) 並丟棄其余的。
  3. 從步驟#2 的結果來看,如果最左邊的位是 0,則使用計算器將數字轉換為十進制。 這是你的答案。
  4. 否則(如果最左邊的位是 1)你的答案是否定的。 保留所有最右邊的零和第一個非零位不變。 並將其余的顛倒過來,即用0代替1,用1代替0。 然后使用計算器轉換為十進制並附加一個負號表示該值為負數。

這種更實用的方法與上面的許多理論答案一致。 所以,那些仍在閱讀那些說要使用模的 Java 書籍的人,這絕對是錯誤的,因為我上面概述的 4 個步驟絕對不是模運算。

補碼方程:

在此處輸入圖片說明


在 Java 中, byte (N=8) 和int (N=32) 由上圖所示的 2s 補碼表示。

從等式來看,a 7byte是負數,但對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

通常在書中,您會發現從 int 轉換為 byte 的解釋是由模數除法執行的。 這並不嚴格正確,如下所示,實際發生的情況是 int 數字的二進制值中的 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);

    }

}

}

模擬其工作方式的快速算法如下:

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;
}

如果你想從數學上理解這一點,比如它是如何工作的

所以基本上數字 b/w -128 到 127 將與其十進制值相同,高於其(您的數字 - 256)。

例如。 132,答案是 132 - 256 = - 124 即

256 + 你在數字 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)

注意:它不會考慮小數點后的數字。

從概念上講,對您的數字進行 256 的重復減法,直到它在 -128 到 +127 的范圍內。 因此,在您的情況下,您從 132 開始,然后一步以 -124 結束。

在計算上,這對應於從原始數字中提取 8 個最低有效位。 (請注意,這 8 個中的最高有效位成為符號位。)

請注意,在其他語言中,此行為未定義(例如 C 和 C++)。

  1. 在java中int需要4個字節=4x8=32位
  2. 字節 = 8 位范圍 =-128 到 127

將“int”轉換為“byte”就像將大對象裝入小盒子

如果登錄 -ve 取 2 的補碼

示例 1:讓數字為 130

步驟 1: 130 位 = 1000 0010

步驟 2:考慮第 1 個 7 位和第 8 位是符號(1=-ve 和 =+ve)

第 3 步:將第 1 個 7 位轉換為 2 的補碼

            000 0010   
          -------------
            111 1101
       add         1
          -------------
            111 1110 =126

第 4 步:第 8 位為“1”,因此符號為 -ve

步驟5:130的字節=-126

示例 2:讓數字為 500

步驟 1:500 位 0001 1111 0100

第 2 步:考慮第 1 個 7 位 =111 0100

第 3 步:剩下的位是 '11' 給出 -ve 符號

第 4 步:接受 2 的贊美

        111 0100
      -------------
        000 1011 
    add        1
      -------------
        000 1100 =12

第 5 步:500 的字節=-12

示例 3:數字=300

 300=1 0010 1100

 1st 7 bits =010 1100

 remaining bit is '0' sign =+ve need not take 2's compliment for +ve sign

 hence 010 1100 =44

 byte(300) =44
 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           

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM