优秀程序员不得不知道的20个位运算技巧

原文地址:
https://blog.csdn.net/zmazon/article/details/8262185

这篇博客总结的特别好,进一步感受到了位运算的奇妙。

关于里面有几处不太好理解,这里做一个小结:

1.获得int型最大值

int getMaxInt(){
        return (1 << 31) - 1;//2147483647, 由于优先级关系,括号不可省略
}

int一共32位,分别是第0位到第31位,因为第31位是符号位,要想是正数,那么符号位一定为0,所以int里面最大的整数是(1 << 31) - 1,

10.取绝对值(某些机器上,效率比n>0 ? n:-n 高)

int abs(int n){
return (n ^ (n >> 31)) - (n >> 31);
/* n>>31 取得n的符号,若n为正数,n>>31等于0,若n为负数,n>>31等于-1
若n为正数 n^0=0,数不变,若n为负数有n^-1 需要计算n和-1的补码,然后进行异或运算,
结果n变号并且为n的绝对值减1,再减去-1就是绝对值 */
}

这个有必要研究研究。看起来特别复杂,我们慢慢来看。
首先,n >> 31是将n右移31位,那么此时分为两种情况,n为非负数和负数的情况。
一、如果n >= 0,那么n >> 31 = 0。因为正数的右移是往最高位补0的,所以最后肯定为0。
二、如果n < 0,那么n >> 31 = -1。这是因为负数的右移往最高位补1,所以最后是
11111111111111111111111111111111这个结果,而这个结果正好就是-1的补码。
故所以n >> 31 = -1

再看它是如何实现取绝对值的。
一、当n >= 0时,n ^ (n >> 31) = n ^ 0 ;因为任何一个数异或0都不变 ,所以n ^ 0 = n;
因此,在这个abs函数中,如果n >= 0,那么返回的结果就是n ^ 0 - 0 = n;符合绝对值的定义
二、当n < 0时,n ^ (n >> 31) = n ^ -1 ;因为任何一个数异或-1都等于该数取反 ,所以

n ^ -1 = ~n = -(n + 1)			//此处涉及一个定理,~n = -(n + 1)

因此,当n < 0时,n函数abs中,返回n ^ -1 - (-1) = -(n + 1) - (-1) = -n;
符合绝对值的定义。
综上所述,abs函数编写是正确的。

这里有个定理还没有证明,就是n ^ -1 = ~n = -(n + 1)
先证n ^ -1 = ~n:

因为-1的补码:11111111111111111111111111111111
所以,由异或的定义,相同为0,不相同为1,n^-1之后,n的0位一定变成1,1位肯定变成0
即n^-1之后,每一位都变成了相反的数字。
因此n^-1 = ~n;

再证 ~n = -(n + 1)
这个结论可以记下来

这个结论不太好证,可以先举例来看看
00000000000000000000000000101101		//45的补码
11111111111111111111111111010010		//~45,45取反之后的补码,我们现在求出它的原码看看
11111111111111111111111111010001		//补码减一,得到反码
10000000000000000000000000101110		//取反,得到原码,
//和45的原码对比一下,就是符号位变成相反的,然后加了一个1,这就是-46的原码。

我个人理解,取反之后减一等于取反前加一(不考虑符号位的话)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值