位运算的奇技淫巧

本文深入探讨了位运算的基本概念,包括与(&)、异或(^)等操作的特性及应用,例如判断奇偶性、交换变量值、求绝对值等。同时,通过实例讲解了如何利用位运算进行高效的数据处理,如快速查找重复数字、实现加减乘除等数学运算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

T0 给定0-1之间double类型实数,给出他的二进制表示,32位之内无法表示输出ERROR 

string s = "0.";
while(n != 0)
{
    n *= 2;
    if(n > 1)
    {
        s.append("1");
        n -= 1;
    }
    else
        s.append("0");
    if(s.lenght() > 34)
    {
        cout<<"ERROR";
        return 0;
    }
}
cout<<s;

与&

T1 判断奇偶性,与1做&

T2 输出某整数二进制表示中1的个数 

while(n != 0)
{
    count++;
    n = n & (n-1);
}
cout<<count;

T3 用一条语句判断某一整数是不是2的整数次方

if(n & (n-1) == 0)
    cout<<"yes";
else
    cout<"no:;

异或^

简单理解就是不进位加法,如1+1=0,,0+0=0,1+0=1。性质:

1、交换律

2、结合律(即(a^b)^c == a^(b^c))

3、对于任何数x,都有x^x=0,x^0=x

4、自反性 A XOR B XOR B = A xor  0 = A

简单例题

T1 交换两个整数变量的值,三次异或。注意:当两个指针变量指向同一个地址的数据时,只有传统写法可以工作。原因是异或写法直接在原地址上进行值运算,一次异或之后值就成了0,两个指针都指向这个地址,后面再怎么异或也只能是0。在应用中,如果要使用异或写法来交换元素,就得确保所传两个地址不一样,否则就会出现这话总错误。

a = a^b;b = a^b;a = a^b;

T2 不用判断语句求整数绝对值

b = (b^(b>>31)) - (b>>31);//^运算符的优先级低于- 补码!补码!补码!

T3 交换整数奇偶位

int out,even = 0xAAAAAAAA,odd = 0x55555555;
out = ((n & even) >> 1) ^ ((n & odd) << 1);

T4 找出重复一次的数,不使用辅助空间,每个数组元素只访问一次 (类似数组中数字都出现了偶数次,只有一个出现奇数次,找出奇数次的数)

//不用辅助空间 (数组内数字均在一定范围,如1~m,都有出现)
int ans = 0;
for(int i=1;i<=m;i++)
    ans = ans ^ arr[i];
for(int j=0;j<n;j++)
{
	ans = ans ^ arr[j];
}
cout<<ans;
//使用辅助空间,类似直方图 ,若没有说明数字范围,则不能异或,用此方法 
int *helper = new int [n];
for(int i=0;i<n;i++)
{
	helper[arr[i]]++;
}
for(int i=0;i<n;i++)
{
	if(helper[i]==2)
	{
		cout<<endl<<i;
		break;
	}
}
delete []helper;	

T5 位运算做加减乘除

//位运算实现加法
int addBit(int num1,int num2)
{
	int sum,carry;
	while(num2 != 0)
	{
		sum = num1 ^ num2;
		//cout<<"sum = "<<sum<<endl;
		carry = (num1 & num2)<<1;
		//cout<<"carry = "<<carry<<endl;
		num1 = sum;
		num2 = carry;
	}
	return sum;
} 
//位运算实现减法(实质仍为加法,数字在计算机中用补码存储,对数字进行求反加1即为该数字的相反数的补码表示) 
int minusBit(int num1,int num2)
{
	return addBit(num1,addBit(~num2,1));//-num2 = ~num2 + 1 = Add(~num2,1) 
}
//位运算实现乘法
int multiplyBit(int num1,int num2)
{
	if(num1 == 0 || num2 == 0)
		return 0;
	//先将被乘数与乘数全部弄为正数
	int multiplicand = (num1 > 0)? num1 : addBit(~num1,1);
	int multiplier = (num2 > 0)? num2 : addBit(~num2,1);
	int res = 0;
	while(multiplier > 0)
	{
		//如果最后一位是1,则进行加运算
		if((multiplier & 0x1)== 1)
			res = addBit(res,multiplicand);
		//无论是否进行了加运算,都将被乘数左移一位,乘数右移一位
		multiplicand <<= 1;
		multiplier >>= 1;
	}
	//恢复符号,num1^num2为负值时表示两者异号,相乘必为负值
	//(注意<优先级高于^,记得加括号)
	if((num1 ^ num2) < 0)
		return addBit(~res,1);
	else
		return res;
	
}
//位运算实现除法
int divideBit(int num1,int num2)
{
	if(num1 == 0)
		return 0;
	if(num2 == 0)
		return -1;
	//先将被除数与除数全部弄为正数
	int dividend = (num1 < 0) ? addBit(~num1,1) : num1;
	int divisor = (num2 < 0) ? addBit(~num2,1) : num2;
	int quotient = 0;
	int remainder = 0;
	//用除数的231, 230, …, 22, 21, 20倍尝试去减被除数(31,30……,2,1,0为上标) 
	for(int i=31;i>=0;i--)
	{
		//注意这里的dividend与divider比较,是将dividend右移i位而不是将divider左移i位
		//目的在于避免divider左移i位后有些数据丢帧
		if((dividend >> i) >= divisor)
		{
			
			//如果(dividend >> i) >= divider,表示dividend除divide的值大于1<<i,则将1左移i位并加入到商中
			//此时表示从dividend中减去了1<<i个divide,所以dividend的值也跟着更新
			quotient = addBit(quotient,1<<i);
			dividend = minusBit(dividend,divisor<<i);
		}
	}
	//余数符号 
	remainder = (num1 < 0) ? addBit(~dividend,1) : dividend;
	//恢复商符号 
	if((num1 ^ num2) < 0)
	{
		quotient = addBit(~quotient,1);
	}
	cout<<"商:"<<quotient<<"\t";
	cout<<"余数:"<<remainder<<endl; 
	return quotient;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值