Chinaunix首页 | 论坛 | 博客
  • 博客访问: 107518
  • 博文数量: 57
  • 博客积分: 1200
  • 博客等级: 中尉
  • 技术积分: 555
  • 用 户 组: 普通用户
  • 注册时间: 2011-04-26 21:13
文章分类

全部博文(57)

文章存档

2012年(14)

2011年(43)

分类: C/C++

2011-12-19 15:45:07

问题:求一个32位的字中bit 1的个数。

分析:我们大多数人的第一想法,大致如下(也许略有不同)。
  1. int cnt = 0;
  2. for (int k = 0; k < 32; ++k)
  3. {
  4.     if (x&1) ++cnt;
  5.     x >>= 1;
  6. }
作者分析和上述代码的运行时执行的RISC指令总数,大约208条,他为什么要分析这个呢?

    那么上述代码在逻辑和解题思路不变的情况下,仅仅在编码方面还能有什么改进呢?关键是在条件判断上做文章,利用C的0为false,其他为true,尽量减少变量,尽量减少比较次数。请看如下代码:
  1. int cnt = 0;
  2. while (x)
  3. {
  4.    cnt += (x&1);
  5.    x >>= 1;
  6. }
此时指令条数大约变为128-160左右,说明研究使用的语言被编译成的目标码的条数,对于编写高度精简、高效、优雅的代码大有裨益。

   之后的解法,逻辑方向改变了,利用了x&(x-1)将x的最低的bit 1清零,这个知识性比较强,类似的有x|(x+1)将x的最有的bit 0置为一。至于你想没想到,反正我是没想到。如果利用x&(x+1),代码类似如下:
  1. int cnt = 0;
  2. while (x)
  3. {
  4.   ++cnt;
  5.   x &= (x-1);
  6. }
如果利用x|(x+1)的话,代码大致如下:
  1. int cnt = 32;
  2. //cnt = 0; x = ~x;
  3. while (x+1)
  4. {
  5.   --cnt;
  6.   x |= (x+1);
  7. }
指令条数大约为4.5 * N,N为字中bit 1的个数。
    此外,对于以上代码还可以继续优化,例如对于例程1,可以将循环展开;另外可以对于单个字节可以表示的256个数中的bit 1的个数以表的形式列出,然后查表即可,效率很高。代码大致如下:
  1. static char table[] = {0,1,1,2,. . ., 8};
  2. cnt = table[x&0xFF]+table[x&0xFF00]+
  3.       table[x&0xFF0000]+table[x&0xFF000000];















阅读(1777) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~