Java方法returns左右算术位移后的错误值

Java Method returns wrong value after left and right arithmetic bit-shifting

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

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;
    }

对于此示例,短 ir = 1557。

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

LeftSh Reads 11111111111111111010100000000000

RightSh Reads 1011

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

使用 logical-and 而不是 left/right shift,以避免 short 已签名这一事实的问题:

short i = 1557;

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

或者,也许更清楚

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

为了理解你的代码中发生了什么,我建议你打印出right-shifting之后但之前的值应用abs().

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

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

要获得预期的 21,您需要在左移后执行以下操作。

addr = (short) ((addr&0xFFFF) >>> 11);
  • 这会屏蔽掉左移短的 16 位。
  • 然后使用 >>> 向右移动符号。
System.out.println(addr);

版画

21

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

  • 大小转换如shortint sign-extend负值的转换,意思是在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

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