• Count the consecutive zero bits (trailing) on the right with multiply and lookup


    我在网上看到了一点神奇的代码,用来计算一个数字末尾连续零的个数。

    刚好我在优化一个I2C读写函数(只写入I2C特定bit),觉得这个很有用。经过尝试,确实没问题。

    下面我隆重介绍一下:

    Count the consecutive zero bits (trailing) on the right with multiply and lookup

    unsigned int v;  // find the number of trailing zeros in 32-bit v 
    int r;           // result goes here
    static const int MultiplyDeBruijnBitPosition[32] = 
    {
      0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 
      31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
    };
    r = MultiplyDeBruijnBitPosition[((uint32_t)((v & -v) * 0x077CB531U)) >> 27];
    

    Converting bit vectors to indices of set bits is an example use for this. It requires one more operation than the earlier one involving modulus division, but the multiply may be faster. The expression (v & -v) extracts the least significant 1 bit from v. The constant 0x077CB531UL is a de Bruijn sequence, which produces a unique pattern of bits into the high 5 bits for each possible bit position that it is multiplied against. When there are no bits set, it returns 0. More information can be found by reading the paper Using de Bruijn Sequences to Index 1 in a Computer Word by Charles E. Leiserson, Harald Prokof, and Keith H. Randall.

    On October 8, 2005 Andrew Shapira suggested I add this. Dustin Spicuzza asked me on April 14, 2009 to cast the result of the multiply to a 32-bit type so it would work when compiled with 64-bit ints.

    以上内容转自http://graphics.stanford.edu/~seander/bithacks.html

     ++++++++++++++++++++++++++++++++我是分割线++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    然后根据此方案,我们来做一个8bit的末尾连续0的计算。

    主要用途是I2C读写时,mask 的计算。如果要读写某Byte的某几个bit,可以只传入寄存器地址和Mask位就可以了。

    创建文件test.c

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 
     4 void main(int argc, **argv)
     5 {
     6     int r;
     7     unsigned char v;  
     8     static const unsigned char MultiplyDeBruijnBitPosition[8] = {0, 1, 6, 2, 7, 5, 4, 3};
     9 
    10     v = (unsigned char)stroul(argv[1],NULL, 0);
    11     r = MultiplyDeBruijnBitPosition[((unsigned char)((v & -v) * 0x1DU)) >> 5];
    12 
    13     printf("The calculated = %d
    ", r);
    14 }

    在Linux下调试验证:

    gcc -o test test.c

    ./test xxx

    应用实例:

    mask的计算方法

    1 #define BIT(nr) (1<<(nr))
    2 #define _PM_MASK(BITS, POS) 
    3     ((unsigned char)(((1 << (BITS)) - 1) << (POS)))
    4 #define PM_MASK(LEFT, RIGHT) 
    5     _PM_MASK((LEFT) - (RIGHT) + 1, RIGHT)

    下面是带mask的I2C写操作。

    static status_t i2c_write_mask(uint8_t reg, uint8_t mask, uint8_t data)
    {
        status_t status;
        uint8_t shift = 0;
        uint8_t tmp;
    
        status = i2c_read_byte(reg, &tmp);
        if (status != kStatus_Success) {
            PRINTF("Failed: status=%ld, reg=%d
    ", status, reg);
            goto out;
        }
    
        tmp &= ~mask;
        /* 0x1D is calculated from the de Bruun sequence */
        shift = MultiplyDeBruijnBitPosition[((uint8_t)((mask & -mask) * 0x1DU)) >> 5];
        data <<= shift;
        tmp |= data & mask;
    
        status = i2c_write_byte(reg, tmp);
        if (status != kStatus_Success) {
            PRINTF("Failed: reg=%02X, status=%ld
    ", reg, status);
        }
    
    out:
        return status;
    }

    至于像 0x1DU 及类似的代码中的 0x077CB531,0x5F3759DF和数组

    {
      0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
      31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
    };
    
    {0, 1, 6, 2, 7, 5, 4, 3};

    的由来问题,就参考:http://www.cnblogs.com/shangdawei/p/3967505.html 好了,非常感谢此作者的工作,让我很快明白了De Bruijin序列的计算方法。

  • 相关阅读:
    MSDN for 2010的那些麻烦事
    CPtrList操作--插入,删除特定元素,删除全部
    如何绕过ORA00701错误和降低bootstrap对象的高水位
    ORA00600:[1112]内部错误&ROW CACHE ENQUEUE LOCK一例
    CRS5008: Invalid attribute value
    ORA00600[kjpsod1]&ORA44203错误一例
    runInstaller ignoreInternalDriverError
    RMAN CURSOR_SHARING=EXACT脚本
    SQL调优:带函数的谓词导致CBO Cardinality计算误差
    11g Real Application Testing:Database Replay使用方法
  • 原文地址:https://www.cnblogs.com/Hello-words/p/7615746.html
Copyright © 2020-2023  润新知