Odd behavior when Java converts int to byte?

int i =132;


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

Mindboggling. Why is the output -124?

294426 次浏览

字节在 Java 中是有符号的,所以它的范围是 -2 ^ 7到2 ^ 7-1-ie,-128到127。 因为132高于127,所以最终包装成132-256 =-124。也就是说,基本上256(2 ^ 8)被加或减,直到它进入范围。

要了解更多信息,您可能需要阅读 两个人的互补

132在字节的 -128到127的范围之外(Byte.MIN _ VALUE 到 Byte.MAX _ VALUE) 相反,在这种情况下,8位值的顶部位被视为有符号,这表明它是负的。所以数字是132-256 = -124。

在 Java 中,int是32位,byte是8 bits

Java 中的大多数基本类型都是有符号的,byteshortintlong编码为两个补码。(char类型是无符号的,符号的概念不适用于 boolean。)

在这个数字方案中,最高有效位指定数字的符号。如果需要更多位,则将最重要的位(“ MSB”)简单地复制到新的 MSB。

所以如果你有字节 255: 11111111 你想把它表示为一个 int(32位) ,你只需要把1向左复制24次。

读取负二的补数的一种方法是从最小有效位开始向左移动直到找到前一个1然后反转每一位。产生的数字是该数字的正数版本

例如: 1111111100000001 = -1。这是 Java 将显示的值。

您可能需要知道字节的无符号值。

你可以用一个位掩码来完成这个任务,它会删除除了最低有效8位之外的所有内容

所以:

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,这是正数) ,字节的原始8位被 Java 读取为正值。

132(基数10)是位 1000_0100(基数2) ,Java 存储 int为32位:

0000_0000_0000_0000_0000_0000_1000_0100

Algorithm for int-to-byte is left-truncate; Algorithm for System.out.println is two's-complement (Two's-complement is if leftmost bit is 1, interpret as negative one's-complement (invert bits) minus-one.); Thus System.out.println(int-to-byte( )) is:

  • interpret-as( if-leftmost-bit-is-1[ negative(invert-bits(minus-one(] left-truncate(0000_0000_0000_0000_0000_0000_1000_0100) [)))] )
  • =interpret-as( if-leftmost-bit-is-1[ negative(invert-bits(minus-one(] 1000_0100 [)))] )
  • =interpret-as(negative(invert-bits(minus-one(1000_0100))))
  • =interpret-as(negative(invert-bits(1000_0011)))
  • =interpret-as(negative(0111_1100))
  • =interpret-as(negative(124))
  • =interpret-as(-124)
  • =-124   Tada!!!

通常在书中,你会发现从 int 到 byte 的转换是通过模除来完成的。这并不完全正确,如下所示 实际发生的情况是,整数二进制值的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);


}


}


}

这里有一个非常机械的方法,没有分散注意力的理论:

  1. 将数字转换为二进制表示(使用计算器可以吗?)
  2. 只复制最右边的8位(LSB)并丢弃其余的。
  3. 根据步骤 # 2的结果,如果最左边的位为0,则使用计算器将数字转换为十进制。这就是你的答案。
  4. 否则(如果最左边的位是1)你的答案是否定的。保留所有最右边的零和第一个非零位不变。然后反过来,也就是,用0代替1,用1代替0。然后使用计算器将其转换为十进制,并附加一个负号表示该值为负。

这种更加实用的方法与上面的许多理论答案是一致的。所以,那些仍然在阅读 Java 书籍的人说要使用模,这是绝对错误的,因为我上面列出的4个步骤绝对不是一个模除。

二的补数方程式:

enter image description here


在 Java 中,byte(N = 8)和 int(N = 32)由上面所示的2s 补语表示。

从方程式来看,a7byte是阴性的,但对 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

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

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

从概念上来说,重复减去256就可以得到你的数字,直到它在 -128到 + 127的范围内。因此在您的例子中,您从132开始,然后在一个步骤中以 -124结束。

在计算上,这相当于从原始数字中提取8个最低有效位。(请注意,这8位中最重要的一位变成了符号位。)

注意,在其他语言中没有定义这种行为(例如 C 和 C + +)。

如果你想从数学上理解它,比如它是如何工作的

所以基本上数字 b/w -128到127将被写成与它们的十进制值相同的值,超过这个值就是它(你的数字 -256)。

答案是 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);

输出为3944

(295-256)(300-256)

注意: 它不会考虑小数后面的数字。

  1. 在 java 中,int 需要4个字节 = 4x8 = 32位
  2. Byte = 8位范围 = -128到127

把“ int”转换成“ byte”就像把大物体装进小盒子里一样

如果符号 -ve 取2的补数

例1: 让数字为130

步骤1:130位元间距 = 10000010

步骤2: 条件符第1个7位和第8位是符号(1 =-ve 和 = + ve)

步骤3: 将前7位转换为2位的赞美

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

步骤4: 第8位是“1”,因此符号是-ve

步骤5: 字节为130 = -126

例2: 让数字为500

步骤1:500位元组000111110100

步骤2: 考虑前7位 = 1110100

步骤3: 剩下的位是“11”给予-五号

第四步: 接受2的赞美

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

步骤5: 字节为500 = -12

例三: 数字 = 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