[英]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 中的大多数原始类型都是有符号的,并且byte
、 short
、 int
和long
以二进制补码进行编码。 ( 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(
))
是:
0000_0000_0000_0000_0000_0000_1000_0100
) [)))] )1000_0100
[)))] )1000_0100
))))1000_0011
)))0111_1100
))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。
这是一个非常机械的方法,没有分散注意力的理论:
这种更实用的方法与上面的许多理论答案一致。 所以,那些仍在阅读那些说要使用模的 Java 书籍的人,这绝对是错误的,因为我上面概述的 4 个步骤绝对不是模运算。
在 Java 中, byte
(N=8) 和int
(N=32) 由上图所示的 2s 补码表示。
从等式来看,a 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
通常在书中,您会发现从 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++)。
将“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.