我在上一门计算机系统课程,在某种程度上,我一直在为“二的补充”而挣扎。我想了解它,但我所读到的一切并没有让我明白它的含义。我读过维基百科的文章和其他各种文章,包括我的课本。

什么是2的补数,我们如何使用它,它如何在强制转换(从有符号到无符号,反之亦然)、逐位操作和位移位操作等操作中影响数字?


当前回答

想象一下,你有有限数量的比特/比特/数字等等。将0定义为所有数字都为0,并自然向上计数:

00
01
02
..

最终你会溢出。

98
99
00

我们有两位数字,可以表示从0到100的所有数字。所有这些数字都是正数!假设我们也想表示负数?

我们真正拥有的是一个循环。2之前的数字是1。1之前的数字是0。0之前的数字是…99.

为了简单起见,我们设任何大于50的数都是负数。0 ~ 49代表0 ~ 49。“99”是-1,“98”是-2,…“50”是-50。

这个表示是十的补数。计算机通常使用2的补码,除了使用位而不是数字之外,它是一样的。

10的补数的好处在于加法运算可以正常进行。你不需要做任何特殊的加法和负数!

其他回答

就像我看到的大多数解释一样,上面的解释清楚地说明了如何使用2的补码,但并没有真正解释它们在数学上是什么。我会试着这么做,至少对整数来说是这样的,我会先介绍一些你们可能熟悉的背景知识。

回想一下它是如何用于十进制的:2345是2 × 103 + 3 × 102 + 4 × 101 + 5 × 100的一种写法。

同样地,二进制是一种只使用0和1来写数字的方法,遵循相同的思路,但把上面的10换成了2。然后在二进制中,1111是1 × 23 + 1 × 22 + 1 × 21 + 1 × 20的一种写法,如果你算出来,结果等于15(以10为底)。因为8+4+2+1 = 15。

这对于正数来说很好。它甚至适用于负数,如果你愿意在负数前面加一个负号,就像人类对待小数一样。在某种程度上,这甚至可以在计算机上完成,但我从20世纪70年代初就没见过这样的计算机了。我将把原因留到另一个讨论。

对于计算机来说,负数使用补表示法效率更高。这里有一些经常被忽视的东西。补表示法涉及到数字数字的某种反转,甚至是在正常正数之前隐含的零。这很尴尬,因为问题来了:所有这些?这可能是一个无限的数字要考虑。

幸运的是,计算机并不代表无穷。数字被限制在特定的长度(或者宽度,如果你喜欢)。所以让我们回到正二进制数,但有一个特定的大小。在这些例子中,我将使用8个数字(“位”)。所以我们的二进制数应该是00001111或者0 × 27 + 0 × 26 + 0 × 25 + 0 × 24 + 1 × 23 + 1 × 22 + 1 × 21 + 1 × 20

为了形成2的补负,我们首先将所有的(二进制)数字补成11110000,然后加上1,形成11110001,但我们如何理解这意味着-15?

The answer is that we change the meaning of the high-order bit (the leftmost one). This bit will be a 1 for all negative numbers. The change will be to change the sign of its contribution to the value of the number it appears in. So now our 11110001 is understood to represent  -1 × 27 + 1 × 26 + 1 × 25 + 1 × 24 + 0 × 23 + 0 × 22 + 0 × 21 + 1 × 20Notice that "-" in front of that expression? It means that the sign bit carries the weight -27, that is -128 (base 10). All the other positions retain the same weight they had in unsigned binary numbers.

算出-15,就是-128 + 64 + 32 + 16 + 1用计算器试试。它是-15。

Of the three main ways that I've seen negative numbers represented in computers, 2's complement wins hands down for convenience in general use. It has an oddity, though. Since it's binary, there have to be an even number of possible bit combinations. Each positive number can be paired with its negative, but there's only one zero. Negating a zero gets you zero. So there's one more combination, the number with 1 in the sign bit and 0 everywhere else. The corresponding positive number would not fit in the number of bits being used.

关于这个数字更奇怪的是,如果你试图通过互补和加1来形成正数,你会得到相同的负数。0会这样做似乎很自然,但这是出乎意料的,完全不是我们习惯的行为,因为除了计算机,我们通常认为数字是无限供应的,而不是这种固定长度的算术。

这只是怪胎的冰山一角。表面之下还有更多的东西在等待着,但这就足够我们讨论了。如果你研究定点算术中的“溢出”,你可能会发现更多。如果你真的想深入了解它,你可能还会研究“模算术”。

2的补码对于查找二进制值非常有用,但是我想到了一个更简洁的方法来解决这样的问题(从未见过其他人发布它):

以二进制为例:1101(假设空格“1”是符号)等于-3。

使用2的补码,我们可以这样做…翻1101到0010…加上0001 + 0010 ===>得到0011。0011的正二进制= 3。因此1101 = -3!

我意识到:

而不是所有的翻转和加法,你可以只做一个基本的方法来解决正二进制(假设0101)是(23 * 0)+(22 * 1)+(21 * 0)+(20 * 1)= 5。

用否定句做同样的概念!(稍微扭曲一下)

以1101为例:

对于第一个数字,用-(23 * 1)= -8代替23 * 1 = 8。

然后像往常一样,做-8 + (22 * 1)+ (21 * 0)+ (20 * 1)= -3

这是一种对负整数进行编码的聪明方法,该方法将数据类型中大约一半的位组合保留给负整数,并且将大多数负整数与其对应的正整数相加会导致进位溢出,使结果为二进制零。

因此,在2的补码中,如果1是0x0001,那么-1是0x1111,因为这将导致0x0000的组合和(溢出1)。

让我们用8位的二进制形式得到答案10 - 12: 我们要做的是10 + (-12)

我们需要用12的恭维部分减去10。 12的二进制值是00001100。 10的二进制值是00001010。

为了得到12的赞美部分,我们只需要把所有的位反转,然后加1。 12的二进制反转是11110011。这也是逆码(一个人的补码)。 现在我们需要加一个,现在是11110100。

所以11110100是12的赞美!这样想很简单。

现在你可以用二进制形式来解决上面的10 - 12问题了。

00001010
11110100
-----------------
11111110  

我喜欢lavinio的回答,但变换部分增加了一些复杂性。通常情况下,可以选择在保留符号位的情况下移动位,或者不保留符号位。这是将数字处理为有符号数字(-8到7表示小块,-128到127表示字节)或全范围无符号数字(0到15表示小块,0到255表示字节)之间的选择。