C语言:位运算
来源:互联网 发布:linux dhcp设置dns 编辑:程序博客网 时间:2024/06/07 23:38
移位运算
清零取反要用与,某位置一可用或若要取反和交换,轻轻松松用异或
原操作数:s;掩码:mask
与 (&) …… 0 & 0 = 0……. 1 & 0 = 0 ……0 & 1 = 0……1 & 1 = 1 ( AND)
1. 清零特定位: (mask中特定位置0,其它位为1,s=s&mask)2 取某数中指定位 (mask中特定位置1,其它位为0,s=s&mask)
- 或 (|) ……. 0 | 0 = 0……… 1 | 0 = 1…… 0 | 1 = 1…….. 1 | 1 = 1 ( OR )
1. 常用来将源操作数某些位置1,其它位不变。 (mask中特定位置1,其它位为0 s=s|mask)
- 异或(^)…….0 ^ 0 = 0……. 1 ^ 0 = 1… 0 ^ 1 = 1…. 1 ^ 1 = 0 ( XOR )
1 使特定位的值取反(mask中特定位置1,其它位为0 s=s^mask)1111010^00001111=01110101 2 与0^,保留原值:00001010^00000000=00001010 3 交换:3和4 a=a^b :a=011 ^ b=100=>a=111 (a=7) b=b^a :b=100 ^ a=111=>b=011(b=3) a=a^b :a=111 ^ b=011=>a=100(a=4)
- 左移运算符m
<< n表示吧m左移n位,左移n位的时候,最左边的n位将被丢弃,同时在最右边补上n个0.比如:
00001010 << 2 = 00101000
- 右移运算符m>>n表示把m右移n位。右移n位的时候,最右边的n位将被丢弃。逻辑右移和算术右移。逻辑右移在左端补k个0;算术右移是在左端补k个最高有效位的值。
00001010 >> 2 = 0000001010001010 >> 3 = 11110001
- 把整数右移一位和把整数除以2在数学上是等价的。
- 把整数左移一位和把整数乘以2在数学上是等价的。
a << = 1 ; //a左移一位等效于a = a * 2;
- 不同长度数据,进行位运算
右端对齐,如是正数:左端补满0;b是负数,左端布满1;
例子
- 取一个整数a的4-7位:
1. 先使a右移4位:a>>42. 设置低4位全是1,其余是0;~(~0<<4);~的优先级高3. (a>>4)& ~(~0<<4)
- 循环移位
//a进行循环右移将a右循环n位,将a中的原来的左边(16-n)右移,右端的n位移动到最左端1. 将a的右端n位,放到b的高n位:b=a<<(16-n)2. a右移n位,左边n位补零: c=a>>n;3. 将c与b按位或运算,c=c|b
位运算技巧
- 计算一个数的二进制中1的个数
//通过与初始值为1的标志位进行与运算,判断最低位是否为1;然后将标志位左移,判断次低位是否为1;一直这样计算,直到将每一位都判断完毕。int countOf1(int num) { int count = 0; unsigned int flag = 1; while(flag) { if(num & flag) { count++; } flag = flag << 1; } return count; } //还有一种方法,一个整数减一,可以得到该整数的最右边的1变为0,这个1右边的0变为1。对这个整数和整数减一进行与运算,将该整数的最右边的1变为0,其余位保持不变。直到该整数变为0,进行的与运算的次数即为整数中1的个数。int countOf1_2(int num) { int count = 0; while(num) { num = num & (num - 1); count++; } return count; }
- 判断一个数是否是2的n次方
一个数是2的n次方,则这个数的最高位是1,其余位为0。根据上一题的第二种解法可以很容易得到解决方案。将这个整数与整数减一进行与运算,如果得到的结果为零,可证明该数为2的n次方。/* 判断一个数是否为2的n次方(一个数为2的n次方,则最高位为1,其余位为0) */ bool is2Power(int num) { bool flag = true; num = num & (num - 1); //计算num和num - 1的与的结果 if(num) //如果结果为0,则不是2的n次方 { flag = false; } return flag; }
- 整数n经过多少步可以变为整数m
n和m的异或结果可以得知两数不同位的个数,再调用计算一个数中1的个数的方法,即可得到结果。/* 求解n变化为m,需要进行的操作步数 */ int countChange(int n,int m) { n = n ^ m; //求n和m的异或,再计算结果中1的个数 return countOf1_2(n); }
- 获得最大的int值
/* 获取最大的int 得到结果:2147483647 */ int getMaxInt() { return (1 << 31) - 1; } /* 使用g++编译,出现warning: left shift count is negative */ int getMaxInt_2() { return (1 << -1) - 1; } int getMaxInt_3() { return ~(1 << 31); } /* 在不了解int的长度情况下使用 */ int getMaxInt_4() { return ((unsigned int) -1) >> 1; }
- 获得最小的int值
与获得最大的int方法类似。/* 求最小int 得到结果:-2147483648 */ int getMinInt() { return 1 << 31; } /* 同样在g++下编译,出现warning: left shift count is negative */ int getMinInt_2() { return 1 << -1; }
- 获得最大的long
/* 求最大long 得到结果:9223372036854775807 */ long getMaxLong() { return ((unsigned long) -1) >> 1; }
- 判断一个数的奇偶性
判断奇偶性,实质是判断最后一位是否是1.bool isOdd(int num) { return num & 1 == 1; }
- 交换两个数(不借助第三变量)
/* 不适用临时变量,交换两个数 a = a ^ b b = b ^ a a = a ^ b */ void mySwap(int* a,int* b) { (*a) ^= (*b) ^= (*a) ^= (*b); }
- 求一个数的绝对值
下面的方法实现的基础是将n右移31位,可以获得n的符号。/* 取绝对值 n右移31位,可以获得n的符号。若n为正数,得到0;若n为负数,得到 -1 */ int myAbs(int n){ return (n ^ n >> 31) - (n >> 31); }
- 求两个数的平均值
第一种方法较为普遍且简单,不多说了。第二种方法,需要知道的是,( m ^ n ) >> 1得到的结果是m和n其中一个数的有些位为1的值的一半,m & n得到的结果是m 和n都为1的那些位,两个结果相加得到m和n的平均数。/* 求m和n的平均数 */ int getAverage(int m,int n){ return (m + n) >> 1; } /* 求m和n的平均数 (m ^ n) >> 1 -> 获得m和n两个数中一个数的某些位为1的一半 m & n -> 获得m和n两个数中都为1的某些位 */ int getAverage_2(int m,int n){ return ((m ^ n) >> 1) + (m & n); }
- 求解倒数第m位相关问题
/* 获取n的倒数第m位的值(从1开始计数) */ int getMthByTail(int n,int m){ return (n >> (m - 1)) & 1; } /* 将n的倒数第m位设为1 */ int setMthByTail21(int n,int m) { return n | (1 << (m - 1)); } /* 将n的倒数第m位设为0 */ int setMthByTail20(int n,int m) { return n & ~(1 << (m - 1)); }
四则运算的位表示
- 加法运算
int Add(int a, int b) { int ans; while(b) { //直到没有进位 ans = a^b; //不带进位加法 b = ((a&b)<<1); //进位 a = ans; } return a; }
- 减法运算
int negtive(int a) //取补码 { return Add(~a, 1); } int Sub(int a, int b) { return Add(a, negtive(b)); }
- 乘法运算:原理上还是通过加法计算。将b个a相加,注意下面实际的代码。
int Multi(int a, int b) { int ans = 0; while(b) { if(b&1) ans = Add(ans, a); a = a << 1; b = b >> 1; } return ans; }
- 正数除法:
//除法就是由乘法的过程逆推,依次减掉(如果x够减的)y^(2^31),y^(2^30),...y^8,y^4,y^2,y^1。减掉相应数量的y就在结果加上相应的数量。 int Divide(int a, int b) { int coun = 0; while(a >= b) { a = Minus(a, b); coun = Add(coun, 1); } return coun; }
- 判断是否是0.正数,负数
//判断是否是负数,0,正数 int isneg(int a) { return a & 0x8000; } int iszero(int a) { return !(a & 0xFFFF); } int ispos(int a) { return (a&0xFFFF) && !(a&0x8000); }
31.1-11
写出一个
http://blog.csdn.net/z84616995z/article/details/21945197
http://blog.163.com/luowei505050@126/blog/static/1199072062011102415243718/
//位运算#include <iostream> using namespace std; //位运算乘法乘法就是将乘数写成(2^0)*k0 + (2^1)*k1 + (2 ^2)*k2 + ... + (2^31)*k31,其中ki为0或1,然后利用位运算和加法就可以了。int bit_Multiplication(int a,int b) { int ans=0; for(int i=1;i;i<<=1,a<<=1) { if(b&i) { ans+=a; } } return ans;}//位运算的除法 除法就是由乘法的过程逆推,依次减掉(如果x够减的)y^(2^31),y^(2^30),...y^8,y^4,y^2,y^1。减掉相应数量的y就在结果加上相应的数量。int bit_Division1(int x,int y) { int ans=0; for (int i=31;i>=0;i--) { //比较x是否大于y的(1<<i)次方,避免将x与(y<<i)比较,因为不确定y的(1<<i)次方是否溢出 if ((x>>i)>=y) { ans+=(1<<i); x-=(y<<i); } } return ans; } //计算整数的二进制位数 int bit_num(int d) { int i=0; while (d) { d>>=1; i++; } return i; } //位运算的除法 计算商 int bit_Division2_quotient(int x,int y) { int c2=bit_num(x),c1=bit_num(y),quotient=0; for (int i=c2-c1;i>=0;i--)//i=c2-c1防止除数y移位后超过无符号整数最大值 时间复杂度O(c2-c1) { unsigned int a=(y<<i);//有了i=c2-c1保证了y<<i不会溢出 a有c1+c2-c1=c2位 if (a<=x) { quotient+=(1<<i); x-=a; } } //总的时间复杂度为 O(c2)=O(x的二进制位数)=O(b^2) b为除数的十进制位数 return quotient; } //位运算的除法 计算余数 与计算商一样,只是返回值不同 int bit_Division2_Remainder(int x,int y) { int c2=bit_num(x),c1=bit_num(y),quotient=0; for (int i=c2-c1;i>=0;i--)//i=c2-c1防止除数y移位后超过无符号整数最大值 时间复杂度O(c2-c1) { unsigned int a=(y<<i);//有了i=c2-c1保证了y<<i不会溢出 a有c1+c2-c1=c2位 if (a<=x) { quotient+=(1<<i); x-=a; } } //总的时间复杂度为 O(c2)=O(x的二进制位数)=O(b^2) b为除数的十进制位数 return x; } void main() { cout<<bit_Multiplication(350,43)<<endl; cout<<bit_Division1(350,43)<<endl; cout<<"商:"<<bit_Division2_quotient(350,43)<<endl; cout<<"余数:"<<bit_Division2_Remainder(350,43)<<endl; }
31.1-12
0 0
- C语言位运算
- C语言位运算
- C语言位运算
- c语言位运算
- C语言位运算
- c语言位运算
- C语言位运算
- c语言位运算
- C语言位运算
- C语言位运算
- C语言位运算
- C语言位运算
- c语言位运算
- C语言位运算
- c语言位运算
- C语言位运算
- C语言位运算
- c语言位运算
- 开启自己的博客之旅,
- QA:UICollectionView不能选中问题
- PHP获得真实客户端的真实IP REMOTE_ADDR,HTTP_CLIENT_IP,HTTP_X_FORWARDED_FOR
- Spring的声明式事务管理
- 1月22日--1月31日(剩3195小时)
- C语言:位运算
- Simple Java—Compiler and JVM(一)Java对象运行时的内存结构
- Django微信开发
- Python Closure 闭包
- 基于OpenWrt防火墙配置(作为二级路由)
- 基于直方图的图像增强算法(HE、CLAHE、Retinex)之(一)
- DockerTool在Windows上的配置和运行
- hdu 2137 circumgyrate the string
- 给 spine slot 绑定node