为什么按位与 0xFF 的负符号整数会产生正符号整数?
Why negative signed integer with bitwise AND 0xFF will result in positive signed integer?
我的目标是理解二进制补码。
10000111
有符号整数等于 -121
。但是,如果您将它与十六进制的 0xFF
或十进制的 11111111
按位 AND,它将等于 135
.
在我看来,这不应该发生,因为最高字节 10000111
与结果字节 10000111
相同
10000111
AND 11111111
------------
10000111 = 135.
我的预期结果是值不应更改,等于 -121
。
我的实际结果是数值变化。
我的猜测是,0xFF
是 unsigned bit
。因此,最高字节的 signed 位 1
和较低字节的 unsigned 位 1
将导致 unsigned位1
。但是……那是不对的。
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class WebSocketWorkerThreadTest {
@Test
void SignedToUnsignedInteger() {
byte signed = (byte) 0b10000111;
// If java uses unsigned integer, it should be 135. however, java uses signed integer. Therefore, the outputs will be -121
// 10000111
// ^
// the sign bit. If it exists then the value will be negative.
Assertions.assertEquals(-121, signed);
// 10000111
// 11111111
// --------
// 10000111
int unsigned = signed & 0xFF;
Assertions.assertEquals(135, unsigned);
}
}
Java 以二进制补码形式存储整数(long 和 byte)。参见 https://en.wikipedia.org/wiki/Two%27s_complement
在这种表示中,任何负数都以一串 1 位开头,因为值 10000... 0000
是最低可表示值,而值 1111... 111
是 -1。
出于这个原因,当您剪切前导 1 位时,您将数字完全向上移动到正数范围内,因为新数字不再以 1 位开头。
在你的例子中,你使用了字节,但你的字节值没有你期望的形式。它是一个整数,当应用 &
操作时,因为您没有将 0xFF
转换为字节。解决此问题的最简单方法是将 &
操作的结果转换为字节,如另一个答案所建议的那样。
当您应用 &
运算符时,signed
被提升为 int
,因为 二进制数字提升 .
不是10000111 & 11111111
,是11111111111111111111111110000111 & 00000000000000000000000011111111
,它的值是00000000000000000000000010000111
(还是一个int)。
此处的 MSB 为零,因此为正数。
如果你将它转换回一个字节,这将只占用 8 个 LSB,该字节将再次为负。
我的目标是理解二进制补码。
10000111
有符号整数等于 -121
。但是,如果您将它与十六进制的 0xFF
或十进制的 11111111
按位 AND,它将等于 135
.
在我看来,这不应该发生,因为最高字节 10000111
与结果字节 10000111
10000111
AND 11111111
------------
10000111 = 135.
我的预期结果是值不应更改,等于 -121
。
我的实际结果是数值变化。
我的猜测是,0xFF
是 unsigned bit
。因此,最高字节的 signed 位 1
和较低字节的 unsigned 位 1
将导致 unsigned位1
。但是……那是不对的。
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class WebSocketWorkerThreadTest {
@Test
void SignedToUnsignedInteger() {
byte signed = (byte) 0b10000111;
// If java uses unsigned integer, it should be 135. however, java uses signed integer. Therefore, the outputs will be -121
// 10000111
// ^
// the sign bit. If it exists then the value will be negative.
Assertions.assertEquals(-121, signed);
// 10000111
// 11111111
// --------
// 10000111
int unsigned = signed & 0xFF;
Assertions.assertEquals(135, unsigned);
}
}
Java 以二进制补码形式存储整数(long 和 byte)。参见 https://en.wikipedia.org/wiki/Two%27s_complement
在这种表示中,任何负数都以一串 1 位开头,因为值 10000... 0000
是最低可表示值,而值 1111... 111
是 -1。
出于这个原因,当您剪切前导 1 位时,您将数字完全向上移动到正数范围内,因为新数字不再以 1 位开头。
在你的例子中,你使用了字节,但你的字节值没有你期望的形式。它是一个整数,当应用 &
操作时,因为您没有将 0xFF
转换为字节。解决此问题的最简单方法是将 &
操作的结果转换为字节,如另一个答案所建议的那样。
&
运算符时,signed
被提升为 int
,因为 二进制数字提升 .
不是10000111 & 11111111
,是11111111111111111111111110000111 & 00000000000000000000000011111111
,它的值是00000000000000000000000010000111
(还是一个int)。
此处的 MSB 为零,因此为正数。
如果你将它转换回一个字节,这将只占用 8 个 LSB,该字节将再次为负。