我在 segmentfault 上提了一个关于 Java 逻辑左移运算的规则的问题,希望得到完善的解答,链接: https://segmentfault.com/u/clearbug
1
Septembers 2016-09-11 11:08:36 +08:00
|
2
imn1 2016-09-11 11:25:08 +08:00
位运算?
x <<< n 相当于 x * 2^n |
3
clearbug OP @Septembers 英语不太好,文档终于阅读完了。看文档里有这么一句:
“ At run time, shift operations are performed on the two's-complement integer representation of the value of the left operand.”也就是说在运行时,移位操作时左操作数使用的是左操作数的补码进行移位运算的,然后运行完再将结果转换为原码就可以知晓其具体数值了( PS :不知道这里理解对否。。)。 那么我想问一下: int x = 3; //00000000,00000000,00000000,00000011 (补码和原码是一样的) int x31 = x << 31; 1.求 x31 的运算过程: 00000000,00000000,00000000,00000011-> 10000000,00000000,00000000,00000000 (移位运算,右边补零) 这个运算过程正确吗?如果正确的话,结果 10000000,00000000,00000000,00000000 又该怎么转换成为原码呢? |
5
Septembers 2016-09-11 15:58:29 +08:00
@clearbug 我主力不是写 Java 因此无法为您回答
|
6
clearbug OP @Septembers 。。。好吧。谢谢提供官方文档哈。敢问大神你主力是啥呢?
|
7
1023400273 2016-09-11 16:35:45 +08:00
@imn1 Java 只有>>>运算符没有<<<运算符吧?
|
8
imn1 2016-09-11 16:48:43 +08:00
@clearbug
我也不懂 java ,不过这个跟 java 无关,是位运算知识 就是这么简单,只不过位运算有位限制(默认 32 位或 64 位),你上面的例子最左边的 1 左移 31 位后溢出了 另外符号问题,第 32 位为 1 时可能是负数 有些语言会有点不同,例如 php 根据机器默认 32 或 64 , python 一般情况下乘法加法不会溢出,但少数情况如取反操作会限制位数 110000000000000000000000000000000(2 进制共 33 位)=6442450944(10 进制)=3*2147483648=3*2^31 右移就是舍弃右边,相当于除以 2^n 并取整数部分(舍弃余数) 左移如果没有溢出可以通过右移相同位复原,右移除非去掉的全是二进制 0 ,否则无法复原 其实编译时,编译器就是把一些计算换成位运算的 如十进制 3*3 ,就是 3*(2+1) => (3<< 1) + (3<<0) 有些非编译语言也可以这样写起到加速作用 |
9
imn1 2016-09-11 16:50:44 +08:00
@1023400273
不懂 java ,不过我上面 2L 写错了,移位运算符是<<和>>,不是<<<,>>> |
10
oldwolf 2016-09-11 16:53:59 +08:00
|
11
clearbug OP @oldwolf 大神威武,把 jvm 的实现都搬出来了。。。可惜对 cpp 不太懂。。顺便问一下:你学 Java 都直接看 jvm 实现吗?
|
12
clearbug OP @imn1 我比较菜。。你说得我也不太懂,不过 sf 上第一个回答我感觉倒是挺合理:
着重讲一下你不理解的 10000000,00000000,00000000,00000000 怎么取补码(也就是从补码转原码)的过程吧。 取补的过程你也很清楚了,但是有一个关键点,就是在+1 的过程中不会改变符号位。在通常的情况下,+1 都不会影响符号位,只有两个数字比较特别,就是 00000000,00000000,00000000,00000000 和 10000000,00000000,00000000,00000000 。这两个取反码是 01111111,11111111,11111111,11111111 和 11111111,11111111,11111111,11111111 ,如果直接+1 都会影响符号位。而真正的去补过程是不修改符号位的,所以这两个数的补码计算之后仍然为他们本身。 所以补码 10000000,00000000,00000000,00000000 的源码就是 10000000,00000000,00000000,00000000 ,也就是负数的最大值 -2147483648 因为没有-0 ,所以 10000000,00000000,00000000,00000000 就是负数的最大值 -2147483648 。。记得之前教科书上好像也说过这个 |
13
napsterwu 2016-09-11 17:18:25 +08:00
Java 有 左移<< 右移>> 无符号右移>>> 以上就是关键词了
|