今天继续学习了位操作,用位操作实现求一个数的绝对值:
对于一个整数a,如果是个正数就直接返回,但是如果是个负数呢?应该取反再返回,比如-5取反后应该是+5,然后返回。
在计算机中数都是用二进制来表示的,就是一串的0和1组合:
例如5的二进制表示为:0000 0101,
-5该如何表示,应该用补码来表示,就是,+5的二进制先按位取反,然后加1,如下:
先按位取反得: 1111 1010, 然后加1
加1以后为: 1111 1011 最高位表示符号 0位正,1为负
所以,我们求一个数的绝对值的时候,对于int(4字节)我们可以先把所求的数右移31位,求的改数的符号位,如果符号位为0,那么该数是整数,直接返回;如果是1,那么该数是负数,就按上面所说的,先按位取反,然后加1,返回。
对于移位操作来说,有算术移位和逻辑移位两种。对于左移来说没有区别,就是后面补0;但是对于右移来说不一样,算术右移是补符号位,就是说正数补0,但是负数要补符号位的话是1,这个要看系统了。而逻辑移位就是补0.
对于位操作来说,他们在c中运算优先级别比较低,应该尽量用括号()来保证运算顺序的正确性。
#include<stdio.h>
int my_abs(int a)
{
int i ;
i = a>>31;//右移31位取得符号位
if(i == 0)//如果符号位是0,是正数,返回a
return a;
else//如果不是0
return (~a+1);//返回(~a+1)就是a先按位取反,然后加1
}
int main()
{
int k =-100;
printf("%d\n",my_abs(k));
return 0;
}
第二种方法:
用异或运算。异或就是说如果对应的二进制位不同,运算结果就是1,如果相同就为0:
1^1 = 0; 1^0=1;0^0=0。我们也可以看出,任何数与0异或是它本身,与它本身异或结果是0:就是说对于一个数a来说,下面的运算式正确的:a^0 = a;a^a = 0;
再说一下一个数a,如果与-1(负1)异或结果会是什么.我们可以先看一下+1和-1怎么表示:
+1 = 0000 0001;
-1 = 1111 1110 +1 =1111 1111;
我们可以看到-1就是二进制的所有位都是1.
我们再看看前面的异或运算:1^1 = 0; 0^1 = 1;所以一个单独的位和1异或就是把该位取反。
因为 -1 就是所有二进制位为1的数。所以一个数和 -1 异或的话,实际上就是 把该数 按位取反。
比如 5 = 0000 0101;
5 = 0 0 0 0 0 1 0 1
^ -1 = 1 1 1 1 1 1 1 1
-------------------------------------
= 1 1 1 1 1 0 1 0(已经按位取反了)
所以我们也可以用异或的方法求绝对值,不用任何库函数和判断语句。
#include<stdio.h>
int my_abs2(int a)
{
int i ;
i = a>>31;//取得符号位
return ((a^i) -i);//如果i是0的话,那么(a^i)-i相当于(a^0)-0=a-0=a;
//如果i是-1的话,那么(a^i)-i相当于(a^-1)-(-1)=(~a)+1,就和上一例一样了
}
int main()
{
int k =-100;
//printf("%d\n",my_abs(k));
printf("--abs2----------------------------\n");
printf("%d\n",my_abs2(-1000));
return 0;
}