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

刚好我在优化一个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

 #include <stdio.h>
#include <stdlib.h> void main(int argc, **argv)
{
int r;
unsigned char v;
static const unsigned char MultiplyDeBruijnBitPosition[] = {, , , , , , , }; v = (unsigned char)stroul(argv[],NULL, );
r = MultiplyDeBruijnBitPosition[((unsigned char)((v & -v) * 0x1DU)) >> ]; printf("The calculated = %d\n", r);
}

在Linux下调试验证:

gcc -o test test.c

./test xxx

应用实例:

mask的计算方法

 #define BIT(nr) (1<<(nr))
#define _PM_MASK(BITS, POS) \
((unsigned char)((( << (BITS)) - ) << (POS)))
#define PM_MASK(LEFT, RIGHT) \
_PM_MASK((LEFT) - (RIGHT) + , RIGHT)

下面是带mask的I2C写操作。

static status_t i2c_write_mask(uint8_t reg, uint8_t mask, uint8_t data)
{
status_t status;
uint8_t shift = ;
uint8_t tmp; status = i2c_read_byte(reg, &tmp);
if (status != kStatus_Success) {
PRINTF("Failed: status=%ld, reg=%d\n", status, reg);
goto out;
} tmp &= ~mask;
/* 0x1D is calculated from the de Bruun sequence */
shift = MultiplyDeBruijnBitPosition[((uint8_t)((mask & -mask) * 0x1DU)) >> ];
data <<= shift;
tmp |= data & mask; status = i2c_write_byte(reg, tmp);
if (status != kStatus_Success) {
PRINTF("Failed: reg=%02X, status=%ld\n", 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序列的计算方法。

Count the consecutive zero bits (trailing) on the right with multiply and lookup的更多相关文章

  1. BitHacks

    备份文件时看到的.我以前居然下过这东西. 2016-12-4 12:05:52更新 纯文本格式真棒.假如使用word写的我能拷过来格式还不乱?? Markdown真好. Bit Hacks By Se ...

  2. Bit Twiddling Hacks

    http://graphics.stanford.edu/~seander/bithacks.html Bit Twiddling Hacks By Sean Eron Andersonseander ...

  3. upc组队赛17 Bits Reverse【暴力枚举】

    Bits Reverse 题目链接 题目描述 Now given two integers x and y, you can reverse every consecutive three bits ...

  4. CCPC2018 桂林 D "Bits Reverse"

    传送门 题目描述 Now given two integers x and y, you can reverse every consecutive three bits ,,) means chan ...

  5. RFID 基础/分类/编码/调制/传输

    不同频段的RFID产品会有不同的特性,本文详细介绍了无源的感应器在不同工作频率产品的特性以及主要的应用. 目前定义RFID产品的工作频率有低频.高频和甚高频的频率范围内的符合不同标准的不同的产品,而且 ...

  6. 二维码详解(QR Code)

    作者:王子旭链接:https://zhuanlan.zhihu.com/p/21463650来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 2016.7.5 更新:长文 ...

  7. LUXURY15

    A - Guess Your Way Out! Time Limit:1000MS     Memory Limit:262144KB     64bit IO Format:%I64d & ...

  8. RFID Exploration and Spoofer a bipolar transistor, a pair of FETs, and a rectifying full-bridge followed by a loading FET

    RFID Exploration Louis Yi, Mary Ruthven, Kevin O'Toole, & Jay Patterson What did you do? We made ...

  9. 算术编码JM实现

    h.264标准中,CABAC的算术编码部分(9.3.4)只是一个参考,实际编码器中并不一定会按照它来实现,像JM中就有自己的算术编码实现方案. 在上篇文章CABAC中有详细的算术编码描述,在了解算术编 ...

随机推荐

  1. 添物零基础到大型全栈架构师 不花钱学计算机及编程(预备篇)— C语言编程基础

    ​C语言介绍 C语言基本是每个编程人员必学的一面语言,很好掌握,是理解编程的关键.很多编程语言基于其编写或者基于此语言的衍生品编写. C语言是人机交互的一个基础语言之一,虽然是之一,单一般其实就是唯一 ...

  2. RxJava如何结合观察者与链式处理

    RxJava如何结合观察者与链式处理 Author: Dorae Date: 2018年12月3日17:10:31 转载请注明出处 一.概述 首先问自己几个问题,如果非常清楚这几个问题的目的与答案,那 ...

  3. Ubuntu 16.04安装Adobe AIR

    安装: wget -O adobe-air.sh http://drive.noobslab.com/data/apps/AdobeAir/adobe-air.sh chmod +x adobe-ai ...

  4. Android GIS开发系列-- 入门季(1) 起点

    前言 这个系列,待最终完成更新,大家体谅点,第一版本全部是参考的网络教程,最近会逐步的细化更新为可以直接使用的情况. 本系列的开发基于AS (  Android Studio ), 和ArcGIS 的 ...

  5. Neo4j教程 Neo4j视频教程 Neo4j 图数据库视频教程

    课程发布地址 地址: 腾讯课堂<Neo4j 图数据库视频教程> https://ke.qq.com/course/327374?tuin=442d3e14 作者 庞国明,<Neo4j ...

  6. Redis: 改变HomeBrew安装的数据库文件目录

    vi /usr/local/etc/redis.conf 修改dir "/Volumes/KG's Big YO/Documents/redis_data" 最后,启动Redis: ...

  7. w3m命令行模式浏览网页

    w3m是一个基于文本的网页浏览器,支持多种操作系统,在命令行终端可以很好的支持中文.即使在没有鼠标支持的情况下也可以检查网页的输出. 我们一般用Ubuntu的X Windows来看图形界面的东西,有没 ...

  8. redis 主从备份自动切换+java代码实现类

    转载:http://blog.csdn.net/qq_23430789/article/details/52185706 目录(?)[-] redis-0sentinel实例之间的通讯端口 maste ...

  9. 第16章 ASP.NET MVC 日志篇

    本章主要介绍MVC中内置的错误处理.日志以及用来提升性能的监控工具 一.错误处理 当该网站忙于处理HTTP请求时,很多内容都会出错.幸运的是,MVC让错误处理工作变得相对简单了很多,因为MVC应用是运 ...

  10. Javascript中双等号(==)隐性转换机制 JS里charCodeAt()和fromCharCode()方法拓展应用:加密与解密

    Javascript中双等号(==)隐性转换机制   在Javascript中判断相等关系有双等号(==)和三等号(===)两种.其中双等号(==)是值相等,而三等号(===)是严格相等(值及类型是否 ...