逻辑NOT(!)运算符不适用于按位语句

时间:2010-09-13 00:49:15

标签: c bit-manipulation bitwise-operators logical-operators

我试图确定是否可以计算两个32位整数的总和而不会溢出,同时仅使用某些按位运算符和其他运算符。因此,如果可以在不溢出的情况下添加整数x和y,则以下代码应返回1,否则返回0。

(((((x >> 31) + (y >> 31)) & 2) >> 1))

但是,它应该为1时返回0,反之亦然。当我使用逻辑NOT(!)运算符或按位XOR(^)和0x1时,它不能解决问题。

!(((((x >> 31) + (y >> 31)) & 2) >> 1))

(((((x >> 31) + (y >> 31)) & 2) >> 1) ^ 0x1)

^这些不起作用。

提前致谢。

5 个答案:

答案 0 :(得分:8)

这有点清洁:

~(x & y) >> 31

<强>更新

kriss的评论是正确的。所有这些代码都检查两个MSB是否都已设置。

我只是看着kriss的答案,我发现只使用一个加法,加上按位运算符,假设无符号整数,就可以完成同样的事情。

((x & 0x7FFFFFFF) + (y & 0x7FFFFFFF)) & 0x80000000 & (x | y)

第一个带括号的部分将MSB都设置为0然后添加结果。任何进位都将以结果的MSB结束。随身携带的下一个bitmask隔离区。最后一项检查x或y上的集合MSB,这导致整体进位。要满足问题中的规范,请执行以下操作:

~(((x & 0x7FFFFFFF) + (y & 0x7FFFFFFF)) & 0x80000000 & (x | y)) >> 31

答案 1 :(得分:2)

假设两个数都是无符号整数。如果你使用有符号整数,那将有点棘手,因为有两种方法可以获得溢出,或者添加两个大的正数来添加两个大的负数。无论如何检查最重要的位是不够的,因为加法传播携带位,你必须考虑它。

对于无符号整数,如果你不打算欺骗一个简单的方法是:

 (x+y < x) || (x+y < y)

这将起作用,因为大多数编译器在溢出发生时都不会做任何事情,只是让它成为。

您还可以注意到,对于溢出发生,至少有两个数字中的一个必须将其最重要的位设置为1.因此类似的东西应该起作用(小心,未经测试),但它比其他版本更加复杂

/* both Most Significant bits are 1 */
(x&y&0x80000000)        
/* x MSb is 1 and carry propagate */
 ||((x&0x80000000)&&(((x&0x7FFFFFFF)+y)&0x80000000))
/* y MSb is 1 and carry propagate */
 ||((y&0x80000000)&&(((y&0x7FFFFFFF)+x)&0x80000000))

答案 2 :(得分:1)

合乎逻辑!对我来说工作正常。

me@desktop:~$ cat > so.c
#include <stdio.h>

void main() {
    int y = 5;
    int x = 3;
    int t;
    t = (((((x >> 31) + (y >> 31)) & 2) >> 1));
    printf("%d\n", t);
    t = !(((((x >> 31) + (y >> 31)) & 2) >> 1));
    printf("%d\n", t);
}
^D
me@desktop:~$ gcc -o so so.c
me@desktop:~$ ./so
0
1
me@desktop:~$ uname -a
Linux desktop 2.6.32-23-generic #37-Ubuntu SMP Fri Jun 11 07:54:58 UTC 2010 i686 GNU/Linux

答案 3 :(得分:1)

没有简单的基于位运算的溢出测试,因为加法涉及进位。但是有一些简单的溢出测试,不涉及调用溢出或无符号整数包装,它们甚至比添加然后检查溢出更简单(这当然是有符号整数的未定义行为):

对于无符号整数xy(x<=UINT_MAX-y)

对于有符号整数,首先检查它们是否有相反的符号。如果是这样,添加是自动安全的。如果它们都是正面的,请使用(x<=INT_MAX-y)。如果它们都是否定的,请使用(x>=INT_MIN-y)

答案 4 :(得分:0)

那些是否签署了整数?你的逻辑看起来对于无符号整数(unsigned int)应该没问题,但对于常规整数则不行,因为在这种情况下,移位将保留符号位。