代码中一些有趣的二进制操作

二进制不是0就是1,有点枯燥乏味,对我们来说可能是没有十进制友好,但是对计算机却是很友好,计算机对二进制的处理可谓是手到擒来。其实代码中对二进制的使用也有很多有趣的操作,本篇就是对一些二进制操作的实例记录。(为了方便,下面的例子都是默认输入都是正整数,也没有多余的判断,可能不够严谨,目的只是为了体现二进制的一些操作而已)

1.奇数偶数的校验

偶数就是能被2整除的那些整数,所以就应该这么写:

num % 2 == 0

如果从二进制的角度考虑,偶数就是最右边的那个位子上的是0而不是1,所以也可以这样写:

(number & 1) == 0

2.判断是否为2的幂次方

2的幂次方,从二进制上可以很快找到规律,比如1,2,4,8,16...

对应的二进制位1,10,100,1000,10000...

可以发现其实就最高位(左边那位)是1,其他位全是0,也就是说只有一个bit位上是1,那么由当前数做个减一的操作,就变成了最高位是0,而右边的所有位都变成1了,再做个&与操作,得到的结果就一定位0:

(n & (n - 1)) == 0

3.求当前输入输的下一个2的幂次方的数(如果本身输入就是幂次方,那么就返回自己即可),这个就是Unity中的Mathf.NextPowerOfTwo(int n)

有了上面的那个分析,沾到2的幂次方相关的一些操作,其实思考方向从二进制出发就变的清晰明了多了,而且时间复杂度也只有O(1)。

如果当前输入的不是2的幂次方,那么他的NextPowerOfTwo的特点就是当前二进制数的最高位的左边相邻的那一位位1,其他全是0,比如输入为9(1001),那么输出结果应该是16(10000)。关键点就是找到那个最高位的左边那位,在做修改即可,但是要怎么用代码来实现呢(本人暂时没有想到),参考源码发现,这个的实现思路是这样的,反过来想,那就想办法从左边第一个1开始后面的所有位都变为1,然后加1,就全部进位操作,只剩下最高位是1,完美,一个int占4个字节,也就是32位,下面的五次右移和或操作是为了保证32位全部操作到位(当然,如果比较小的数比如9,进行两次右移操作其实已经达到目标了)

    public static int NextPowerOfTwo(int n)
    {
        n--; //减一是为了保证输入的已经是2的n次方的数输出也是自己本身,否则就得到2^(n+1)
        n |= n >> 1;
        n |= n >> 2;
        n |= n >> 4;
        n |= n >> 8;
        n |= n >> 16;
        n++;

        return n;
    }

 

4.和3类似,求当前输入的前一个2的幂次方的数

这个想找的数,二进制的特点是输入的数只保留左边最高位1即可,剩下的低位全设为0,然后就是想办法找到当前数最高位到底在哪一位,又回到上面的分析中,既然我们已经找到了他的下一个,那么他的前一个数不就是他的下一个除以二这么简单吗。

return NextPowerOfTwo(int n) >> 1;

5.交换整数a,b的值

常规操作

int temp = a;
a = b;
b = temp;

如果用二进制的位操作运算,则需要用到异或(^)操作符,这个位运算的意思就是同样的为0,不同的为1,就是说 1^1 = 0^0 = 0, 而 1^0 = 0^1 = 1,所以可以得出 a ^ a = 0, a ^ 0 = a,这一步则是二进制操作两个整数互换的关键所在:

a = a ^ b;
b = a ^ b;    // a ^ b ^ b = a;
a = a ^ b;    // a ^ b ^ a = b;
发布了23 篇原创文章 · 获赞 6 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Vitens/article/details/105007475