JAVA位运算符及源码,反码,补码的相关笔记
引语:
在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以用补码统一处理。此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
- 原码:二进制表示。二进制首位是符号位,0为正,1为负
- 反码:正数,反码和原码一样**;负数**,符号位不变,其他各位取反
- 补码:正数,补码和原码一样**;负数**,反码末位加1,有进位则进位,但不改变符号位
以-101为例
源码 | 10000000 | 00000000 | 00000000 | 01100101 |
---|---|---|---|---|
反码 | 11111111 | 11111111 | 11111111 | 10011010 |
补码 | 11111111 | 11111111 | 11111111 | 10011011 |
相关的位运算符
1.(~)非运算符,把1变成0,把0变成1 超出运算范围,变成负数
2.(&)与运算符,当两边操作数的位同时为1时,结果为1,否则为0
3.(|)或运算符,当两边操作数的位有一边为1时,结果为1,否则为0
4.(^)异或运算符,两边的位不同时,结果为1,否则为0
5.(<<)左移运算符
value << num value指定移动的值 num指定移动的位数
运算规律
- 按照操作符右侧指定的位数将左边的操作数向左边移动(高位移除,在低位补0)
- 当左移的操作数是int类型时,每移动一位它的第31位就要被移除(位数以第0位开始)
- 当左移的操作数是long类型时,每移动一位 它的第63位就要被移除
- 当左边的操作数为byte、short类型时,它们会被转换为int类型,其结果为int类型
- 在左移过程中正数可能移为负数,负数也可能移为正数
数学意义
- 在没有数字溢出的前提下,左移1位相当于乘以2的1次方,左移n位相当于乘以2的n次方
6.(>>)(区别型符号)右移运算符
value >> num value指定移动的值 num指定移动的位数
运算规则
- 按照操作符右侧指定的位数将操作符左边的操作数向右移动(采用符号扩展机制)
- 符号扩展进行移位,即:若符号为正,则在高位插入0,若符号为负,则在高位插入1(符号位保持不变)//区别左移
- 当左边的操作数为byte、short类型时,它们会被转换为int类型,其结果要是int类型
数学意义
- 右移一位相当于除以2,右移n位相当于除以2的n次方
注:无论正负偶数左移一位直接是整除结果,但对于正值奇数结果是除以2后向下取整后的结果,对于负值奇数结果是除以2后向上取整结果
正数 | 负数 | |
---|---|---|
60 | 直接除以2(30) | 直接除以2(-30) |
61 | 除以2后向下取整(30) | 除以2后向上取整(-31) |
总而言之,奇数右移以后,结果取小
7.(>>>)无符号右移运算符
value >>> num value指定移动的值 num指定移动的位数
运算规则
- 按照操作符右侧指定的位数将操作符左边的操作数向右移动(0扩展机制)
- 移位过程中,无论数值是正数还是负数,都在最高位补0
- 只对32位和64位值有意义
在Thinking in java 中有这么一句话:只有数值右端的低5位才有用(Only the five low-order bits of the right-hand side will be used),这样可以防止我们移位超过int型值所具有的位数。(因为2的5次方为32,而int类型只有32位)若对一个long类型的数值进行处理,最后得到的结果也是long类型,此时只会用到数值右端的低6位,以防止移位超过long型数值具有的位数
根本原因是:Java中规定,没有任何移位操作符可以让一个数字丢弃所有的位
换言之,如果移动位数超过该类型的最大位数,那么编译器会对移动的位数取模。例如果对int类型移位33位,实际上只移动了33%32=1位。具体细节是(int a<<b)如果移位超过数值类型的最大位数,就将b化为二进制数,取右端的低5位数,再把这5位数化为10进制,此时这个10进制就是要将a移动的位数,long 类型同理