为什么对签名数字更喜欢两个补码而不是符号和数量?

Ray*_*Ray 196 math binary negative-number internal-representation twos-complement

我只是好奇是否有一个理由为了在二进制中表示-1,使用二进制补码:翻转位并加1?

-1表示为11111111(二进制补码)而不是(对我来说更直观)10000001,它是二进制1,第一位作为负标志.

免责声明:我不依赖二进制算术来完成我的工作!

Wel*_*bog 324

这样做是为了使加法不需要任何特殊的逻辑来处理负数.查看维基百科上的文章.

假设你有两个数字,2和-1.用你的"直观"表示数字的方式,它们分别是(00101001我坚持4位大小).在两者的补充方式中,他们是00101111.现在,让我们说我想添加它们.

两个补码的添加非常简单.您可以正常添加数字,最后的任何进位都将被丢弃.所以他们添加如下:

  0010
+ 1111
=10001
= 0001 (discard the carry)
Run Code Online (Sandbox Code Playgroud)

0001 是1,这是"2 +( - 1)"的预期结果.

但在你的"直观"方法中,添加更复杂:

  0010
+ 1001
= 1011
Run Code Online (Sandbox Code Playgroud)

哪个是-3,对吗?在这种情况下,简单的添加不起作用.您需要注意其中一个数字是否定的,如果是这种情况则使用不同的算法.

对于这种"直观"存储方法,减法是与添加不同的操作,需要在添加数字之前对数字进行额外检查.由于您希望最基本的操作(加法,减法等)尽可能快,因此您需要以允许您使用最简单算法的方式存储数字.

此外,在"直观"存储方法中,有两个零:

0000  "zero"
1000  "negative zero"
Run Code Online (Sandbox Code Playgroud)

这些数字直观相同,但存储时有两个不同的值.每个应用程序都需要采取额外的步骤来确保非零值也不是负零.

以这种方式存储整数还有另外一个好处,那就是当你需要扩展寄存器的宽度时,存储的值.使用二进制补码,将一个4位数存储在一个8位寄存器中是一个重复的问题.最重要的一点:

    0001 (one, in four bits)
00000001 (one, in eight bits)
    1110 (negative two, in four bits)
11111110 (negative two, in eight bits)
Run Code Online (Sandbox Code Playgroud)

这只是查看较小单词的符号位并重复它直到它填充较大单词的宽度的问题.

使用您的方法,您需要清除现有位,这是一个额外的操作,除了填充:

    0001 (one, in four bits)
00000001 (one, in eight bits)
    1010 (negative two, in four bits)
