关于二进制、位运算的心得、特殊应用场景

现有一问题:如何快速判断某数字是否是2的幂?用程序实现、当然效率越快越好。

首先想到的当然是将不断环循环/2,看最终是否=1,若是则是;若否则否

其次想到,可以将上述/2改为位运算(右移>>1相当于/2)

再次思索,可以这样:

 1 /// <summary>
 2         /// 判断num数字是否是2的幂
 3         /// </summary>
 4         /// <param name="num">待判断数据</param>
 5         /// <returns></returns>
 6         public bool JudgeIs2Power(long num)
 7         {
 8             return (num & (num - 1)) == 0;
 9             //证明:
10             //①先证明为什么当num是2的幂时,运算值一定是0
11             //因为num是2的幂,则num的值二进制一定形如1...0..0(首位是1,其后不含0或含N个0,N>=1)
12             //所以num-1的值二进制必然是1..1..1,即含有多个1或者不含1(即为0)
13             //所以num & (num-1)一定是0
14             //②再证明为什么当num补是2的幂时,运算值一定不是0
15             //因为num不是2的幂,则num转化为二进制一定形如1...1...(首位是1,其后含N个1,N>=1)
16             //所以num-1的值二进制必然是1...(后面任意,不做讨论)...(首位是1,其后值任意)
17             //所以num & (num-1)的值二进制首位必定是1,<>0
18             //③排除0和负数。若搞不清楚,可在①②证明里去除1的情况、在此处单独讨论
19             //综上,当且仅当num是2的幂时,运算值一定是0,即(num & (num - 1)) == 0可作为判断num是否是2的幂的方法。因为该方法是位运算、减1本身很快,所以计算速度原理上会非常快。
20         }

 

由此问题想到,位运算虽然不常用、但是因为运算效率之高、和计算机硬件联系密切、有若干有用的数学特性,还是得了解下。事物必须先了解,而后有问题才能想到;如果连了解、听说都做不到,那遇到问题也想不到那边去。

 

再来说一个,用1个数字的二进制方式来获取内部多个状态位:

现有一订单自动化定时运行程序:一个订单下单后,程序需并行或串行处理订单的若干任务,比如说超过30min未支付则自动取消、已支付6H还没有op处理、已超过出游时间还没有出游。。。这样的话,一个订单需要N个标识状态字段(是否已运行超时出游程序、是否已运行超时自动取消程序),每个字段都得标识:0-未运行,1-已运行-出错,2-已运行-成果,3-其他;可能各自还需要一个详细原因字段。 这样程序非常冗余。

优化办法:新建2字段   OrderFlags(long),OrderFlagsDesc(string)。

OrderFlags:每4位标志一种状态,比如第1-4位表示超时订单job状态、5-8位表示投保job状态。每个状态位里自定义0000,0001,0010代表什么意思(最好统一)。当然也可以每3位表示一种job状态。    原理上long类型已经可以有60位二进制=》即使4位表示一个栏目,可以表示10+个job状态。读取时可以分别>>4*N位,然后&15(1111)即可获取每个状态位的具体细节状态。

OrderFlagsDesc:结构   {"Reasons":[{"NodeTypeId":1,"BreakReason":"该订单未超时取消订单,运行正常"},{"NodeTypeId":2,"BreakReason":"投保自动化失败,游客身份证错误,身份证XXXX"}]}

 

posted on 2017-02-07 23:53  nlh774  阅读(548)  评论(0编辑  收藏  举报