Java方法在左右算术位移位后返回错误的值



我有一个看起来像这样的方法:

private short getAddress(short ir) { //performs bit shifting to isolate and find address
short addr = ir;
addr = (short) (addr << 11); //remove leading bits
if (debug == true) {
System.out.println("LeftSh Reads " + Integer.toBinaryString(addr));
debugging();
}
addr = (short) Math.abs((addr >> 11)); //Shift back to starting position. Java's casting leaves this in negative for some reason. Taking the absolute value fixes it.
if (debug == true) {
System.out.println("RightSh Reads " + Integer.toBinaryString(addr));
debugging();
}
return addr;
}

对于本例,short ir=1557。

addr的预期返回值是21,但我得到的却是11我的两个系统输出的控制台输出为:

LeftSh Reads 11111111111111111010100000000000
RightSh Reads 1011

我正在自学Java,我觉得我错过了导致这种情况发生的一些关于类型转换或位转换的基本知识。我该如何解决这个问题?

使用逻辑和而不是左/右移,以避免short已签名的问题:

short i = 1557;
short i_masked = (short)(i & 0x001F);

或者,也许更清楚的

short i_masked = (short) (i & 0b0000000000011111);

为了了解您的代码中发生了什么,我建议您在右移后打印出值,但在应用abs()之前打印出值。

当向右移动时,由于数字的二进制补码,得到了-11。

当你取绝对值时,你得到11。

要得到预期的21,你需要在左移后做以下操作。

addr = (short) ((addr&0xFFFF) >>> 11);
  • 这屏蔽了左移short的16位
  • 则使用>gt>
System.out.println(addr);

打印

21

问题是short是一种有符号的数据类型。最高位等于1的值表示负值:

  • 像从shortint符号的转换这样的大小转换扩展负值,这意味着1的16位被添加到负short值之前。

  • 算术右移,对于负值,在移位模式前面插入1位。

让我们按照1557(0x0615=0000 0110 0001 0101(的输入通过您的代码:

addr = (short) (addr << 11);           // Gives 10101 00000000000, a negative number.
Integer.toBinaryString(addr)           // Sign-extends to "11111111111111111010100000000000"
addr = (short) Math.abs((addr >> 11)); // (addr >> 11) gets sign-extended: 
// 11111111111 10101, meaning -11
// abs() gives 00000000000 01011, meaning 11

正如其他人已经回答的那样,使用位和而不是移位。

最新更新