分析是参考了别的文章中的分析结合自己的一些思路写出来的
原文章链接如下:
https://blog.csdn.net/weixin_41256413/article/details/79937907
一,代码如下:
int odd_ones(unsigned x)
{
x^=x>>1;
x^=x>>2;
x^=x>>4;
x^=x>>8;
x^=x>>16;
return x&1;
}
分析
1.首先看 return x&1 这个最后返回值的意义
&是位运算,两个整数位运算,就是将这两个整数都变成对应的二进制位的形式,然后对应位进行位运算, 而 & 位运算的意义如下:
简单总结下,就是 0 & 任何数都是 0,而 1 & 任何数都是那个数本书,
因此 x & 1 =xk xk-1 xk-2…….x3 x2 x1 x0 & …0000001
因为 0 & 任何数都是0 1 &任何数都是这个数本身可以看出 x&1的最后结果只跟 x0有关
因此代码之前的所有操作,都是要得到一个合适的 x0
x^=x>>1; (xm.n是 xm ^ xn)
x^=x>>2
x^=x>>4
x^=x>>8
x^x>>16
可以发现规律 每一次计算后得到的x的第0位 都是一串数字的异或,,这串数字中最高位 = (假设 移位 为k) 2k-1,例如 x2k-1x2k-2…x0
如下图:
于是经过这一系列操作之后的 x中的 x0 为 原本 x 所有位的异或。
然后再看为什么异或
异或的性质是 非1 同0,如下图:
总结一下异或的几个跟这道题有关的性质
1.
0 ^ 任何数 都是这个数本身
2.
异或满足交换律 即 a^b =b^a
3.
异或满足结合律 即 a^ b^C = a^ ( b ^ c)
于是有这几个性质之后,可以把最后 所得的这个x0 划成如下形式:0在一起,1在一起:000000…000 111111…1
因为0异或任何数都是这个数本身,因此 这一堆是0的位都不用管了,最后返回的值只跟这堆1有关,如果1是奇数个,x0=1,1是偶数个 x0=0
另外,其实 异或的性质,只用到第1个: 0 ^ 任何数 都是这个数本身就可以得到结论,因为这个性质,所以x0中的是0的位直接可以不用管了。