【问题标题】:Bitwise Operations in C: Can't figure out why XOR does not work. Is my code or logic flawed?C 中的按位运算:无法弄清楚为什么 XOR 不起作用。我的代码或逻辑有缺陷吗?
【发布时间】:2015-01-27 06:08:54
【问题描述】:

我只能使用下面提到的按位运算符来创建描述的函数:

/* 
*  allEvenBits - return 1 if all even-numbered bits in word set to 1
*  Examples allEvenBits(0xFFFFFFFE) = 0, allEvenBits(0x55555555) = 1
*  Legal ops: ! ~ & ^ | + << >> 
*  Max ops: 12
*  Rating: 2    
*/

我们使用 2s 补码,整数的 32 位表示。此外,我只能使用整数常量 0 到 255 (0xFF),包括在内。我的蛮力解决方案如下:

int allEvenBits(int x) {
  int mask0 = 0x55;
  int mask1 = 0x55 << 8;
  int mask2 = 0x55 << 16;
  int mask3 = 0x55 << 24;
  return(!(x ^ (mask0 | mask1 | mask2 | mask3)));
}

所以我基本上创建了一个 0x55555555 掩码,将掩码与 x 进行异或运算,并否定此操作,假设 (x ^ 0x55555555) 等于 0 的唯一时间是 x 等于 0x55555555。 (基于x ^ x == 0的异或属性。)

因此,当x == 0x55555555 时,这应该是我的函数唯一一次返回 1。当x == 0x55555555 时它确实返回 1。

但是,我的功能不正确,我无法弄清楚原因。是我的逻辑有缺陷还是我的代码有问题?

【问题讨论】:

  • 如果设置了所有偶数位加上其他一些位,您确定该函数不应该返回 1 吗?例如 0xFFFFFFFF 似乎应该返回 1。
  • 如果单个 int 可以保存您的值 0x55555555 并像 int mask = 0x55555555; return (!(x ^ mask)); 那样做,为什么要提出多个 int
  • 不允许使用大于 0xFF 的 int 字面量吗?
  • 你的逻辑是错误的,因为它忽略了任何奇数位的存在
  • 为什么说“函数不正确”?尤其是在说它确实有效之后。

标签: c bit-manipulation bitwise-operators


【解决方案1】:

您切换偶数位,然后将结果与 0 进行比较。但是,即使所有偶数位都是 1,奇数位仍然不变,因此只要奇数位为 1,您的函数将返回 0。它仅当所有奇数位均为 0 时才能正常工作

return (!(x ^ (mask0 | mask1 | mask2 | mask3)));

你也需要清除所有奇数位

int allEvenBits(int x) {
  int mask = 0x55;
  int mask = mask | (mask << 8);
  int mask = mask | (mask << 16);

  return !(x & mask);
}

另一种方式

int allEvenBits(int x) {
  int mask = 0xAA;
  int mask = mask | (mask << 8);
  int mask = mask | (mask << 16);

  return !((x | mask) ^ (~0));
}

另一种更短的方式

x &= x >> 16;
x &= x >> 8;
return !((x & 0x55) ^ 0x55);
// or return !(((x | 0xAA) + 1) & 0xFF);

【讨论】:

  • 谢谢!你帮助阐明了我错过的一个非常重要的观点。我不认为奇数位仍然可以是 1,只要所有偶数位都是 1。如果可以的话,我会支持你。
  • 我添加了另一种更短的方式,你可以试试
【解决方案2】:

按照问题陈述而不是您的规定,函数应该只为 0x55555555 返回 1,这是一种方法:

int allEvenBits(int x) {
  int filled = x | 0xAAAAAAAA;
  return !(filled + 1);
}

我们将输入与一个设置了所有奇数位的值按位或。因此,如果输入中的所有偶数位都已设置,我们将得到 0xFFFFFFFF。然后我们加 1 溢出并得到 0,我们最终取反得到结果。增加 0xFFFFFFFF 以外的任何数字都会产生非零结果,取反时将为 0。

【讨论】:

  • +1 表示简短有效的方式。但严格来说,有符号溢出是未定义的行为,所以return !(filled + 1U); 会更好。而且您应该从多个班次构造 0xAAAAAAAA,因为不允许 OP 使用如此大的常量
【解决方案3】:
// Get a platform-independent mask of all even bits in an int set to one:
#define MASK ( (unsigned int) 0x55555555u )

/* MASK will be 0x5555u or 0x55555555u depending on sizeof(int).
   And then the actual algorithm: */
unsigned int allEvenBits(int x) 
{
  return (unsigned int)( !(x ^ MASK) );
}

【讨论】:

  • == 不是允许的运算符
  • OP 也不允许使用大于 0xFF 的整数文字,所以你最终会得到和他完全一样的方式
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-21
相关资源
最近更新 更多