【问题标题】:bitwise: different behaviour with negative input value按位:负输入值的不同行为
【发布时间】:2013-04-25 22:28:42
【问题描述】:

我正在参加 Coursera 上的硬件/软件界面课程,我相信您已经从那里看到了其中的一些问题..

其中一项任务是确定 2 的补码整数 x 是否可以放入 n 位,仅使用运算符的子集等。我做得很好,但遇到了 2 种不同的方法,并用它们打了白板两者都充分了解它们。然后是混乱。

如果可以拟合,该函数返回 1,否则返回 0。

方法一(正确输出)

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 位整数。

方法一分析

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,如在 3 位内不能将 5 表示为 2 的补码整数。

方法二(输出错误)

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

以正整数执行

fooBar(5,3)  == 1

误报。

以负整数执行

fooBar(-4,3) == 0

假阴性。

方法二分析

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.

【问题讨论】:

    标签: c bit-manipulation


    【解决方案1】:

    在方法1中,你写

    10100000000000000000000000000000    x<<29
    00000000000000000000000000000101    >> 29
    

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

    首先,5 &lt;&lt; 29 的结果导致带符号的 32 位(或更小)ints 溢出,这是未定义的行为。

    接下来,如果移位创建了指示的位模式(如通常那样),则结果将为负数。

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

    11111111111111111111111111111101    >> 29
    

    当与 5 进行异或运算时会得到非零结果(然后应用 ! 会产生 0)。

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

    【讨论】:

    • 嗨,丹尼尔,感谢您的回复,这让我回到了这辈子破解这个东西的轨道上 :-)
    • 提示:你必须将正的n-bit 二进制补码整数向右移动多远才能获得 0?将负的n-bit 二进制补码整数移到最右边(假设算术移位)的结果是什么?
    • 你不需要移动那么远。例如,写出二进制补码三位整数类型可以容纳的所有值,并仔细查看。
    • 啊,是的,3 位正负似乎都一样(在 3 位整数的情况下)。我会重新插入并玩弄一些东西......谢谢:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-27
    • 1970-01-01
    • 1970-01-01
    • 2020-06-29
    相关资源
    最近更新 更多