Java中的位移

时间:2012-05-29 13:13:16

标签: java bit-manipulation

这是一个Java程序,它左移short 2的值num << i。我有两个问题:

为什么i的{​​{1}}值介于16和29之间会产生有效结果? short只能保存-32,768到32,767之间的值。

所以我想,也许System.out.println会将num << i解释为大于short的值。但那为什么它会在num << 30开始产生意外的价值?

public class LeftShift {

    public static void main(String[] args)
    {
        short num = 2;
        for (int i = 0; i < 32; i++) {
            System.out.println("Left-shifting 2 by " + i + " places yields: " 
                                + (num << i));
        }
    }

}

输出:

Left-shifting 2 by 0 places yields: 2
Left-shifting 2 by 1 places yields: 4
Left-shifting 2 by 2 places yields: 8
Left-shifting 2 by 3 places yields: 16
Left-shifting 2 by 4 places yields: 32
Left-shifting 2 by 5 places yields: 64
Left-shifting 2 by 6 places yields: 128
Left-shifting 2 by 7 places yields: 256
Left-shifting 2 by 8 places yields: 512
Left-shifting 2 by 9 places yields: 1024
Left-shifting 2 by 10 places yields: 2048
Left-shifting 2 by 11 places yields: 4096
Left-shifting 2 by 12 places yields: 8192
Left-shifting 2 by 13 places yields: 16384
Left-shifting 2 by 14 places yields: 32768
Left-shifting 2 by 15 places yields: 65536
Left-shifting 2 by 16 places yields: 131072
Left-shifting 2 by 17 places yields: 262144
Left-shifting 2 by 18 places yields: 524288
Left-shifting 2 by 19 places yields: 1048576
Left-shifting 2 by 20 places yields: 2097152
Left-shifting 2 by 21 places yields: 4194304
Left-shifting 2 by 22 places yields: 8388608
Left-shifting 2 by 23 places yields: 16777216
Left-shifting 2 by 24 places yields: 33554432
Left-shifting 2 by 25 places yields: 67108864
Left-shifting 2 by 26 places yields: 134217728
Left-shifting 2 by 27 places yields: 268435456
Left-shifting 2 by 28 places yields: 536870912
Left-shifting 2 by 29 places yields: 1073741824
Left-shifting 2 by 30 places yields: -2147483648
Left-shifting 2 by 31 places yields: 0

6 个答案:

答案 0 :(得分:3)

因为short上的算术运算会产生int s,除非你把它们重新抛出。例如,

short value = 2;
short result = value << 31;

为您提供编译错误,您需要将其转换为short

这有几个原因,最值得注意的是

  • 字节码语言并不真正处理小于int
  • 的任何类型
  • 否则short上的操作会更频繁地溢出。
  • 更好地模拟大多数硬件,通常不对子32位值进行操作

答案 1 :(得分:3)

从Java语言规范15.19:“Shift运算符”

  

shift表达式的类型是左侧操作数的提升类型。

推广类型由5.6定义:“数字促销”:

  

否则,如果操作数是编译时类型byte,short或   char,一元数字促销通过a将其提升为int类型的值   扩大转换(第5.1.2节)。

答案 2 :(得分:3)

请注意,复合赋值运算符会将结果转换为指定的类型。所以,修改你的例子:

public static void main(String[] args) {
    for (int i = 0; i < 32; i++) {
        short num = 2;
        num <<= i; // equivalent to num = (short)(num << i);
        System.out.println("Left-shifting 2 by " + i + " places yields: " + num);
    }
}

这将产生不同的结果,可能更符合您的期望。

答案 3 :(得分:2)

30的意外值是integer overflow,MSB变为1 - 因此作为负数被插入。

还要注意运营商&lt;&lt;正在产生int s(除非参数是long,然后它产生long)。 (事实上​​,short首先被扩展为int,然后才评估<<。)因此结果如预期的那样 - int,而不是short

答案 4 :(得分:1)

正在发生的事情是自动推广操作数。在Java中,示例中(num << i)表达式的结果是int类型。这就是为什么结果在int范围内,而不是short

如果您尝试将(num << i)分配回short,则会收到编译错误,迫使您转回short

答案 5 :(得分:1)

请参阅this SO帖子。

与此问题相关的部分是来自here的引用:

If an integer operator has an operand of type long, then the other operand is also
converted to type long. Otherwise the operation is performed on operands of type int, if  
necessary shorter operands are converted into int.

我认为这个扩展转换不会丢失信息,并且可能在溢出的情况下保护您。请参阅Chapter 5 of the Java language specification,详细了解如何扩大和缩小转化次数。