硬件设计之 Distributed Arithmetic 一例
下面是一段常见的c代码,用于计算下面这个问题。
问题:求一个32位整数的二进制表示中 1 的数量。
unsigned long CountOnes(unsigned long X) {
X = (X & 0x55555555) + (X >> 1 & 0x55555555);
X = (X & 0x33333333) + (X >> 2 & 0x33333333);
X = (X & 0x0F0F0F0F) + (X >> 4 & 0x0F0F0F0F);
X = (X & 0x00FF00FF) + (X >> 8 & 0x00FF00FF);
X = (X & 0x0000FFFF) + (X >> 16 & 0x0000FFFF);
return(X);
}
它背后的原理是什么呢?这篇文章尝试从硬件设计领域中 Distributed Arithmetic(DA算法)的角度来解释。
首先把这个问题转换成不那么专业的数学语言。
已知一个 32 位正整数
,其中
表示 X 的第 b 位,取值 0 或者 1。该位的权值即 2 的 b 次幂,
。N 在此例中等于 32。
求 X 的二进制表示中的 1 的数量,即
。
上面 c 代码函数中的第一步
X = (X & 0x55555555) + (X >> 1 & 0x55555555);
的结果可以用下式表示,
其中,b 的取值是 0 到 15。它的含义就是每相邻两个 bit 中含有的 1 的个数,这 16 个个数是单独体现在每两个 bit 组成的整数中,把这 16 个两 bit 数组合在一起,1 的个数的含义就模糊不清了,因为每个两 bit 数都用 2 的 2b 次幂加权了。分开看才会清楚,这也是这段 c 代码容易使人困惑的主要原因。
直接考虑用硬件实现的时候,不必用 1 个 32 bit 宽的加法器,而是用 16 个 1 bit 加法器并行计算。这就是 DA 算法的分布式计算特点。
上面 c 代码函数中的第二步
X = (X & 0x33333333) + (X >> 2 & 0x33333333);
的结果可以用下式表示,
其中,b 的取值是 0 到 7。它的含义就是每四个 bit 中含有的 1 的个数,这 8 个个数是单独体现在每四个 bit 组成的整数中,同样这 8 个四 bit 数组合在一起,含义也是隐藏起来的,因为每个四 bit 数都用 2 的 4b 次幂加权了。同样也是分开看才清楚。
类似的第三步可以用下式表示,
其中,b 的取值是 0 到 3。
第四步可以用下式表示,
其中,b 的取值是 0 到 1。
第五步,及最后一步可以表示为,
其中,b 的取值只有 0,即上式可以简化为
从这里就可以看到,此时 X 的取值,就是原来的 32 位整数 X 的二进制表示中的 1 的个数了。
看到这里,读者朋友们对这几句“奇技淫巧”般的代码背后的数学原理应该有所了解了吧。不过这种代码也并不只是在面试中为难面试者的,它还真是用来解决实际问题的。
比如,编码理论中经常提到的计算一个编码符号的 hamming weight,就是这个编码符号相对于全零编码符号的 hamming distance,二进制情况下也就是这个编码符号中 1 的个数。
- CodeSmith 创建Ado.Net自定义模版(三)
- Android注解学习(2)
- Android注解学习(2)
- 机器学习之——距离度量学习
- Enterprise Library Policy Injection Application Block 之三:PIAB的扩展—创建自定义CallHandler(提供Source Code下载)
- CodeSmith 创建Ado.Net自定义模版(四)
- TensorFlow图像分类教程
- Enterprise Library Policy Injection Application Block 之一: PIAB Overview
- Python教学——第七天
- 大数据将带来电视媒体生态式变革!大数据如何深度融合电视媒体?
- Silverlight SEO优化
- Silverlight性能优化
- WCF后续之旅(6): 通过WCF Extension实现Context信息的传递
- WCF后续之旅(6): 通过WCF Extension实现Context信息的传递
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- qt学习第2天:QRadioButtonTest+ButtonGroup单选后提示消息,QComBox
- Python使用矩阵分解法找到类似的音乐
- SpringBoot集成ELK实现日志收集实践
- python在Scikit-learn中用决策树和随机森林预测NBA获胜者
- R语言:用R语言填补缺失的数据
- R语言如何和何时使用glmnet岭回归
- r语言中对LASSO回归,Ridge岭回归和Elastic Net模型实现
- cmd里如何查看历史命令并执行
- akka-typed(10) - event-sourcing, CQRS实战
- 【每日一题】37. Sudoku Solver
- A quick introduction to innodb_ruby (2.对innodb_ruby的简单介绍)
- Webkit 内核初探
- 配置跨域后,框架帮我们做了什么?
- python应用(1):安装与使用
- TCP粘包和拆包