【SWAR算法】在看redis的设计与实现这本书的时候,看到了BITCOUNT实现中用到了SWAR算法

在书中看到了BITCOUNT命令实现的时候,用了SWAR算法,当时理解得不太到位。
后来知乎上看到了一个作者关于这个算法的文章然后自己跟着计算了一次,一切就都明了了。
详情请看

// 这是个32位的swar算法的实现,下面将对这个算法的每一个步骤进行详细的运算拆解
uint32_t swar(uint32_t i){
    i = (i & 0x55555555) + ((i>>1) & 0x55555555);  // 步骤1
    i = (i & 0x33333333) + ((i>>2) & 0x33333333);  // 步骤2
    i = (i & 0x0F0F0F0F) + ((i>>4) & 0x0F0F0F0F);  // 步骤3
    i = (i * 0x01010101) >> 24;                    // 步骤4
    return i;
}

(i & 0x55555555) + ((i>>1) & 0x55555555);  // 步骤1 

0001 0010 0011 0100 0101 0110 0111 1000 -- 原始 = i

0101 0101 0101 0101 0101 0101 0101 0101 -- 步骤1的掩码 = 0x55555555

0001 0000 0001 0100 0101 0100 0101 0000 - 原始&掩码

0000 1001 0001 1010 0010 1011 0011 1100 - 原始右移

0101 0101 0101 0101 0101 0101 0101 0101 - 掩码

0000 0001 0001 0000 0000 0001 0001 0100 - 原始右移1&掩码

0001 0000 0001 0100 0101 0100 0101 0000 - 原始&掩码

0001 0001 0010 0100 0101 0101 0110 0100 - 原始右移1&掩码 + 原始&掩码

00 01 00 01 00 10 01 00 01 01 01 01 01 10 01 00 - 原始右移&掩码 + 原始&掩码 = 步骤计算出的i
 0  1  0  1  0 2   1  0  1  1  1  1  1 2   1  0 - 2位合并作1位的结果(这个结果只是用来给你看的)

i = (i & 0x33333333) + ((i>>2) & 0x33333333);  // 步骤2

0001 0001 0010 0100 0101 0101 0110 0100 - 步骤1计算的i

0011 0011 0011 0011 0011 0011 0011 0011 - 步骤2的掩码=0x33333333

0001 0001 0010 0000 0001 0001 0010 0000 - i&掩码

0000 0100 0100 1001 0001 0101 0101 1001 - i右移20011 0011 0011 0011 0011 0011 0011 0011 - 步骤2的掩码=0x33333333

0000 0000 0000 0001 0001 0001 0001 0001 - i右移2&步骤2的掩码=0x33333333

0001 0001 0010 0000 0001 0001 0010 0000 - i&掩码

0001 0001 0010 0001 0010 0010 0011 0001 - i&掩码 + i右移2&步骤2的掩码=0x33333333
   1    1    2    1    2    2    3    1 - 4位合并做1位的结果(这个结果只是用来给你看的)
i = (i & 0x0F0F0F0F) + ((i>>4) & 0x0F0F0F0F);  // 步骤3

0001 0001 0010 0001 0010 0010 0011 0001 - 步骤2计算的i

0000 1111 0000 1111 0000 1111 0000 1111- 掩码 = 0x0F0F0F0F

0000 0001 0000 0001 0000 0010 0000 0001 - 步骤2计算的i & 掩码 = 0x0F0F0F0F

0000 0001 0001 0010 0001 0010 0010 0011 - i右移40000 1111 0000 1111 0000 1111 0000 1111 - 掩码 = 0x0F0F0F0F

0000 0001 0000 0010 0000 0010 0000 0011 - i右移4& 掩码 = 0x0F0F0F0F

0000 0001 0000 0001 0000 0010 0000 0001 - 步骤2计算的i & 掩码 = 0x0F0F0F0F

0000 0010 0000 0011 0000 0100 0000 0100 - 步骤2计算的i & 掩码 = 0x0F0F0F0F  + i右移4& 掩码 = 0x0F0F0F0F

        2         3         4         4 - 8位合并作1位结果(这个结果只是用来给你看的)
步骤4,按照我们前面的思路这里还得会继续合并,但是8个bit的相加运算使得答案已经很清晰,直接可以口算 得到原i中有131
不信你数一下 
0001 0010 0011 0100 0101 0110 0111 1000 -- 原始 = i
   1    1    2    1    2    2    3    1 -- 这里代表是的1的个数
结果 = 1+1+2+1+2+2+3+1 = 13

看到了这里,是不是突然就觉得那个遍历累加计数的算法,确实有点上不了台面了!
但这个算法的实现还有更加精美绝伦的姿态,不信你看一下java中Integer.bitCount()的实现。
最后感谢那位作者让我廓然开朗 知乎传送门https://zhuanlan.zhihu.com/p/165968167

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值