详解 位运算

前言:在之前的博客《哥德巴赫猜想的验证》中,我们用到了位运算,极大地降低了运行时间,提高了运行效率,那么,在这篇博客中,我们就来介绍一下位运算的基本内容,以及《歌德巴赫猜想》中所用到的函数的原理吧。
首先,我来引用一下位运算的定义:

程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算就是直接对整数在内存中的二进制位进行操作。

在这句话中,我们要注意的是:
1.必须站在位的角度考虑运算,必须用二进制角度考虑运算;
2.要特别注意补码

那么,顾名思义,它是一类运算,那么,我来介绍一下它的运算符
1.按位与(&):
相同位的两个数字都为1,则为1;若有一个不为1,则为0。(全1为1,遇0则0
即:01010010 & 10100011 的结果是 : 00000010
按位与运算 主要用来取位操作,例如:假设要取一个8位二进制数最后一位,就让这个数和 00000001 按位与操作,这样一来,只需看结果最后一位为多少,那个8位二进制数的最后一位就为多少

2.按位或(|) :
相同位只要一个为1即为1。(遇1则1,全0为0
即:01010010 | 10100011 的结果是 : 11110011
按位或运算 主要用于二进制特定位上的无条件赋值,例如:假如要求将一个8位二进制数的第一位赋值为1,就让这个数和 10000000 按位或操作,这样得到的结果的二进制数的第一位一定是1

3.按位异或(^) :
操作的结果是如果某位不同则该位为1, 否则该位为0。(相同位0 ,不同为1
即:01010010 ^ 10100011 的结果是 : 11110101
按位异或运算 主要用于数字的简单加密,这用到了它的性质: ^ 的逆运算是它本身,例如:对于 01010010 进行加密,我将密钥设置为 10100011,那么,得到的加密结果是 11110101,于是,想要知道被加密对象,就需要加密结果和密钥进行一次异或运算,即:11110101 ^ 10100011就可以得到被加密对象:01010010

4.按位取反(~) :
把被操作数的0和1全部取反。(颠倒黑白
即:~ 01010010 的结果是 : 10101101
这里要注意的是处理无符号数和有符号数是有差别的,但是转换到二进制再进行操作的话结果就会很直观,所以,上面注意中的两句话还是很重要的!

5.左移(<<) :
将二进制下操作数,各位向左移动指定数目位,后面补0.(num << n,相当于num/(2的n次方)
即:01010010 << 1 的结果是 10100100

6.右移 (>>) :
右移可以分为两类,即:带符号右移,无符号右移。但是无符号右移仅存在于JAVA编译系统中。
这另类右移运算有所差异:(num >> n,相当于num*(2的n次方)
对于有符号数,符号位保留,其余位右移;
对于无符号数,所有位右移,前面补0

下图是位运算运算符的优先级表(从1到6,优先级依次降低):
在这里插入图片描述

以上,就是目前为止所有位运算的运算符以及主要用途。

那么,接下来,我就来介绍下《哥德巴赫猜想》中所用到的函数的基本原理:

第一个,置“1”函数(宏):
功能:将数 v 的从右往左数第 i 位置为 1
我们要置第 i 位为 1 ,其实是将 v 与 1 << ((i) ^ 7) 或运算,所以,得出以下宏:

#define SET(v, i) (v |= (1 << ((i) ^ 7)))

第二个,置“0”函数(宏):
功能:将数 v 的从左往右数第 i 位置为 0
我们要置第 i 位为 0 ,其实是将 v 与 ~(1 << ((i) ^ 7)) 或运算,所以,得出以下宏:

#define CLR(v, i) (v &= ~(1 << ((i) ^ 7)))

第三个,取数函数(宏):
功能:将指定位的数取出
这个宏就用到了上面提到的 & 的主要用途,所以,可以写成以下代码:

#define GET(v, i)((v) & (1 << ((i) ^ 7))) 
posted @ 2020-03-04 17:54  在下右转,有何贵干  阅读(482)  评论(0编辑  收藏  举报