按位:负输入值的不同行为

时间:2013-04-25 14:15:40

标签: c bit-manipulation

我正在使用Coursera上的硬件/软件界面课程,从那里我确定你已经看到了其中一些问题..

其中一个任务是确定2的补码整数x是否可以适合n位,仅使用运算符的子集等。我做得很好,但遇到了两种不同的方法,并用它们点击白板两者都要完全理解它们。然后是混乱。

如果可能,函数返回1,否则返回0.

方法1(正确输出)

int fooBar(int x, int n) {
    return !(((x << (32-n)) >> (32-n)) ^x);
}    

以正整数执行

fooBar(5,3)  == 0

正确计算5不能表示为2的补码3位整数。

以负整数执行

fooBar(-4,3) == 1

正确计算-4可以表示为2的补码3位整数。

方法1分析

x=5, n=3

00000000000000000000000000011101    32 - n == 29
10100000000000000000000000000000    x<<29
00000000000000000000000000000101    >> 29


00000000000000000000000000000101    5
             XOR
00000000000000000000000000000101    5
--------------------------------    
00000000000000000000000000000000    0

00000000000000000000000000000001   !0 == answer, 1.

如您所见,这将返回0,因为没有5可能不会表示为3位内的2的补码整数。

方法2(输出错误)

int fooBar(int x, int n) {
    return !((x & ~(1 << (32-n))) ^x);
}

以正整数执行

fooBar(5,3)  == 1

误报。

以负整数执行

fooBar(-4,3) == 0

假阴性。

方法2分析

x=5, n=3

00000000000000000000000000011101    32 - n == 29

11011111111111111111111111111111    ~(1<<29)
              AND
00000000000000000000000000000101    5
--------------------------------    
00000000000000000000000000000101    5


00000000000000000000000000000101    5
              XOR
00000000000000000000000000000101    5
--------------------------------
00000000000000000000000000000000    0

00000000000000000000000000000001   !0 == answer, 1.

我正在编译:

gcc version 4.7.2 (Debian 4.7.2-5)

问题

我无法解释输出的差异,当分析表明在位级别的所有内容都是相同的时候,所以关于我可以在哪里为自己揭示这一点的任何提示/提示都是高度的赞赏。

感谢您的时间!

SC。

1 个答案:

答案 0 :(得分:3)

在方法1中,你写了

10100000000000000000000000000000    x<<29
00000000000000000000000000000101    >> 29

但这不正确(请注意,您的分析意味着fooBar(5,3) == 1)。

首先,5 << 29的结果会导致签名的32位(或更小)int溢出,这是未定义的行为。

接下来,如果移位创建指示的位模式(通常如此),结果将是负数。

右移负整数是实现定义的,常见的是算术右移,它会签名扩展,这里导致

11111111111111111111111111111101    >> 29

当xor-ed为5时给出非零结果(然后应用!产生0)。

方法2根本不起作用,因为除了某些输入的未定义行为外,它所做的只是检查(32-n)位是否已设置。