Skip to content

Instantly share code, notes, and snippets.

@yorkie
Last active December 11, 2015 20:59
Show Gist options
  • Save yorkie/4659563 to your computer and use it in GitHub Desktop.
Save yorkie/4659563 to your computer and use it in GitHub Desktop.
运用位级运算实现如下函数:even_ones[具体功能见注释]
// 来自 @颜闽辉
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;
}
// 函数要实现的功能是:
// 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);
}
// 你有其他的实现吗?
// 欢迎提交与讨论,指正等 - ^.^
// 来自微博 @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;
}
@yorkie
Copy link
Author

yorkie commented Jan 29, 2013

回复微博上 @颜闽辉 关于unsigned int占用字节长度在各平台不同是否会对结果造成影响:
我觉得并不会造成影响,考虑到是无符号整数的输入,因此为了减少错误,我将所有运算数都使用无符号,并且在even_ones函数中,对位较敏感的运算符应该是>>也对结果不会造成影响,因为其结果只会把最低位的1(如果有)去掉,其余位补零。

不过对于位移运算,我倒是有个疑问,位移运算是否会根据机器的字节序而变化,比如在大端上的>>运算,运行在小端的机器上时,会实际进行左移,而且对于某些编译器,左移又涉及到算数左移与逻辑左移,情况会变得比较复杂,不过既然没有出现相关问题,我相信机器代码里有相应的处理机制了,在以后的学习中,我也有可能会了解到。

另外,我看了你的@我的图之后,虽然你的方法可用来显示一个数的位模式(位图),但我仍然想问,是否有更地层的方法,来直接获取地址上的二进制值呢。

@yorkie
Copy link
Author

yorkie commented Feb 4, 2013

伪标准答案是:

int func_a(unsigned x) {
  int val = 0;
  while(x) {
    val ^= x;
    x >>= 1;
  }
  return val & 0x1;
}

@yorkie
Copy link
Author

yorkie commented Feb 4, 2013

关于两种方法的对比:
从代码上看,循环不变式都是通过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