【发布时间】:2010-10-24 23:26:15
【问题描述】:
int i =132;
byte b =(byte)i; System.out.println(b);
令人难以置信。为什么输出是-124?
【问题讨论】:
标签: java
int i =132;
byte b =(byte)i; System.out.println(b);
令人难以置信。为什么输出是-124?
【问题讨论】:
标签: java
在 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"
这里实际发生了什么?
我们使用按位与来屏蔽所有无关的符号位(最低有效 8 位左侧的 1。) 当一个 int 转换为一个字节时,Java 会砍掉最左边的 24 位
1111111111111111111111111010101
&
0000000000000000000000001111111
=
0000000000000000000000001010101
由于第 32 位现在是符号位而不是第 8 位(我们将符号位设置为 0,即为正),Java 将字节中的原始 8 位读取为正值。
【讨论】:
132 的位数 (base 10) 是 1000_0100 的位 (base 2),Java 存储 int 的 32 位:
0000_0000_0000_0000_0000_0000_1000_0100
int-to-byte 算法是左截断; System.out.println 的算法是 two's-complement(如果最左边的位是 1,则二进制补码解释为负数 one's-complement(反转位)减一。);因此System.out.println(int-to-byte()) 是:
0000_0000_0000_0000_0000_0000_1000_0100) [)))])1000_0100 [)))] )1000_0100))))1000_0011)))0111_1100))【讨论】:
0 为正,1 为负)。
int 到byte 的转换是有损转换(即信息丢失)。因此,无法将其转换回原来的int 值。
Java 中的字节是有符号的,因此它的范围是 -2^7 到 2^7-1 - 即 -128 到 127。 由于 132 高于 127,因此您最终会回绕到 132-256=-124。也就是说,本质上是加或减 256 (2^8),直到它落入范围内。
有关更多信息,您可能需要阅读two's complement。
【讨论】:
132 超出了 -128 到 127 的字节范围(Byte.MIN_VALUE 到 Byte.MAX_VALUE) 相反,8 位值的最高位被视为带符号的,表示在这种情况下它是负数。所以这个数字是 132 - 256 = -124。
【讨论】:
这是一种非常机械的方法,没有令人分心的理论:
这种更实用的方法是根据上面的理论答案。所以,那些还在阅读那些说要使用模数的 Java 书籍的人,这绝对是错误的,因为我上面概述的 4 个步骤绝对不是模数运算。
【讨论】:
http://iiti.ac.in/people/~tanimad/JavaTheCompleteReference.pdf 第 59 页
在 Java 中,byte (N=8) 和 int (N=32) 由上面显示的 2s 补码表示。
从等式中,a7 对于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步:判断第一个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 位 0001 1111 0100
第 2 步:考虑第一个 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
【讨论】: