判断无符号整数的二进制形式中是否包含偶数个1

题目要求:若二进制无符号整数x包含偶数个1,返回1,否则返回0.

要求:只能使用位运算、加减法和==、!=,最多包含12个算术运算、位运算和逻辑运算,可以假设sizeof(unsigned)==4

不能使用乘除模运算,不能使用条件分支,循环,函数调用,大小比较等(详见《深入理解计算机系统》第二章习题)

首先,最朴素最直接的方法——一位一位统计肯定次数远远多于12次.

考虑:异或运算(^)可以保持两个操作数1的个数的奇偶性.

因为两个操作数,一1一0,结果为1,1的个数还是奇数;两0,结果为0,不影响,两1,结果为0,1的个数还是偶数.

这样,想到了降量的思想,把判断32位数转化为16位,然后依次进行.

先开始想的是分别取到前/后16位,然后异或:

1.x&0xFFFF0000;

2.x&0x0000FFFF;

3.将步骤1得到的结果向右移16位;

4.将2和3的结果异或.

4得到的结果和原32位数1的个数的奇偶性一致.

但是需要4*5+1(根据要求取反)=21步.

简化一下,1和3可以通过x/65536这一步得到,这样,需要步数是3*5+1=16步,还是超出了要求.

仔细想想,将x和x/65536异或,得到结果前16位和原x前16一致,但是后16位1的个数奇偶性与原x二进制1的个数奇偶性一致.

这样,两步完成32位到16位的简化,2*5=10次之后,得到结果前面31位不用管,最后1位说明了奇偶性.

这时,把结果模2,得到最后1位,0或者1.

然后取反,得到题目要求的结果.总共需要12步.

用C++(底层数据的表示和C一样)写了一段程序并简单测试了一下.

下面附上源码,一共使用6次算术运算,5次位运算和1次逻辑运算.

代码如下:

nt even_ones(unsigned x )  
{  
    unsigned x16 = (x>>16)^x;  
    unsigned x8 = (x16>>8)^x16;  
    unsigned x4 = (x8>>4)^x8;  
    unsigned x2 = (x4>>2)^x4;  
    unsigned x1 = (x2>>1)^x2;  
    return (~x1)&0x1;  
} 

int main()
{
    unsigned a;
    scanf("%u",&a);
    int ret=even_ones(a);

    printf("%d",ret);
} 

参考:http://blog.csdn.net/zhzhanp/article/details/6324511

原文地址:https://www.cnblogs.com/youxin/p/3234094.html