使用位运算符,找到一个逻辑不等价
Posted
技术标签:
【中文标题】使用位运算符,找到一个逻辑不等价【英文标题】:Using bitwise operators, find a logical not equivalent 【发布时间】:2011-11-09 22:25:47 【问题描述】:仅使用:
<< >> | ^ & +
如何创建一个等效于逻辑非运算符 (!
) 的函数?
现在我有:
int i = (~x + 1) >> 31;
int j = (x + 1) >> 31;
i = i | j;
i = i & 1;
return i ^ 1;
它适用于一切,但-1
。
【问题讨论】:
您的解决方案使用 ~。我们是否允许使用它?另外,x 是整数还是布尔值? 您的问题指出仅使用这些运算符“> | ^ & +”,但随后您尝试使用“~”? 【参考方案1】:我假设您使用的是 32 位、有符号并使用 2 的补码表示法的 int
s。数字 0 的独特之处在于,无论是 0 还是它的否定符号位都没有 1。如果允许您使用否定运算符 (-),则此代码将起作用:
int not(int x)
return (-x | x) >> 31 & 1 ^ 1;
您不能使用减号,但这没关系,因为对于所有 x,我们都知道 -x
等于 ~x + 1
等于 (x ^ -1) + 1
。这就是 2 的补码符号的工作原理。所以最终的答案是:
int not(int x)
return ( (x^-1)+1 | x ) >> 31 & 1 ^ 1;
编辑 1: 好的,这是函数的“ANSI”版本,它不假设 int 的大小,也不依赖于右移有符号 int 的未定义行为。它在 MinGW 中对我有用:
int not(int x)
unsigned int y = x;
return (( ((y^-1)+1) | y ) >> (sizeof(x)*8-1)) ^ 1;
【讨论】:
不推荐有符号整数右移(实现根据C标准定义)。 是的,抱歉,我的功能因此而失败。我现在将对其进行编辑以添加一个“& 1”以在右移后修剪除 LSB 之外的所有内容。 如果您无法理解我的代码,请阅读:difranco.net/cop2220/op-prec.htm 根据 C 标准(至少是 C89,我稍后会检查 C99),“每个实现都应记录其在本节列出的每个领域中的行为。”所以我真的不能说结果会是什么。 您使用的运算符比问题允许的要多得多(乘法、减法、sizeof)。但我不确定是否有可能解决提出的问题(即至少没有关于整数表示等的一些假设)【参考方案2】:假设 x 是一个 32 位无符号值:
x = x | (x >> 1)
x = x | (x >> 2)
x = x | (x >> 4)
x = x | (x >> 8)
x = x | (x >> 16)
此时,如果 x 为 0,那么它仍然为 0。如果它有一个非零值,它现在具有位模式 111....111。
使用二补码表示,您现在可以简单地加 1 并获得所需的结果:
x = x + 1
这个解决方案对整数表示、类型等做了很多假设。
(当然,上面的“代码”不是有效的 C 代码)。
【讨论】:
@quasiverse - 然后执行unsigned x = *(unsigned *)&arg;
,使用x for your computation, then do
arg = (desired_type)x;`
对于有符号整数,右移具有依赖于实现的行为。
Omri,您错误地断言 x 在代码运行后将具有位模式 111111...111111。右移运算符不循环操作。考虑 x 是否为 1。第一个代码块中的任何操作都不会将其更改为 1 以外的值。
@David 当然你是对的。那会教我不要在凌晨 2 点 30 分回答问题...
@David 只是一个想法——如果我只接受 LSB 作为答案,它仍然可以工作。但它表明当你累了时编程是多么不明智。【参考方案3】:
有点“作弊”,但是:
bool logicalNot(int i)
return((bool)i ^ true);
我假设在关于函数组合/类型转换/隐式类型转换的规则中没有任何内容?
【讨论】:
C语言没有bool
类型;你能得到的最好的是typedef unsigned char bool
,它不能用于这个目的。以上是关于使用位运算符,找到一个逻辑不等价的主要内容,如果未能解决你的问题,请参考以下文章