Const_Lin
你从远方来, 我到远方去, 遥远的路程经过这里, 天空一无所有, 为何给我安慰。

题目描述:

/*

 *Generate mask indicating leftmost 1 in x.  Assume w=32.

 *For example 0xFF00 -> 0x8000, and 0x6600 -> 0x4000.

 * If x = 0, then return 0.

*/

代码如下:

 1  #include<stdio.h> 
 2 int leftmost_one(unsigned x);
 3  int main()
 4  {
 5  printf("Please enter number: ");
 6  unsigned x;
 7  scanf("%x",&x);
 8  int i = leftmost_one(x);
 9  printf("%x\n",i);
10  return 0;
11  }
12  
13  int leftmost_one(unsigned x)
14  {
15  x |= x >> 1;
16  x |= x >> 2;
17  x |= x >> 4;
18  x |= x >> 8;
19  x |= x >> 16;
20  return x-(x >> 1);
21  }

 

代码分析:

这道题目其实不难,难就难书上对题目的要求。如果没这些要求,那么这道题目可以简单的写成这样,代码如下:

 1 #include<stdio.h>
 2 int left_max(unsigned x);
 3 int main()
 4 {
 5     printf("Please enter number: ");
 6     unsigned x;
 7     scanf("%x",&x);
 8     int i = left_max(x);
 9     printf("%x\n",i);
10     return 0;
11 }
12 
13 int left_max(unsigned x)
14 {
15     int i;
16     for(i = 32;i >= 0;i--)
17     {
18         if(x & (1 << i))
19         {
20             return 1 << i;
21         }
22     }
23     return 0;
24 }

这样就简单,不过既然要求就这样,那我们只能老老实实的按要求写了。

首先我们用一个具体数据来测试 leftmost_one() 这个函数,比如用0xFF,这个数的二进制表示为1111111100000000。

第一次或操作:

x:

0000 0000 0000 0000 1111 1111 0000 0000

|

x>>1:

0000 0000 0000 0000 0111 1111 1000 0000

=

0000 0000 0000 0000 1111 1111 1000 0000

接下来的四次或操作,我们就不一一写出来,给出最后的结果为0000 0000 0000 0000 1111 1111 1111 1111 1111,我们观察结果和原数的差别,发现原数位为1的,结果对应的位也为1。而在位值为1的最左的位,右边位值为0的位的位值也变成1。即原数由[00..0011..1100..00],变成了[00..0011..1111..11]的形式。为什么能得出这样的结果,因为或操作保证原数位值为1的位不变,位值为0的位可能被转换为1。而右移操作保证只作用想要作用的位置,即位值为1的最左的位的右边。

至于为什么从右移1到右移16?我不是太明白,但我想可能是为了保证不漏位吧。因为在我用的这个数据0xFF,在第四次或操作,得出的结果就已经是0xFFFF,懂的朋友请不舍赐教,先感谢了。

再得出0xFFFF,接下来就很简单了,可以用 x-(x >> 1),得出想要的结果。

参考地址:http://code.ohloh.net/file?fid=SjlyeNad20Rez25yMPL1kKX2YwQ&cid=zBWzgOHNzoI&s=&fp=527061&mp=&projSelected=true#L0

posted on 2013-11-05 14:31  Const_Lin  阅读(736)  评论(4)    收藏  举报