Java二进制运算
Java二进制表示法
首先了解下二进制,二进制是相对十进制而言的,当然还有八进制,十六进制等等,我们常用的都是十进制,计算机用的都是二进制,而符号表示常用十六进制。
二进制就是只有0、1两个值表示的数,规则是逢二进一。数据存储在内存中都是存储的二进制,二进制又可分为原码、反码、补码。最终存储在内存中的是“补码”。
在了解原码、反码、补码之前先得了解一下机器数和真值。
机器数
一个数在计算机中的二进制表示形式,叫做这个数的机器数。机器数是带符号的,在计算机用机器数的最高位存放符号,正数为0,负数为1。比如,十进制中的数 +3 ,计算机字长为8位,转换成二进制就是 0000 0011。如果是 -3 ,就是 100 00011 。那么,这里的 0000 0011 和 1000 0011 就是机器数。
机器数的真值
因为第一位是符号位,所以机器数的形式值就不等于真正的数值。 例如上面的有符号数 1000 0011,其最高位1代表负,其真正数值是 -3,而不是形式值131(1000 0011转换成十进制等于131)。
所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值。例:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1。
原码、反码、补码是计算机中对数字的二进制表示方法。一个正数的原码、反码、补码都是它的二进制表现形式。(无符号数没有原码、反码和补码一说。只有带符号数才存在不同的编码方式。)
原码、反码、补码
原码:原码就是符号位加上真值的绝对值,即用第一位表示符号,其余位表示值。比如:如果是8位二进制:[+1]原 = 0000 0001, [-1]原 = 1000 0001;
反码:如果是正数,则表示方法和原码一样;如果是负数,符号位不变,其余各位取反,则得到这个数字的反码表示形式。比如:[+1] = [0000 0001]原 = [0000 0001]反 ,[-1] = [1000 0001]原 = [1111 1110]反;
补码:如果是正数,则表示方法和原码一样;如果是负数,则将数字的反码加上1(相当于将原码数值位取反然后在最低位加1)。
比如:[+1] = [0000 0001]原 = [0000 0001]反 = [0000 0001]补, [-1] = [1000 0001]原 = [1111 1110]反 = [1111 1111]补。
示例:
数值 原码 反码 补码
6 0000 0110 0000 0110 0000 0110
-6 1000 0110 1111 1001 1111 1010
示例中均为8-bit的整数。它的可表示范围包括-128到127,总共256(=2<sup>8</sup>)个整数。0的反码、补码都为0。
进制转化
数学中的进制转化
十进制转二进制,整数部分除以2,整除为0,否则为1,直到结果为1,然后从后窜到前的结果就是其二进制值。
比如:10
10/2 = 5 整除 0
5/2 = 2 未整除 1
2/2 = 1 整除 0
1 结果为1,结束 1
最后10的二进制值为:1010
再比如77
77/2=38 未整除 1
38/2=19 整除 0
19/2=9 未整除 1
9/2=4 未整除 1
4/2=2 整除 0
2/2=1 整除 0
1 结果为1,结束 1
最后77的二进制为1001101
小数部分的二进制化,取小数部分乘以2,结果大于等于1,取1,否则取0,再取小数部分乘以2,取值,直到结果为0或者循环。
比如:10.22
先进行整数部分二进制,结果为1010
再进行小数部分二进制:
0.22 * 2 = 0.44 0
0.44 * 2 = 0.88 0
0.88 * 2 = 1.76 1
0.76 * 2 = 1.52 1
0.52 * 2 = 1.04 1
0.04 * 2 = 0.08 0
0.08 * 2 = 0.16 0
0.16 * 2 = 0.32 0
0.32 * 2 = 0.64 0
0.64 * 2 = 1.28 1
0.28 * 2 = 0.56 0
0.56 * 2 = 1.12 1
0.12 * 2 = 0.24 0
0.24 * 2 = 0.48 0
0.48 * 2 = 0.96 0
0.96 * 2 = 1.92 1
0.92 * 2 = 1.84 1
0.84 * 2 = 1.68 1
0.68 * 2 = 1.36 1
0.36 * 2 = 0.72 0
0.72 * 2 = 1.44 1
...
结果就是1010.00111000010100011110...
若是以科学计数法表示那就是1.01000111000010100011110...E11
若是表示成float的二进制形式那就是:0100 0001 0010 0011 1000 0101 0001 1110
Java内置的进制转换
用途 | 方法 |
---|---|
十进制转成十六进制 | Integer.toHexString(int i) |
十进制转成八进制 | Integer.toOctalString(int i) |
十进制转成二进制 | Integer.toBinaryString(int i) |
十六进制转成十进制 | Integer.valueOf("FFFF", 16).toString() |
八进制转成十进制 | Integer.valueOf("2234", 8).toString() |
二进制转成十进制 | Integer.valueOf("0110", 2).toString() |
二进制位运算
1. 按位与(&)
位运算实质是将参与运算的数字转换为二进制,而后逐位对应进行运算。
按位与运算为:两位全为1,结果为1,即1&1=1,1&0=0,0&1=0,0&0=0。
例如51 & 5 -> 00110011 & 00000101 = 00000001 -> 51 & 5 = 1
特殊用法:
(1)与0相与可清零。
(2)与1相与可保留原值,可从一个数中取某些位。例如需要取10101110中的低四位,10101110 & 00001111 = 00001110,即得到所需结果。
2. 按位或(|)
两位只要有一位为1,结果则为1,即1|1=1,1|0=1,0|1=1,0|0=0。
特殊用法:
(1)与0相或可保留原值。
(2)与1相或可将对应位置1。例如,将X=10100000的低四位置1,使X | 00001111 = 10101111即可。
3. 异或运算(^)
两位为“异”,即一位为1一位为0,则结果为1,否则为0。即1^1=1,1^0=0,0^1=0,0^0=1。
特殊用法:
(1)使指定位翻转:找一个数,对应X要翻转的各位为1,其余为0,使其与X进行异或运算即可。例如,X=10101110,使低四位翻转,X ^ 00001111 = 10100001。
(2)与0相异或保留原值。例如X ^ 00000000 = 10101110。
(3)交换两变量的值。(比借助容器法、加减法效率高)原理:一个数对同一个数连续两次进行异或运算,结果与这个数相等。
因此,交换方法为:A = A ^ B,B = A ^ B,A = A ^ B。
4. 取反(~)
将一个数按位取反,即~ 0 = 1,~ 1 = 0。
5. 左移(<<)
将一个数左移x位,即左边丢弃x位,右边用0补x位。例:11100111 << 2 = 10011100。
拓展:
- 原码:一个整数按照绝对值大小转换为二进制即为原码;
- 反码:将二进制数按位取反,得到的即为反码;
- 补码:反码加1即为补码。
- 由于计算机底层硬件的限制,负数均使用补码表示。若左移时舍弃的高位全为0,则每左移1位,相当于该数十进制时乘一次2。
例:11(1011) << 2 = 44(11表示为1011时实际上不完整,若计算机中规定整型的大小为32bit,则11的完整二进制形式为00000000 00000000 0000000 00001011)
6. 右移(>>)
将一个数右移若干位,右边舍弃,正数左边补0,负数左边补1。每右移一位,相当于除以一次2。
例:4 >> 2 = 1,-14 >> 2 = -4。
7. 无符号右移(>>>)
将一个数右移若干位,左边补0,右边舍弃。
例:-14 >>> 2 = (11111111 11111111 11111111 11110010) >>> 2 = (00111111 11111111 11111111 11111100) = 1073741820