某种程度上讲,二进制也算一种算法?
前言
二进制从定义上讲只是一种数字表示方式。
与你们人类使用的十进制不同,二进制表示法中只有0和1两个数位。
例如,十进制下的 19 在二进制下就表示为 10011(注:所有二进制数均省略二进制表示法)。
十进制转换为二进制
二的幂分解
首先需要了解常用的二进制整数(即 2 的幂):2,4,8,16,32,⋯。
对于一个十进制数,从大到小分解:19=16+2+1=24+21+20,所以就表示为 10011。
倒序取余
这个方法更常用一些,但是原理不容易理解。具体操作过程如下:
- 对于一个数 N0,取它除以 2 的商 N1 和余数 r0。
- 对得到的 N1 重复第一步操作,得到商 N2 和余数 r1。
- 重复操作至商 Nn=0。
- 找到所有余数 r0,r1,⋯,rn−1(共 n 个余数)。
- 将余数倒序书写:rn−1,⋯,r1,r0,得到的就是 N0 的二进制表示法。
二进制转换为十进制
例如一个二进制数是 11010,从右到左依次是第 0,1,2,3,4 位。
所以,十进制表示法就是:
1×24+1×23+0×22+1×21+0×20
补码表示法
为了使用0和1表示负数,我们使用补码表示法。
具体是这样的:2 在二进制(一个字节)中是 0000 0010,为使 −2+2=0,只需要让 −2 用 1110 1110 表示(忽略溢出位)即可。
对于任意的一个正数,对其取反再加 1 就得到了对应负数的补码表示法。
那么反过来,一个负数先减 1 再取反就是对应的正数。
位操作/位运算
接下来进入程序部分!
首先,定义两个二进制数。
1 2 3
| int a = 0b11010; int b = 0b110100; int ans = 0;
|
对于一般的编程语言,常见的位运算包括:
- 或:两个数只要有一个数为 1,结果就为 1。
- 非:0 变成 1,1 变成 0,即取反。
int具有 32 个二进制位,需要把所有的 0 都取反!
思考:如果a的类型是short或者long long,结果会有不同吗?
- 异或:两个数相同的时候结果为 0,不同则为 1(最常用)。
- 左移:将数字整体左移 n 位(注意:不要让它溢出!)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
ans = a << 1;
ans = a << 3;
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
ans = a >> 1;
ans = a >> 3;
|
补充
lowbit 函数可以获得一个数字的二进制表示中,最低位的 1 及其后面的 0 表示的数。
例如:
- lowbit(3)=lowbit((11)2)=1
- lowbit(6)=lowbit((110)2)=2
- lowbit(100)=lowbit((110 0100)2)=4
实现方式:lowbit(x)=x & (-x)。
这个函数是内置函数,可以直接使用。
作用为:获取最低位的 1 所在的位置(从 1 开始)。
例如:
- __builtin_ffs(2)=__builtin_ffs((10)2)=2
- __builtin_ffs(3)=__builtin_ffs((11)2)=1
- __builtin_ffs(100)=__builtin_ffs((110 0100)2)=3
- __builtin_ffs(1024)=__builtin_ffs((100 0000 0000)2)=11