位运算
2015-06-13 09:36
211 查看
各种位运算的使用
=== 1. & 按位与 ===
& 运算通常用于二进制取位操作,例如一个数 & 1的结果就是取二进制的最末位。这可以用来判断一个整数的奇偶,二进制的最末位为0表示该数为偶数,最末位为1表示该数为奇数.
=== 2. | 按位或 ===
| 运算通常用于二进制特定位上的无条件赋值,例如一个数 | 1的结果就是把二进制最末位强行变成1。如果需要把二进制最末位变成0,对这个数 | 1之后再减一就可以了,其实际意义就是把这个数强行变成最接近的偶数。
===
3. ^ 异或 ===
^ 运算通常用于对二进制的特定一位进行取反操作,因为异或可以这样定义:0和1异或0都不变,异或1则取反。
^ 运算的逆运算是它本身,也就是说两次异或同一个数最后结果不变,即(a ^ b) ^ b = a。^ 运算可以用于简单的加密,比如我想对一 MM说1314520,但怕别人知道,于是双方约定拿我的生日123456789作为密钥。1314520 ^ 123456789 = 122667981,我就把122667981告诉MM。MM再次计算122667981
^ 123456789的值,得到1314520,于是她就明白了我的意思。
交换两个数的数值的时候就可以不用多声明一个临时变量,只需要进行x = x ^ y; y = x ^ y; x = x ^ y;对于给定的n个数值,然后给出n – 1个数值,判断哪一个数值没有出现也可以用 ^ 运算符。
=== 4. ~ 运算 ===
~ 运算的定义是把内存中的0和1全部取反。使用 ~ 运算时要格外小心,你需要注意整数类型有没有符号。如果 ~ 的对象是无符号整数,那么得到的值就是它与该类型上界的差,因为取反后的数和原来的数相加后每一位都是1,然后这个数是该类型最大的数。如果 ~ 的对象是有符号整数的话,那么得到的值应该是这个数的相反数减一,因为计算一个数的相反数,就是对一个数进行取反加一。
=== 5. << 运算 ===
a <<
b就表示把a转为二进制后左移b位(在后面添b个0)。例如100的二进制为1100100,而110010000转成十进制是400,那么100 << 2 = 400。可以看出,a << b的值实际上就是a乘以2的b次方,因为在二进制数后添一个0就相当于该数的二进制转化成十进制时乘的数值再乘2,就相当于整个数值乘二,例如一百的最右边的1,本来应该乘16,右移一位后,就是乘上32。
a << 1比a * 2更快,因为前者是直接操作内存。因此程序中乘以2的操作请尽量用左移一位来代替。
定义一些常量可能会用到 << 运算。你可以方便地用(1 <<
16) - 1来表示65535,
这边要注意<< 的优先级。很多算法和数据结构要求数据规模必须是2的幂,此时可以用
<< 来定义来这些数。
=== 6. << 运算 ===
和 << 相似,a >>
b表示二进制右移b位(去掉末b位),相当于a除以2的b次方(取整),原因类似于<<,这边要注意,右移在左边补的数值和符号位相同,如果是整数,右移补0,如果是负数,右移补1。我们也经常用 >> 1来代替
/ 2,比如二分查找、堆的插入操作等等。想办法用
>> 代替除法运算可以使程序效率大大提高。
Ps:
位操作的优先级一般都是比较低的,在位操作符中:
①
~ 的优先级最高,比+ - * / %还要高,其它的位操作符优先级都比它们低,遇到要记得加好括号,~是唯一一个从右往左计算的,如果遇到多个,则从右开始计算,其它位操作符都是从左往右计算,~也是唯一一个单目运算符;
②
<< 和 >>;
③
&;
④
^;
⑤
|;
常见的二进制变换操作
=== 1. & 按位与 ===
& 运算通常用于二进制取位操作,例如一个数 & 1的结果就是取二进制的最末位。这可以用来判断一个整数的奇偶,二进制的最末位为0表示该数为偶数,最末位为1表示该数为奇数.
=== 2. | 按位或 ===
| 运算通常用于二进制特定位上的无条件赋值,例如一个数 | 1的结果就是把二进制最末位强行变成1。如果需要把二进制最末位变成0,对这个数 | 1之后再减一就可以了,其实际意义就是把这个数强行变成最接近的偶数。
===
3. ^ 异或 ===
^ 运算通常用于对二进制的特定一位进行取反操作,因为异或可以这样定义:0和1异或0都不变,异或1则取反。
^ 运算的逆运算是它本身,也就是说两次异或同一个数最后结果不变,即(a ^ b) ^ b = a。^ 运算可以用于简单的加密,比如我想对一 MM说1314520,但怕别人知道,于是双方约定拿我的生日123456789作为密钥。1314520 ^ 123456789 = 122667981,我就把122667981告诉MM。MM再次计算122667981
^ 123456789的值,得到1314520,于是她就明白了我的意思。
交换两个数的数值的时候就可以不用多声明一个临时变量,只需要进行x = x ^ y; y = x ^ y; x = x ^ y;对于给定的n个数值,然后给出n – 1个数值,判断哪一个数值没有出现也可以用 ^ 运算符。
=== 4. ~ 运算 ===
~ 运算的定义是把内存中的0和1全部取反。使用 ~ 运算时要格外小心,你需要注意整数类型有没有符号。如果 ~ 的对象是无符号整数,那么得到的值就是它与该类型上界的差,因为取反后的数和原来的数相加后每一位都是1,然后这个数是该类型最大的数。如果 ~ 的对象是有符号整数的话,那么得到的值应该是这个数的相反数减一,因为计算一个数的相反数,就是对一个数进行取反加一。
=== 5. << 运算 ===
a <<
b就表示把a转为二进制后左移b位(在后面添b个0)。例如100的二进制为1100100,而110010000转成十进制是400,那么100 << 2 = 400。可以看出,a << b的值实际上就是a乘以2的b次方,因为在二进制数后添一个0就相当于该数的二进制转化成十进制时乘的数值再乘2,就相当于整个数值乘二,例如一百的最右边的1,本来应该乘16,右移一位后,就是乘上32。
a << 1比a * 2更快,因为前者是直接操作内存。因此程序中乘以2的操作请尽量用左移一位来代替。
定义一些常量可能会用到 << 运算。你可以方便地用(1 <<
16) - 1来表示65535,
这边要注意<< 的优先级。很多算法和数据结构要求数据规模必须是2的幂,此时可以用
<< 来定义来这些数。
=== 6. << 运算 ===
和 << 相似,a >>
b表示二进制右移b位(去掉末b位),相当于a除以2的b次方(取整),原因类似于<<,这边要注意,右移在左边补的数值和符号位相同,如果是整数,右移补0,如果是负数,右移补1。我们也经常用 >> 1来代替
/ 2,比如二分查找、堆的插入操作等等。想办法用
>> 代替除法运算可以使程序效率大大提高。
Ps:
位操作的优先级一般都是比较低的,在位操作符中:
①
~ 的优先级最高,比+ - * / %还要高,其它的位操作符优先级都比它们低,遇到要记得加好括号,~是唯一一个从右往左计算的,如果遇到多个,则从右开始计算,其它位操作符都是从左往右计算,~也是唯一一个单目运算符;
②
<< 和 >>;
③
&;
④
^;
⑤
|;
常见的二进制变换操作
功能 | 位操作 | 示例 |
x / 2n | x >> n | 1111 / 21 -> 111 |
x * 2n | x << n | 1111 * 21 -> 11111 |
2 * x + 1 | x << 1 | 1 | 100 * 2 + 1 -> 1001 |
把x的右起第n + 1位变成1 | x | 1 << n | 1000,3 -> 1100 |
把x最后n位变成1 | x | ((1 << n) – 1) | 1000, 3 -> 1111 |
对x的右起第n+ 1位取反 | x ^ 1 << n | 1111, 3 -> 1011 |
对x的右起n位取反 | x ^ ((1 << n) – 1) | 1101, 3 -> 1010 |
把x的右起第n + 1位变成0 | x & ~(1 << n) | 1111, 3 -> 0111 |
把x最后n位变成0 | x &~ ((1 << n) – 1) | 1, 3 -> 1000 |
取x的右起第n + 1位 | x >> n & 1 | 1101, 3 -> 1 |
取x的右起n位 | x & ((1 << n) – 1) | 1101, 3 -> 101 |
把x末位开始连续的1变成0 | x & (x + 1) | 1111 -> 0 |
把x末位开始连续的0变成1 | x | (x - 1) | 1000 -> 1111 |
把x的右起第一个0变成1 | x | (x + 1) | 1101 -> 1111 |
取x的右起第一个1 | x & -x | 1100 -> 100 |
把x的右起第一个1变成0 | x & ~(x & -x) | 1000 -> 0 |
取x末位开始连续的1 | (x ^ (x + 1)) >> 1 | 1011 -> 11 |
取int的绝对值 | (x ^ (x >> 31)) - (x >> 31) | 0xffffffff -> 0x1 |
int类型x高16位和低16位交换 | (x >> 16) | (x << 8) | 0x7fffffff -> 0xffff7ffff |
int类型x二进制逆序 | x = ((x & 0xAAAAAAAA) >> 1) | ((x & 0x55555555) << 1); x = ((x & 0xCCCCCCCC) >> 2) | ((x & 0x33333333) << 2); x = ((x & 0xF0F0F0F0) >> 4) | ((x & 0x0F0F0F0F) << 4); x = ((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8); x = ((x & 0xFFFF0000) >> 16) | ((x & 0x0000FFFF) << 16); | 0x1 -> 0x80000000 |
相关文章推荐
- oracle数据库常用命令
- oracle数据库常用命令
- LeetCode Implement Stack using Queues
- oracle数据库常用命令
- oracle数据库常用命令
- LeetCode Invert Binary Tree
- LeetCode Rectangle Area
- Windows 7 64bit上安装Oracle Database 12c [INS-30131] 错误的解决方法
- kiki's game(博弈)
- 2015061301 - 马王堆汉墓(下)
- 我的arduino小车图片
- ubuntu系统使用SSH免密码登陆
- android string.xml 特殊字符
- LinearGradient线性渲染
- ios网络学习------4 UIWebView的加载本地数据的三种方式
- Epic - Tic Tac Toe
- 深入解读PHP插件机制原理
- 欧几里德算法与扩展欧几里德算法
- 20150613课程内容
- 欧几里德算法与扩展欧几里德算法