清零取反要用与,某位置一可用或
若要取反和交换,轻轻松松用异或
原操作数: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)
1. 常用来将源操作数某些位置1,其它位不变。 (mask中特定位置1,其它位为0 s=s|mask)
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)
00001010 << 2 = 00101000
00001010 >> 2 = 00000010 10001010 >> 3 = 11110001
a << = 1 ; //a左移一位等效于a = a * 2;
右端对齐,如是正数:左端补满0;b是负数,左端布满1;
1. 先使a右移4位:a>>4
2. 设置低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;一直这样计算,直到将每一位都判断完毕。
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次方,则这个数的最高位是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的异或结果可以得知两数不同位的个数,再调用计算一个数中1的个数的方法,即可得到结果。
/* 求解n变化为m,需要进行的操作步数 */
int countChange(int n,int m)
{
n = n ^ m; //求n和m的异或,再计算结果中1的个数
return countOf1_2(n);
}
/* 获取最大的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 得到结果:-2147483648 */
int getMinInt()
{
return 1 << 31;
}
/* 同样在g++下编译,出现warning: left shift count is negative */
int getMinInt_2()
{
return 1 << -1;
}
/* 求最大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);
}
/* 获取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));
}
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,正数
int isneg(int a)
{
return a & 0x8000;
}
int iszero(int a)
{
return !(a & 0xFFFF);
}
int ispos(int a)
{
return (a&0xFFFF) && !(a&0x8000);
}
写出一个 β 位整数除以一个短整数的有效算法,以及求一个 β 为整数除以一个短整数的余数有效算法,给出的是时间是 O(β2)
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;
}