32位二进制里有多少个1

        有这样一道计算机问题“32位二进制里面有多少个1”。这是一道比较普遍也比较简单的计算机题目,但是之前看过一篇文章,不单单是答案,而是在各个方面对该问题做了考虑。看了之后,很受启发,现在把这篇文章整理一下。

        简单明了的方法

         最简单明了的方法,就是遍历一遍这个32位的数字的各个二进制位,然后数一数1的个数。

        s & (s-1)

        因为计算机是二进制存储数据,基于这种存储方式,我们可以把任何一个数字看成是若干个2的n次方的和的形式。例如:10010011表示147,它等于2的7次方+2的4次方+2的1次方+2的0次方。又由于对于任何一个2的n次方的数字s,例如128=10000000,s-1=01111111,可以看到s&(s-1)可以消灭掉s中的最低位的1。而对于一个有若干个2的n次方和的s,只要进行若干次这样的操作,就会使得s最终等于0。所以,算法如下:

    int cnt = 0;
    while (s != 0){
        s = s & (s - 1);
        cnt++;
    }
    return cnt;

      算法很简单,也很好理解,这样s中有几个1,就进行几次上述的操作。

      查表法

        我们还可以运用查表法,查表法是在节省时间的基础上以使用更多的物理资源为代价。如果是32位数,则需要4GB的存储空间。这样对于任何一个32位的数字,只要进行一次查表法即可获得答案,也大大节省了效率。

       那么能否在时间效率和存储效率做一个权衡那?我们可以将32位数字拆解成两组16位的数字,这样需要进行2次查表,但是所消耗的内存却从4GB减少到64KB,这个时候需要2次查表加1次加法运算,需要3步操作。如果将32位数字拆解成四组8位的数字,所消耗的内存继续减少为256个字节,这样需要进行4次查表,这个时候需要4次查表加3次加法运算,需要7步操作。

       那么是否一定用一张4GB的大表比用一张64KB或者256字节的小表来的快那?从理论上来讲,1次查表操作,要比3次操作或是7次操作来的快。但是在真实的计算机系统中,主存与CPU之间有一个高速缓存。高速缓存的空间有限,通常只有几兆,4G内存的空间容量是高速缓存的上千倍。这样在进行随机测试的时候,可能每一次查表都需要从主存中把数据拷贝到缓存中,而一次cache miss的时间,CPU可以进行几百次的时钟操作。这样看来,实际上使用小表其实更加提升效率。

       具体说一下,在Linux下,lscpu命令能够得到系统CPU Cache的情况,例如,

       L1d cache:             32K
       L1i cache:             32K
       L2 cache:              256K
       L3 cache:              20480K

      CPU在CPU Cache取一次值可能也就1ns左右,而如果随机在内存中取值可能要80ns左右,关于这一块可以看我之前写的两篇博客《如何更加有效的操控内存》《CPU Cache翻译》

      这在时间效率上可能查出来十几倍到几十倍都不止。

     所以在非常在意时间效率的编码中要考虑CPU Cache的影响。

参考文献:

1.《吴军的谷歌方法论》

 

     

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值