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

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


当前回答

我在Reddit上读到jng的一篇精彩的解释,用里程表做类比。

It is a useful convention. The same circuits and logic operations that add / subtract positive numbers in binary still work on both positive and negative numbers if using the convention, that's why it's so useful and omnipresent. Imagine the odometer of a car, it rolls around at (say) 99999. If you increment 00000 you get 00001. If you decrement 00000, you get 99999 (due to the roll-around). If you add one back to 99999 it goes back to 00000. So it's useful to decide that 99999 represents -1. Likewise, it is very useful to decide that 99998 represents -2, and so on. You have to stop somewhere, and also by convention, the top half of the numbers are deemed to be negative (50000-99999), and the bottom half positive just stand for themselves (00000-49999). As a result, the top digit being 5-9 means the represented number is negative, and it being 0-4 means the represented is positive - exactly the same as the top bit representing sign in a two's complement binary number. Understanding this was hard for me too. Once I got it and went back to re-read the books articles and explanations (there was no internet back then), it turned out a lot of those describing it didn't really understand it. I did write a book teaching assembly language after that (which did sell quite well for 10 years).

其他回答

Two的补码是一种存储整数的聪明方法,因此常见的数学问题很容易实现。

为了理解,你必须把数字想象成二进制。

它基本上是说,

对于0,用所有的0。 对于正整数,开始计数,最大值为2(位数-1)-1。 对于负整数,做完全相同的事情,但是切换0和1的角色并开始倒数(所以不是从0000开始,而是从1111开始——这是“补”部分)。

让我们尝试一个4位的迷你字节(我们称之为1/2个字节)。

0000 -零 0001 - 1 0010 - 2 0011 - 3 0100到0111,4点到7点

这是我们目前能找到的阳性结果。23-1 = 7。

负面影响:

1111 - 1 1110 - 2 1101 - 3 1100到1000 - - 4到- 8

注意,负数(1000 = -8)有一个额外的值,而正数没有。这是因为0000用于表示零。这可以看作是计算机的数轴。

区分正数和负数

这样一来,第一个位就扮演了“符号”位的角色,因为它可以用来区分非负的十进制值和负的十进制值。如果最高有效位是1,那么二进制就可以说是负的,如果最高有效位(最左边)是0,就可以说十进制值是非负的。

“符号量级”的负数只是将它们的正数对应的符号位颠倒了,但这种方法必须处理将1000(一个1后面跟着所有的0)解释为“负零”,这是令人困惑的。

“1的补”负数只是它们的正数的位补,这也导致了“负零”和1111(都是1)的混淆。

除非你的工作非常接近硬件,否则你可能不需要处理个位补或符号幅度整数表示。

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

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

到目前为止,许多答案都很好地解释了为什么2的补数被用来表示负数,但没有告诉我们2的补数是什么,尤其是没有告诉我们为什么加了一个“1”,而且实际上经常以错误的方式加。

这种混淆来自于对补数定义的不理解。补语是指使某物完整的缺失部分。

根据定义,n位数x以b为基数的基数补是b^n-x。

在二进制中,4由100表示,它有3位数字(n=3)和基数2 (b=2)。所以它的基数补是b^n-x = 2^3-4=8-4=4(或二进制的100)。

然而,在二进制中,求一个基数的补并不像求它的消简基数补那么容易,消简基数补定义为(b^n-1)-y,只比基数补小1。要得到一个减少的基数补,只需翻转所有的数字。

100 -> 011(减基数补位)

为了得到基数(2的)补,我们只需按定义加1。

011 +1 ->100(2的补码)。

现在,有了这个新的理解,让我们看看Vincent Ramdhanie给出的例子(见上面的第二个回答):

将1111转换为十进制: 这个数从1开始,所以它是负的,所以我们找到1111的补数,也就是0000。 0000加上1,得到0001。 将0001转换为十进制,即1。 应用符号= -1。 大作。

应理解为:

数字从1开始,所以是负的。所以我们知道它是x的一个2的补。为了找到由它的2的补表示的x,我们首先需要找到它的1的补。

x的2的补数是1111 x的补数:1111-1 ->1110; X = 0001,(翻转所有数字)

应用符号-,结果=-x =-1。

补一词来源于完备性。在十进制世界中,数字0到9提供了一个数字或数字符号的补集(完整集)来表示所有的十进制数。在二进制世界中,数字0和1提供了一个数字的补数来表示所有二进制数。事实上,符号0和1必须用来表示所有东西(文本、图像等)以及正(0)和负(1)。 在我们的世界里,数字左边的空白被认为是零:

                  35=035=000000035.

