如何计算一个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 第四卷。没文化真可怕,我很羞愧,以后一定好好看书。

posted on 2022-02-16 14:52  ahfuzhang  阅读(201)  评论(0编辑  收藏  举报