二进制与十进制的转换
十进制->二进制
正整数
除二取余,逆序排列,高位补0
负整数
先是将对应的正整数转换成二进制后,对二进制取反,然后对结果再加一
小数
对小数点以后的数乘以2,然后取其结果的整数部分(不是1就是0),然后再用小数部分再乘以2,再取结果的整数部分……以此类推,直到小数部分为0或者位数已经够了就OK了。然后把取的整数部分按先后次序排列,就构成了二进制小数部分的序列
当小数除不尽的时候,一般取八位(或按要求)
混合数
二进制->十进制
正整数
从二进制的右边第一个数开始,每一个乘以2的n次方,n从0开始,每次递增1。然后得出来的每个数相加即是十进制数。
例如:
二进制的数110化为十进制:
0*2^0+1*2^1+1^2^2=6
负整数
如果补齐之后,最高位是1,则说明是负数
- 方法一:先减一,再取反,再加上负号
- 方法二:先取反,再加一,再加上负号
小数
原码、反码、补码的转换
(1) 正数的原码、反码、补码相同
(2) 负数的原码、反码、补码转换如下图所示
需要说明的是,在计算机中,数字是以补码的形式存在的,计算也是用补码来进行计算,计算后的结果也是补码
位运算
下表列出了位运算符的基本运算,假设整数变量 A 的值为 60 和变量 B 的值为 13:
(1) & : 按位与
5 & 9 = 1
(2) | : 按位或
5 | 9 = 13
(3) ^ : 按位异或
5 ^ 9 = 12
(4) ~ : 按位非
~5 = -6
(5) << : 左移
5 << 2 = 20
-5 << 2 = -20
(6) >> : 右移
-5 >> 2 = -2
(7) >>> : 无符号右移
-5 >>> 2 = 1073741822
应用
左移
左移常常被用来 *(2^n)的运算
8<< 1 -> 8 * 2=16
8<< 2 -> 8 * (2^2)=32
8<< n -> 8 * (2^n)
右移
右移常被用来做 / (2 ^ n)的运算,
12 >> 1 = 6
12 >> 2 = 3
12 >> n = 12 /(2^n)
位与
- 二进制位与运算相当于对应位相加之后的进位 ,例如:
1 & 1 = 1 (当前位的值进一位)
1 & 0 = 0(当前位的值不进位)
0 & 0 = 0 (当前位的值不进位)
计算二进制中有多少个 1(32位)
由 x & (x-1)
消去x最后一位知。循环使用x & (x-1)
消去最后一位1,计算总共消去了多少次即可。
Loading Question… - 力扣(LeetCode)
public class Solution {
// you need to treat n as an unsigned value
public int hammingWeight(int n) {
int count = 0;
for (int i = 0; i < 32; ++i) {
count += n & 1;
n >>>= 1;
}
return count;
}
public int hammingWeight2(int n) {
int res = 0;
while (n != 0) {
res += 1;
n &= n - 1;//可以把n的最后一个1变成0
}
return res;
}
}
取模运算转化成位运算
(在不产生溢出的情况下)
-
a % (2^n)
等价于a & (2^n - 1)
-
a % 2
等价于a & 1
判断奇偶数
利用 &位运算符的特性,判断二进制数第一位是0还是1。
用if ((a & 1) == 0)
代替if (a % 2 == 0)
来判断a是不是偶数。
异或
- 二进制位的异或运算相当于位相加,例如:
1 ^ 1 = 0 (当前位值为 0 进一位)
1 ^ 0 = 1 (当前位值为 1)
0 ^ 0 = 0 (当前位值为 0)
交换两个数
使用 ^位运算符的特性,不使用临时变量实现两个数的交换。
a ^= b;
b ^= a;
a ^= b;
a=10,b=1
a=11
b=10
a=1
eg a=10,b=10,c=a^b=0,可以实现相加的效果,但是没有进位的效果
因此 ^ & <<可以一起实现+的效果
题目链接
public int add(int a, int b) {
while(b != 0){
int temp = a ^ b;//计算出相对应的位置相加后的结果,非进位和
b = (a & b) << 1;//计算出想对应的位置的进位,然后左移一位
a = temp;
}
return a;
}