位操作
来源:互联网 发布:孟加拉语翻译软件 编辑:程序博客网 时间:2024/05/17 23:11
转载自:http://www.ahathinking.com/archives/76.html
========目录=======
--位运算简介
--打印整型二进制 | 获取原码、反码、补码
--位运算技巧
==================
位运算简介
位运算的基本运算符有:and(&), or(|), xor(^), not(~), shl(<<), shr(>>),一般来讲,位运算符通常用于unsigned类型的整数。关于这六种运算符的简介,matrix67总结的很好,这里手抄一遍,部分做了修改和补充,加入了我的理解。
=== 1. and 运算 ===
and 运算通常用于二进制取位操作,例如一个数 and 1 的结果就是取二进制的最末位。这可以用来判断一个整数的奇偶,二进制最末位为0表示偶数,最末位为1表示位奇数。
and 运算符通常和一个称为“屏蔽码(mask)”的操作数一起使用,例如上面的1。屏蔽字是指定位置为1的整数值,用来选择一个值的某些位时隐藏其他位。and与屏蔽码一起使用有很多用处,例如
- 将指定位置0
- 测试某个位是1还是0
=== 2. or 运算 ===
or运算通常用于二进制特定位上的无条件赋值(将指定位置1),例如一个数 or 1 的结果就是把二进制最末位强行变成1。如果需要把二进制最末位变成0,对这个数or 1 之后再减一就可以了,其实际意义就是把这个数强行变成最接近的偶数。
=== 3. xor 运算 ===
xor 运算通常用于对二进制的特定位进行取反操作,因为异或可以这样定义:0和1异或0都不变,异或1则取反。
xor 运算的逆运算是它本身。也就是说两次异或同一个数最后结果不变,即(a xor b)xor b = a。xor 运算可以用于简单的加密,比如我想对MM说1314520,但怕别人知道,于是双方约定拿我的生日19880516作为密钥。1314520 xor 19880516 = 2066500,我就把20665500告诉MM。MM再次计算20665500 xor 19880516的值,得到1314520,于是她就明白了我的企图。 (matrix好有爱,哈哈)
逆运算可以延伸另外一个神奇的东西,例如,加法和减法互为逆运算,并且满足交换律。利用它们我们可以写出一个不需要临时变量的swap过程。
void swap(int &a, int &b) // 注,可能会导致越界(a+b){ a = a + b; b = a - b; a = a - b;}
刚才说xor的逆运算是它本身,于是我们就有了一个看起来非常诡异的swap过程:
void swap(int &a, int &b){ a = a ^ b; b = a ^ b; a = a ^ b;}
注,这样做木有用中间变量来的快,毕竟需要计算嘛,使用中间变量只是简单的赋值。
=== 4. not 运算 ===
not运算的定义是把内存中的0和1全部取反。根据我最近看书及做题的经验,not运算符经常配合移位运算符来制造“屏蔽码”,例如下面就是很常用的屏蔽码
- ~0 << n 右端n位置0
- ~(~0 << n) 右端n位置1
=== 5. shl 运算 ===
a shl b 表示把a转为二进制后左移b位(在后面添b个0)。例如100的二进制为1100100,而110010000转成十进制是400,那么100 shl 2 = 400。可以看出,a shl b的值实际上就是a乘以2的b次方。
通常认为a shl1 比a*2更快,因为前者更底层一些。因此程序中乘以2的操作请尽量用左移一位来代替。
此外,定义一些屏蔽码一般会用到shl运算,例如 1 << n 就是比较常用的屏蔽码。
再如很多算法和数据结构要求数据规模必须是2的幂,此时可以用shl来定义Max_N等常量,在下一篇位排序我们会看到。
=== 6. shr 运算 ===
和shl相似,a shr b 表示把a转为二进制后右移b位(去掉末b位),相当于a除以2的b次方(取整)。因此我们也经常用shr 1来代替div 2,比如二分查找,堆的插入操作等等。
想办法用shr代替除法运算可以使程序效率大大提高,例如最大公约数的二进制算法用除以2操作代替慢的出奇的mod运算,效率可以提高60%。(木有验证)
这里附上最大公约数的二进制算法
// 思想,先提取2的幂,然后辗转相减int gcd(int x, int y) //注,只适合处理整型{ int i, j; if(0 == x) return y; if(0 == y) return x; for(i = 0; 0 == (x & 1); ++i) //提取2的幂 { x >>= 1; } for(j = 0; 0 == (y & 1); ++j) { y >>= 1; } if(i > j) i = j; //辗转相减 while(1) { if(x < y) // 保证每次相减x>y { int t = x; x = y; y = t; // 使用中间变量,就不用异或了吧 } x -= y; if(0 == x) { return y<<i; } while(0 == (x & 1)) // 去掉2的幂 { x >>= 1; } }}
========================================================
打印整型二进制 | 获取原码、反码、补码
这一部分,在了解了位运算的基本知识后,我们实现了打印整型二进制,获取原码、反码和补码的代码,如下
#include<stdio.h> #define MAX 32 void IntToBinary(char binary[], int x); // x转换为二进制void IntToBinary2(char binary[], int x); // 不同的思路可以有多种方法void TrueForm(char binary[], int x); // 获得x的原码void RadixMinus(char binary[], int x); // 获得x的反码void Complement(char binary[], int x); // 获得x的补码 void main(){ char binary[MAX+1] = {0}; int number; printf("输入要测试的整型:"); scanf("%d",&number); IntToBinary2(binary,number); printf("%d 的二进制表示: %s\n",number,binary); TrueForm(binary,number); printf("%d 的原码: %s\n",number,binary); } void IntToBinary(char binary[], int x) // 由高位到低位转换{ for(unsigned int i = 0x80000000, j = 0; i > 0; i >>= 1) { binary[j++] = x & i ? '1':'0'; }} void IntToBinary2(char binary[], int x) // 由低位到高位转换{ for(int j = MAX-1; j >= 0; --j) { binary[j] = (x & 1) + '0'; x >>= 1; }} void TrueForm(char binary[], int x) // 对于负数,计算机存储的是补码{ if(x >= 0) { IntToBinary(binary,x); }else { IntToBinary(binary,(1<<(MAX-1))-x); // 由原码数学公式得 | 1<<n <=> 2^n }} void RadixMinus(char binary[], int x){ if(x >= 0) { IntToBinary(binary,x); }else { IntToBinary(binary,x-1); // 计算机存储的是补码,负数的反码等于补码减一 }} void Complement(char binary[], int x){ IntToBinary(binary,x);}
========================================================
位运算技巧
通过之前的整理,可以总结一下一些常用的位运算基本技巧,如下,设真值x,位数n
- 判断奇偶:x & 1
- 除以2的n次幂(乘法左移):x >> n
- 对2的n次幂取余:x & ~(~0<<n)
- 从低位开始,将x的第n位置1:x | (1<<n)
- 从低位开始,将x的第n位置0:x & ~(1<<n)
- 测试x的第n位是否为1:x & (1<<n)
- 最大的int (01 11111111 11111111 11111111): MAX_INT = ~(1<<31)
- 最小的int (10 00000000 000000000 00000000):MIN_INT = 1<<31
(全文完)
参考文献:
http://www.matrix67.com/blog/archives/263
http://kenby.iteye.com/blog/1011480
======================分割线===
我自己的总结:
要保存不变: 跟1与、 跟0或;
要置1: 跟1或;
要置0: 跟0与;
- 位操作
- 位操作
- 位操作
- 位操作
- 位操作
- 位操作
- 位操作
- 位操作
- 位操作
- 位操作
- 位操作
- 位操作
- 位操作
- 位操作
- 位操作
- 位操作
- 位操作
- 位操作
- 2013年10月福建综合性网站及社区网站综合影响力排名
- 网络编程:Reactor与Proactor的概念
- Action Bar for Android
- 如何正确删除ORACLE归档日志文件
- 或许对你创业有所启示:10个英国快速增长的科技创业公司
- 位操作
- mfc写入Excel
- Ogre源代码浅析——Mesh文件结构及加载
- 一个界面,有多个UITextField的时候,点击提交按钮发送数据时,取消键盘
- Android4.2.2 Gallery2源码分析(6)——GLView.java
- CI笔记
- DOS的主要功能和构成
- ode配置及使用(open dynamic engine)
- 如何使用<identity impersonate="true"/>