细数那些位运算的骚操作(持续更新)


无论在C语言的学习的过程中还是ARM裸机的学习过程中,我们总会遇到有关位运算的问题,这里就细数一下那些位运算的骚操作吧!!!。

1.置位和位清除

开发过程中时常会操作寄存器,比如一个16位的,每一位都有不同的作用,我们要在不影响其他位的情况下,对特定的某一位(某些位)来就行置位、位清除操作。

置位操作结合或运算|、位清除操作结合与运算&和~取反

比如ARM裸机开发中要点亮LED,首先要对GPFCON寄存器进行配置,需要将此寄存器中的[9:8]位配置为01

在这里插入图片描述

相当于对位9清除、位8置位

GPFCON |= (1<<8);
GPFCON &= ~(1<<9);

2.交换变量

初学C语言时,交换变量的操作无非有俩种:引入新变量、相加相减

引入新变量很简单,这里简单提及一下俩变量相加相减的方法:

int a=2,b=3;
a = a+b;  //a=2+3
b = a-b;  //b=2+3-3=2
a = a-b;  //a=2+3-2=3

还可以通过位运算进行俩个变量的交换,就是异或运算^,对异或运算要了解:

俩个相同的数异或结果为0,一个数异或0的结果是这个数本身。

所以,利用异或运算可以交换俩个变量:

int a=2,b=3;  //a=010 b=011
a = a^b;  //a=010^011
b = a^b;  //b=010^011^011=010^0=010
a = a^b;  //a=010^011^010=011^0=011
/*用一句代码也可以实现*/
a^=b^=a^=b;

利用异或的性质:相同的数异或为0,与0异或为本身。

3.判断整数奇偶性

判断一个二进制数的奇偶性,只需要看0位的值是1还是0.

if( x&1 == 1 )
    printf("奇数\n");
else
    printf("偶数\n");

4.求2的次方

移位:左乘右除

x << n ;  //x乘以2的n次方
x >> n ;  //x除以2的n次方
x << 3 ;  //x*2^3
x >> 4 ;  //x/(2^4)

5.求俩个整数的平均数

求俩个数的平均数就是和除以2,可以用移位运算来实现:

x = (a+b) >> 1;  //x为a、b的平均数

6.取int绝对值

/*取int型数据x的绝对值*/
int abs( int x )
{
	return ( x^(x>>31) - (x>>31) );    
}

如果x为正数,即最高位符号位是0,则(x>>31)=0,x^0=x,返回的是x;

如果x为复数,即最高位符号位是1,则(x>>31)=-1,x^(-1),要计算补码再进行异或运算,结果为|n|-1(绝对值n-1),所以在后面要通过:-(x>>31)来+1.使结果为-n,即n的绝对值。

7.比较俩个int数的大小

以前比较俩个数的大小都是采用三目运算符:a>b?a:b,可以采用位运算来求出俩个数的大小,如示,调用max函数既可以返回较大的一个数:

方法一:

和-1作与运算结果不变

/*输出最大数*/
int max( int a, int b )
{
    return  b & ( (a-b)>>31 ) | a & ( ~(a-b)>>31 );
}

如果b大,则(a-b)>>31为-1,b&-1=b,或运算|第一个为真,结束运算,直接返回b;

如果a大,则(a-b)>>31为0,b&0=0,或运算|进入下一个判断,(~(a-b)>>31)=-1,a&-1=1,返回a。

方法二:

与0异或为本身,与自己异或为0

/*输出最大数*/
int max( int a, int b )
{
    return a ^ ( (a^b) & -(a<b) );
}

首先要判断(a<b)的真假:

如果(a<b)为真,即1,即(ab)&-1=ab,则表达式就变为aab=b,返回较大的b;

如果(a<b)为假,即0,即(ab)&0=0,则表达式就变为a0=a,返回较大的a。

8.判断俩个int数符号是否相同

利用了最高位符号位:正数符号位为0,负数符号位为1

(a^b) < 0    //a、b异号
(a^b) >= 0   //a、b同号

9.不用加减乘除作加法

题目: 写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

先了解十进制中的加法步骤,比如:21+192

首先,所有位相加,不进位,得到113

然后,计算进位值,得到100

然后,进位值与相加值(不进位)相加,得到213

然后,计算进位值,得到0

最后,当新的进位值为0时,即得到最终结果

这就是十进制下的加法,可以看出来,十进制加法的求解时,是处于一个循环的,先在每个位做不进位加法,然后求出进位值,然后使俩者相加,循环,直到进位值为0,得出最终结果。

所以,核心思想在于:

  • 每个位实现不进位加法
  • 求出进位值
  • 循环上述直到进位值为0

在二进制中,俩个数的不进位加法就是异或运算^,求进位值就是与运算左移一位。

不进位加法:a^b

求进位值 :(a&b)<<1

所以,思路就是不断求不进位加法,直到进位值为0

所以初步的实现就如下:

int sum( int a, int b )
{
	int temp1=0,temp2=1;

    do
    {
        temp1 = a^b;
    	temp2 = (a&b)<<1;
        a=temp1;
        b=temp2;
        
    }while(temp2!=0);
    
    return temp1;
}

在do-while循环里面实现

首先,作第一次的不进位加法 temp1 = a^b;

然后,看看有没有进位值:temp2 = (a&b)<<1;

如果,有进位值:temp2!=0

则,将进位值与不进位的结果再进行不进位加法

然后,再看看有没有进位值

直到进位值为0,退出循环

结果就是temp1!!!

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值