保证在二进制补码中左移负数时结果为负数?

8
假设负的二进制数是用二进制补码表示的,我们怎样才能保证符号不变呢? 假设我们用四位来表示十进制数-51011,现在想左移一位以乘以2:
1011 << 1

这个操作返回0110,即6,而不是我们所希望的-10。

(我认为这只适用于第二位为0的负数,即某个范围内最小可表示负数附近的负数)


@PaulR 我读到大多数 << 的实现都同时满足 ASL 和 LSL 的要求。ASL 操作是否以某种方式保留了最高有效位(符号位)?如果是这样,它是否通过从第二位开始移位而不是 MSB 开始来实现? - sgarza62
这篇维基百科文章上的图片表明了 MSB 被移出并替换,这对于无符号数来说是可以的,但对于有符号负数来说就不行了,对吗?http://en.wikipedia.org/wiki/Arithmetic_shift - sgarza62
1
抱歉 - 我意识到我在上面的评论中说了些无聊的话:对于二进制补码,LSL和ASL是完全相同的。OP的困惑来自于不同的误解。 - Paul R
那么,在4位字段中如何表示-10? - Hot Licks
@HotLicks 在一个4位字段中是不可能的。第一位表示二进制补码系统中的符号,因此我们只剩下三位。你需要至少5位来表示-10:10110 - sgarza62
1个回答

9

楼主在这。我已经找到了我的问题的答案。

左移操作可能会触发算术溢出

二进制补码系统可表示的数字范围为-(2^(n-1))2^(n-1)-1,其中n是可用位数,包括符号位(最高位)。因此,在上面的例子中,每个数字使用4位,可能的值范围是从-87,包括边界值。

向左移动m位将把该数字乘以2^m。因此,在上面的例子中,-5 << 1将产生-10,这超出了4位带符号表示法中可能数字的范围 - 这就是溢出。

1111 << 1 == 1110 // -1 * 2 is -2
1110 << 1 == 1100 // -2 * 2 is -4
1101 << 1 == 1010 // -3 * 2 is -6
1100 << 1 == 1000 // -4 * 2 is -8
1011 << 1 == 0110 // overflow
1010 << 1 == 0100 // overflow
1001 << 1 == 0010 // overflow
1000 << 1 == 0000 // overflow

总之,在使用ASL进行二的幂次方乘法时,重要的是确保产品位于可能值的范围内。


2
在二进制补码中,如果有符号负数的第二位是0,那么左移一位将会导致溢出。同样地,如果第三位是0,那么左移两位将会导致溢出。以此类推。 - sgarza62

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接