In a computer storage location there is no blank space. All bits (binary digits) must be either 0 or 1. To efficiently use memory numbers may be stored as 8 bit, 16 bit, 32 bit, 64 bit, 128 bit representations. When a number that is stored as an 8 bit number is transferred to a 16 bit location the sign and magnitude (absolute value) must remain the same. Both 1's complement and 2's complement representations facilitate this. As a noun: Both 1's complement and 2's complement are binary representations of signed quantities where the most significant bit (the one on the left) is the sign bit. 0 is for positive and 1 is for negative. 2s complement does not mean negative. It means a signed quantity. As in decimal the magnitude is represented as the positive quantity. The structure uses sign extension to preserve the quantity when promoting to a register [] with more bits:

       [0101]=[00101]=[00000000000101]=5 (base 10)
       [1011]=[11011]=[11111111111011]=-5(base 10)

用作动词: 2的补语表示否定。这并不意味着消极。意思是如果负数变成正数;如果是正的就是负的。大小是绝对值:

        if a >= 0 then |a| = a
        if a < 0 then |a| = -a = 2scomplement of a

此功能允许使用先求负后加的有效二进制减法。 A -b = A + (-b)

1的补数的官方方法是每一位数用1减去它的值。

        1'scomp(0101) = 1010.

这与逐个翻转或反转每一位是一样的。结果是- 0,这是不受欢迎的,所以给te 1的补码加上1就解决了这个问题。 要求2s的补,先求1s的补,然后加1。

        Example 1                             Example 2
         0101  --original number              1101
         1's comp  1010                       0010
         add 1     0001                       0001
         2's comp  1011  --negated number     0011

在这些例子中,否定也适用于符号扩展数。

添加: 1110进位111110进位 0110与000110相同 1111年 111111年 Sum 0101 Sum 000101

减法:

    1110  Carry                      00000   Carry
     0110          is the same as     00110
    -0111                            +11001
  ----------                        ----------
sum  0101                       sum   11111

请注意,当使用2的补码时,数字左侧的空白区域对于正数用0填充,而对于负数用1填充。进位总是被加上,必须是1或0。

干杯

我想知道是否有比维基百科上的文章更好的解释。

你试图用2的补表示法解决的基本问题是存储负整数的问题。

首先,考虑一个存储在4位的无符号整数。您可以拥有以下内容

0000 = 0
0001 = 1
0010 = 2
...
1111 = 15

这些是无符号的,因为没有指示它们是负的还是正的。

符号大小和多余符号

要存储负数,您可以尝试一些方法。首先,您可以使用符号幅度表示法,它将第一个位指定为符号位来表示+/-,其余位表示幅度。还是用4位假设1代表- 0代表+那么你就有

0000 = +0
0001 = +1
0010 = +2
...
1000 = -0
1001 = -1
1111 = -7

所以,你看到问题了吗?我们有正0和负0。更大的问题是二进制数的加减法。使用符号幅度进行加减法的电路将非常复杂。

是什么

0010
1001 +
----

?

另一个系统是过量符号。你可以存储负数,你可以摆脱两个0的问题但加减法仍然很困难。

于是就有了二的补。现在您可以存储正整数和负整数,并相对轻松地执行算术。有许多方法可以将一个数转换为二的补数。这是一个。

将十进制转换为二的补数

将数字转换为二进制(暂时忽略符号) 例如,5是0101,-5是0101 如果这个数字是正数,那么你就完成了。 例5是二进制的0101,使用二的补符号。 如果数字是负的,那么 3.1求补(0和1的倒数) 例如,-5是0101,所以找到补语是1010 3.2补数1010 + 1 = 1011加1 因此,2的补数-5等于1011。

那么,如果你想用二进制写2 +(-3)呢?2 +(-3) = -1。 如果你用符号的大小来加这些数,你需要做什么?0010 + 1101 = ?

使用2的补码,想想会有多简单。

 2  =  0010
 -3 =  1101 +
 -------------
 -1 =  1111

将2的补数转换为十进制

将1111转换为十进制:

这个数从1开始,所以它是负的,所以我们找到1111的补数,也就是0000。 0000加上1,得到0001。 将0001转换为十进制,即1。 应用符号= -1。

哒哒!