Last active
December 11, 2015 20:59
-
-
Save yorkie/4659563 to your computer and use it in GitHub Desktop.
运用位级运算实现如下函数:even_ones[具体功能见注释]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 来自 @颜闽辉 | |
int bitmap(unsigned in, char out[]) | |
{ | |
unsigned count = 0; | |
unsigned size = sizeof(in) * 8; | |
out[size] = '\0'; | |
do { | |
if (in & 1) { | |
++count; | |
out[--size] = '1'; | |
} else { | |
out[--size] = '0'; | |
} | |
} | |
while (in >> 1, size); | |
return count; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 函数要实现的功能是: | |
// input: unsigned int | |
// output: 判断输入位模式中的置1位的奇偶性如: | |
// - 1(001) => 0(false, odd, 奇数个) | |
// - 3(011) => 1(true, even, 偶数个) | |
// - 8(1000) => 0(false, odd, 奇数个) | |
#include <stdio.h> | |
int main(int argc, char const *argv[]) | |
{ | |
unsigned x; | |
printf("Please input a positive number:\n"); | |
scanf("%u", &x); | |
if (x == 0u) | |
{ | |
printf("the number %d hava no '1' bit", x); | |
return 0; | |
} | |
printf("%s\n", even_ones(x) == 1 ? ":even" : ":odd"); | |
return 0; | |
} | |
// Return 1 when x contains an even number of 1s, 0 otherwise | |
unsigned is_even = 0u; | |
int even_ones(unsigned x) | |
{ | |
unsigned a = x; | |
if (a <= 0u) return (int)!is_even; | |
if (x & 1u == 1u) | |
is_even = !is_even; | |
return even_ones(a >> 1); | |
} | |
// 你有其他的实现吗? | |
// 欢迎提交与讨论,指正等 - ^.^ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 来自微博 @enginespot 的算法 | |
// 二进制步长为1,逢1变为0,逢0变1,问题直接变成数学问题,n%3==0,为偶数个,n%3>0 ,为奇数个 | |
int even_ones_v1(unsigned x) | |
{ | |
int temp = x % 3u; | |
if (temp == 0u) return 1; | |
else if (temp > 0u || 1u) return 0; | |
} | |
// 表达式版本 | |
int even_ones_v2(unsigned x) | |
{ | |
return !(x % 3u) ? 1 : 0; | |
} |
伪标准答案是:
int func_a(unsigned x) {
int val = 0;
while(x) {
val ^= x;
x >>= 1;
}
return val & 0x1;
}
关于两种方法的对比:
从代码上看,循环不变式都是通过x>>1
来实现的,唯一不同的是,我的前一个答案中是通过比较x & 1u
来标示,而下面的例子则是使用:
val ^= x
这不得不引起关于位运算^
的思考,首先我们来看看异或的真值表:
> P - Q - P ^ Q
> T - T - F
> T - F - T
> F - T - T
> F - F - F
再来看看x & 1u
的真值表:
> x - 1 - x & 1u
> T - T - T
> F - T - F
第二种方法通过& 1u
来获取其最高有效位的值,其并不关心个位以外的位,只要输入的数的当前最高有效位是1,就会通过^
让其改变当前值(即1>2,而2>1)。
第一种方法中的&
同样起着获取输入的数的最低有效位的作用。
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
回复微博上 @颜闽辉 关于unsigned int占用字节长度在各平台不同是否会对结果造成影响:
我觉得并不会造成影响,考虑到是无符号整数的输入,因此为了减少错误,我将所有运算数都使用无符号,并且在
even_ones
函数中,对位较敏感的运算符应该是>>
也对结果不会造成影响,因为其结果只会把最低位的1(如果有)去掉,其余位补零。不过对于位移运算,我倒是有个疑问,位移运算是否会根据机器的字节序而变化,比如在大端上的
>>
运算,运行在小端的机器上时,会实际进行左移,而且对于某些编译器,左移又涉及到算数左移与逻辑左移,情况会变得比较复杂,不过既然没有出现相关问题,我相信机器代码里有相应的处理机制了,在以后的学习中,我也有可能会了解到。另外,我看了你的@我的图之后,虽然你的方法可用来显示一个数的位模式(位图),但我仍然想问,是否有更地层的方法,来直接获取地址上的二进制值呢。