10000010 (negative two, in eight bits)
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,您仍然需要设置额外的4位,但在"直观"的情况下,您还需要清除第5位.这是每个应用程序中最基本和最常见操作之一的一小步.

  • 我同意.2的补充工作.但是我们是如何在第一时间到达它的呢?如果假设我需要达到这种表示法,那么思考过程是什么.我认为到达2的补充不仅仅是运气,不是吗? (12认同)
  • @Lazer查看这篇文章,了解`我们是如何到达2s赞美的第一名.http://www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html (5认同)
  • @Suraj,我建议查看维基百科关于完整答案的两个补码的文章:https://en.wikipedia.org/wiki/Two%27s_complement.简短的回答是MSB"1"表示"-8",其余三个"1"分别表示"4","2"和"1",所以`-8 + 4 + 2 + 1 = -1`. (3认同)

Yac*_*oby 18

维基百科说:

二进制补码系统的优点是不需要加法和减法电路检查操作数的符号以确定是加或减.该属性使系统更易于实现,并且能够轻松处理更高精度的算术.此外,零只有一个表示,避免了与负零相关的细微差别,它存在于补充系统中.

换句话说,添加是相同的,无论数字是否为负数.


Rpa*_*ant 12

即使这个问题已经过时了,让我加入我的2美分.

在我解释之前,让我们回到基础.2'补码是1的补码+ 1.现在什么是1的补充,另外还有什么意义.

任何n位数及其1的补码之和为您提供可由这些n位表示的最高数字.例:

 0010 (2 in 4 bit system)
+1101 (1's complement of 2)
___________________________
 1111  (the highest number that we can represent by 4 bits)
Run Code Online (Sandbox Code Playgroud)

现在,如果我们尝试在结果中再添加1个,会发生什么.它会导致溢出.

结果将1 0000是0(因为我们使用4位数字,(左边的1是溢出)

所以,

Any n-bit number + its 1's complement = max n-bit number
Any n-bit number + its 1'complement + 1 = 0 ( as explained above, overflow will occur as we are adding 1 to max n-bit number)
Run Code Online (Sandbox Code Playgroud)

然后有人决定将1的补码+ 1称为2'补码.所以上面的陈述变成:任何n位数+其2的补数= 0,这意味着2的补数= - (该数字)

所有这些产生了另外一个问题,为什么我们只能使用n位中的(n-1)来表示正数,为什么最左边的第n位代表符号(最左边的位表示+ ve数字,1表示-ve号).例如,为什么我们只使用java中int的前31位表示正数,如果第32位为1,则为-ve数.

 1100 (lets assume 12 in 4 bit system)
+0100(2's complement of 12)
___________________________
Run Code Online (Sandbox Code Playgroud)

1 0000(结果为零,进位1溢出)

因此,(n + 2'实现n)= 0的系统仍然有效.这里唯一不明确的是12的补码12是0100,它除了在2s补码系统中代表-12之外,它也模糊地表示+8.

如果正数在最左边的位中始终为0,则会解决此问题.在那种情况下,它们的2的补码在它们最左边的位中总是有1,并且我们不会有同一组位的模糊性,表示2的补码数和+ ve数.


Zif*_*fre 8

二进制补码允许以正常方式进行加法和减法(就像你为无符号数字缠绕一样).它还可以防止-0(使用正常的逐位比较数字方法表示0不会等于0的单独方式).


Ste*_*rna 6

这是为了简化数字的总和和差异.在2的补码中编码的负数和正数之和与以正常方式对它们求和相同.


Cod*_*ile 6

二进制补码允许负数和正数相加而无需任何特殊逻辑。

如果您尝试使用您的方法
10000001 (-1)
+00000001 (1)添加 1 和 -1,
您将得到
10000010 (-2)

相反,通过使用二进制补码,我们可以添加

11111111 (-1)
+00000001 (1) 你得到
00000000 (0)

减法也是如此。

此外,如果您尝试从 6(两个正数)中减去 4,您可以对 4 进行 2 的补码并将两者相加 6 + (-4) = 6 - 4 = 2

这意味着正数和负数的减法和加法都可以由 cpu 中的同一电路完成。


yai*_*chu 5

要扩展其他答案:

补码

  • 加法与普通正整数加法的机制相同。
  • 减法也不会改变
  • 还有乘法!

除法确实需要不同的机制。

所有这些都是正确的,因为二进制补码只是正常的模算术,我们选择通过减去模数来将某些数字视为负数。


pue*_*tzk 5

操作的通常实现是"翻转位并添加1",但还有另一种定义它的方法可能使基本原理更清晰.2的补码是你得到的形式,如果你采用通常的无符号表示,其中每个位控制下一个2的幂,并且只使最重要的项为负.

取8位值a 7 a 6 a 5 a 4 a 3 a 2 a 1 a 0

通常的无符号二元解释是:
2 7*a 7 + 2 6*a 6 + 2 5*a 5 + 2 4*a 4 + 2 3*a 3 + 2 2*a 2 + 2 1*a 1 + 2 0*a 0
11111111 = 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 255

二者的补语解释是:
-2 7*a 7 + 2 6*a 6 + 2 5*a 5 + 2 4*a 4 + 2 3*a 3 + 2 2*a 2 + 2 1*a 1 + 2 0*a 0
11111111 = -128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = -1

其他任何一个位都没有改变含义,并且进入7是"溢出"并且预期不起作用,因此几乎所有的算术运算都没有修改地工作(正如其他人已经注意到的那样).符号幅度通常检查符号位并使用不同的逻辑.