添加后的意外结果
Unexpected result after addition
我现在正在 Java 编写个人项目,最近第一次使用位运算。我试图将两个字节转换为一个短字节,一个字节是高 8 位,另一个是低 8 位。
我在运行下面的第一行代码运行时出错。
不正确的结果
short regPair = (short) ( (byte1 << 8) + (byte2) );
正确结果
short regPair = (short) ( (byte1 << 8) + (byte2 & 0xFF) );
预期结果为:AAAAAAAABBBBBBBB
,其中 A
表示来自 byte1
的位,B
表示来自 byte2
.
的位
使用第一行代码,我将在经过位移的字节 1 和添加到字节 2 之间得到典型的加法。
错误结果示例
byte1 = 11, byte2 = -72
result = 2816 -72
= 2744
当使用产生预期结果的代码行时,我可以获得正确答案 3000。我很好奇为什么 byte2
需要位掩码。我的想法是它在加法之前将 byte2
转换为二进制,然后对两个字节执行二进制加法。
直接打印中间值看看是怎么回事。喜欢,
System.out.printf("%d %s%n", ((byte) -72) & 0xFF, Integer.toBinaryString(((byte) -72) & 0xFF));
我明白了
184 10111000
所以正确的代码实际上是加上 184(而不是减去 72)。
所以我完全忘记了 byte
在 Java 中被签名,因此当使用这种数据类型的变量执行数学运算时,它将采用带符号的解释而不是位的直接值。通过执行 byte2 & 0xFF
,Java 将有符号字节值转换为除前 8 位以外的所有位都设置为 0 的无符号整数。因此,您可以正确执行二进制加法。
有符号字节值0x11111111 = -1
无符号字节值0x11111111 = 255
在不正确的情况下,由于 +
运算符,byte2
被提升为 int
。这不仅仅意味着在 byte2
的二进制表示形式的开头添加一些零。由于整数类型在Java中的two's complement中表示,因此将添加1s。晋升后,byte2
变为:
1111 1111 1111 1111 1111 1111 1011 1000
通过执行 & 0xFF
,您强制提升到 int
first,然后保留最低有效 8 位:1011 1000
和将其他所有内容设为 0.
In both cases byte values are promoted to int in the expression when
it is evaluated.
byte byte1 = 11, byte2 = -72;
short regPair = (short) ( (byte1 << 8) + (byte2) );
(2816) + (-72) = 2744
甚至在下面的表达式中 byte 被提升为 int
short regPair = (short) ( (byte1 << 8) + (byte2 & 0xFF) );
2816 + 184 = 3000
在此表达式中,没有两个字节的串联,就像上面问题中所表达的那样 - AAAAAAAABBBBBBBB,其中 A 表示来自字节 1 的位,B 表示来自字节 2 的位。
实际上 -7 和 255 得到 184 加到 2816 得到输出 3000。
我现在正在 Java 编写个人项目,最近第一次使用位运算。我试图将两个字节转换为一个短字节,一个字节是高 8 位,另一个是低 8 位。
我在运行下面的第一行代码运行时出错。
不正确的结果
short regPair = (short) ( (byte1 << 8) + (byte2) );
正确结果
short regPair = (short) ( (byte1 << 8) + (byte2 & 0xFF) );
预期结果为:AAAAAAAABBBBBBBB
,其中 A
表示来自 byte1
的位,B
表示来自 byte2
.
使用第一行代码,我将在经过位移的字节 1 和添加到字节 2 之间得到典型的加法。
错误结果示例
byte1 = 11, byte2 = -72
result = 2816 -72
= 2744
当使用产生预期结果的代码行时,我可以获得正确答案 3000。我很好奇为什么 byte2
需要位掩码。我的想法是它在加法之前将 byte2
转换为二进制,然后对两个字节执行二进制加法。
直接打印中间值看看是怎么回事。喜欢,
System.out.printf("%d %s%n", ((byte) -72) & 0xFF, Integer.toBinaryString(((byte) -72) & 0xFF));
我明白了
184 10111000
所以正确的代码实际上是加上 184(而不是减去 72)。
所以我完全忘记了 byte
在 Java 中被签名,因此当使用这种数据类型的变量执行数学运算时,它将采用带符号的解释而不是位的直接值。通过执行 byte2 & 0xFF
,Java 将有符号字节值转换为除前 8 位以外的所有位都设置为 0 的无符号整数。因此,您可以正确执行二进制加法。
有符号字节值0x11111111 = -1
无符号字节值0x11111111 = 255
在不正确的情况下,由于 +
运算符,byte2
被提升为 int
。这不仅仅意味着在 byte2
的二进制表示形式的开头添加一些零。由于整数类型在Java中的two's complement中表示,因此将添加1s。晋升后,byte2
变为:
1111 1111 1111 1111 1111 1111 1011 1000
通过执行 & 0xFF
,您强制提升到 int
first,然后保留最低有效 8 位:1011 1000
和将其他所有内容设为 0.
In both cases byte values are promoted to int in the expression when it is evaluated.
byte byte1 = 11, byte2 = -72;
short regPair = (short) ( (byte1 << 8) + (byte2) );
(2816) + (-72) = 2744
甚至在下面的表达式中 byte 被提升为 int
short regPair = (short) ( (byte1 << 8) + (byte2 & 0xFF) );
2816 + 184 = 3000
在此表达式中,没有两个字节的串联,就像上面问题中所表达的那样 - AAAAAAAABBBBBBBB,其中 A 表示来自字节 1 的位,B 表示来自字节 2 的位。
实际上 -7 和 255 得到 184 加到 2816 得到输出 3000。