由“位运算”想到的

最近,有人问到我一个面试题,求可以整除整数N的最大的数,并且还是2的幂。因为这次不是讨论这个问题,我就直接给答案了,是:N&(-1*N)。

这个题目就用到了位运算。位运算很简单,一共就那么几个,分别是:左移位(<<),右移位(>>),与(&),或(|),异或(^),取反(~)。没了,就这些了。

那么,用这些操作,都可以干些什么呢?在回答这个问题问题之前,需要先复习一些离散数学里面的问题,至少我需要复习一下。

A&B = B&A, A|B = B|A
(A&B)&C = A&(B&C), (A|B)|C = A|(B|C)
A|(B&C) = (A|B)&(A|C)
A&(B|C) = (A&B)|(A&C)
A|(A&B) = A
A&(A|B) = A
~(A|B) = ~A&~B
~(A&B) = ~A|~B
A|~A = 11...111(1的个数等于A的位数)
A&~A = 0
~(~A) = A
A^B = (A&~B)|(B&~A)
好了,基本的知识就这些,其它的东西都是在这个的基础上面推导出来的。其中异或(^)运算很特别,我们可以把它理解为逻辑上面的加法和减法。做一次是加,再做一次就是减,呵呵,有趣吧。而且还没有因为进位而导致溢出的苦恼。另外就是还要记得-A是A的取反加1。

现在,就可以看看位运算都可以干些什么了。

1,与2相关的运算。
左移或者右移,就是乘以2或者除以2,这个比较常见,就不多说了。

2,屏蔽某些数据位。
比如取A的低8位,就是A&0xFF。这里,如果用A&(-1*A),就取到了从A的低位数起,一直到第一个1的数,也就是可以整除A的最大的2的幂了。

3,交换两个数的值。
A=A^B
B= A^B
A=A^B
道理就是,
A=A^B=(A&~B)|(B&~A)
B=B^A=(B&~((A&~B)|(B&~A)))|(((A&~B)|(B&~A))&~B)=(B& (~A|B)&(~B|A))|(((A&~B)|~B)|((B&~A)&~B))
=(A&B)|(A&~B) =A&(B|~B)=A
A=A^B=(((A&~B)|(B&~A))&~A) | (A&~((A&~B)|(B&~A)))= B| (A&(~A|B)) = B|(A&B)=B
也许大家已经看得眼晕了。其实这个推导过程就是用了上面的公式,像宏运算似的一点一点展开后就能得出来了。

其实,可以理解为

A=A+B

B=A-B

A=A-B

 

有了这些基础,我们就可以做许多事情了。特别是与2相关的。比如算一个数是不是16的整倍数,只要看末4位是不是0,如A&0xF == 0,这比用 A % 16 == 0要快多了,比 A > int(A/16)*16更是快了太多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值