• 如何计算一个uint64类型的二进制值的尾部有多少个0


    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!


    正文

    这实在是一个很简单的问题,用代码可以表示如下:

    func CountBit0(x uint64) int{
        cnt := 0
        for i:=0; i<64; i++{
            if (x>>i)&1==1{
                break   
            }
            cnt++
        }   
        return cnt
    }
    

    但是,我们再看看golang标准库中的解决办法:

    // C:\Go\src\math\bits\bits.go
    
    const deBruijn64 = 0x03f79d71b4ca8b09
    
    var deBruijn64tab = [64]byte{
    	0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4,
    	62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5,
    	63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11,
    	54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6,
    }
    
    // TrailingZeros64 returns the number of trailing zero bits in x; the result is 64 for x == 0.
    func TrailingZeros64(x uint64) int {
        if x == 0 {
            return 64
        }
        // If popcount is fast, replace code below with return popcount(^x & (x - 1)).
        //
        // x & -x leaves only the right-most bit set in the word. Let k be the
        // index of that bit. Since only a single bit is set, the value is two
        // to the power of k. Multiplying by a power of two is equivalent to
        // left shifting, in this case by k bits. The de Bruijn (64 bit) constant
        // is such that all six bit, consecutive substrings are distinct.
        // Therefore, if we have a left shifted version of this constant we can
        // find by how many bits it was shifted by looking at which six bit
        // substring ended up at the top of the word.
        // (Knuth, volume 4, section 7.3.1)
        return int(deBruijn64tab[(x&-x)*deBruijn64>>(64-6)])
    }
    

    老实说,没看懂……
    我用python还原了一遍计算过程

    >>> '{:b}'.format(100)  #假设我们计算100这个值的二进制值后面有几个零
    '1100100'  # 从这里看, 答案应该是2
    >>> '{:b}'.format(int(100&-100))  #一个值,与它的负值补码做 bit and,得到了尾部最后一个1开始的二进制值
    '100'
    '{:b}'.format(int(100&-100)*0x03f79d71b4ca8b09)  # 这个 magic number,神来之笔,不懂为什么
    '111111011110011101011100011011010011001010100010110000100100'
    >>> '{:b}'.format( (int(100&-100)*0x03f79d71b4ca8b09) >> 58 )  # 最后再右移58个bit,得到了一个下标
    '11'  # 这个下标值是3
    

    最后一步,根据下标值3去查表,得到最终结果2……
    从注释来看,算法来自高德纳大师的 The Art of Computer Programming 第四卷。没文化真可怕,我很羞愧,以后一定好好看书。

  • 相关阅读:
    事件类型
    program的发展史与两个数学方法
    字符统计与基本正则
    bom与dom
    css长度单位及颜色表示
    grid学习
    position定位的认识
    remark:node端口的close-wait
    css background属性设置
    Promise之我发现
  • 原文地址:https://www.cnblogs.com/ahfuzhang/p/15900551.html
Copyright © 2020-2023  润新知