什么是"2的补充"?

Fra*_*k V 410 binary computer-science bit-manipulation twos-complement data-representation

我在计算机系统课程中,并且一直在与Two's Complement一起挣扎.我想了解它,但我读过的所有内容并没有为我提供图片.我已经阅读了维基百科文章和其他各种文章,包括我的教科书.

因此,我想开始这个社区wiki帖子来定义Two's Complement是什么,如何使用它以及它如何在诸如强制转换(从有符号到无符号,反之亦然)等操作中影响数字,逐位操作和位移操作.

我所希望的是一个清晰简洁的定义,程序员很容易理解.

lav*_*nio 596

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

要理解,您必须考虑二进制数字.

它基本上说,

  • 为零,使用全0.
  • 对于正整数,开始向上计数,最大值为2 (位数 - 1) -1.
  • 对于负整数,执行完全相同的操作,但切换0和1的角色(因此不是从0000开始,而是从1111开始 - 这是"补充"部分).

让我们尝试一个4位的小字节(我们称之为半字节 - 1/2个字节).

  • 0000 - 零
  • 0001 - 一个
  • 0010 - 两个
  • 0011 - 三
  • 01000111- 四到七

这就是我们可以采取积极的态度.2 3 -1 = 7.

对于否定:

  • 1111 - 消极的
  • 1110 - 否定两个
  • 1101 - 否定三
  • 11001000-负四,负8

请注意,您为负数(1000= -8)获得了一个额外的值,而不是肯定的.这是因为0000用于零.这可以视为计算机的数字行.

区分正数和负数

这样做,第一位获得"符号"位的作用,因为它可用于区分正十进制值和负十进制值.如果最高有效位是1,那么二进制可以说是负数,其中就好像最高有效位(最左边)是0,你可以说识别十进制值是正数.

"一个人的称赞"负数只是翻转符号位,然后从0开始计算.但这种方法必须将解释1000称为"负零",这令人困惑.在靠近硬件工作时,通常只需要担心这一点.

  • 可能两个补码中最好的部分是如何简化数学.尝试一起添加2(0010)和-2(1110),你得到10000.最重要的位是溢出,所以结果实际上是0000.几乎像魔术,2 + -2 = 0. (133认同)
  • 除了简单的加法和减法之外的另一个优点是2s补码只有一个零.如果您使用简单的符号位,比如使用0001表示+1和1001表示-1,则您将有两个零:0000("+ 0")和1000(" - 0").这背后真的很痛苦. (92认同)
  • 赞成它的重点,并解释为什么负值具有较大范围的正值.我来找范围差异的原因. (22认同)
  • 你不应该说"对于负整数,做同样的事情,但倒数并切换0和1的角色" (2认同)

Vin*_*nie 327

我想知道它是否可以比维基百科文章更好地解释.

您尝试使用二进制补码表示的基本问题是存储负整数的问题.

首先考虑以4位存储的无符号整数.您可以拥有以下内容

0000 = 0
0001 = 1
0010 = 2
...
1111 = 15
Run Code Online (Sandbox Code Playgroud)

这些是未签名的,因为没有迹象表明它们是否定为正面.

签署量级和超额表示法

要存储负数,您可以尝试许多事情.首先,您可以使用符号幅度表示法,将第一位指定为符号位以表示+/-,将剩余位指定为幅度.所以再次使用4位并假设1意味着​​ - 而0意味着+那么你就拥有了

0000 = +0
0001 = +1
0010 = +2
...
1000 = -0
1001 = -1
1111 = -7
Run Code Online (Sandbox Code Playgroud)

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

什么是

0010
1001 +
----
Run Code Online (Sandbox Code Playgroud)

另一个系统是多余的表示法.你可以存储负数,你摆脱了两个零问题,但加法和减法仍然很困难.

所以随之而来的是两个补充.现在,您可以存储正负整数并相对轻松地执行算术运算.有许多方法可以将数字转换为二进制补码.这是一个.

将十进制转换为二进制补码

  1. 将数字转换为二进制(暂时忽略符号),例如5为0101,-5为0101

  2. 如果数字是正数,那么你就完成了.例如,5是使用二进制补码表示法的二进制0101.

  3. 如果数字是负数那么

    3.1找到补码(反转0和1),例如-5是0101,所以找到补码是1010

    3.2在补码1010 + 1 = 1011中加1.因此,2的补码中的-5是1011.

那么,如果你想在二进制中做2 +( - 3)怎么办?2 +( - 3)为-1.如果您使用符号幅度来添加这些数字,您需要做什么?0010 + 1101 =?

使用两个补码考虑它是多么容易.

 2  =  0010
 -3 =  1101 +
 -------------
 -1 =  1111
Run Code Online (Sandbox Code Playgroud)

将两个补码转换为十进制

将1111转换为十进制:

  1. 数字从1开始,所以它是负数,所以我们找到1111的补码,即0000.

  2. 加1到0000,我们获得0001.

  3. 将0001转换为十进制,即1.

  4. 应用sign = -1.

田田!

  • 我认为最好的答案. (41认同)
  • 是的,这个非常简单并且非常好地解释了这个问题 (5认同)
  • 此答案应在Wikipedia上使用。 (4认同)
  • 我不明白在转换两种方式时添加一个总是会导致相同的数字.在我看来,你会颠倒这些步骤,或者减去一个或者某个东西. (3认同)
  • 为什么要在补数上加1? (2认同)

小智 112

像我看到的大多数解释一样,上面的解释清楚如何使用2的补码,但是没有真正解释它们数学上是什么.我会尝试这样做,至少对整数而言,我会介绍一些可能先熟悉的背景.

回想一下小数是如何工作的:
  2345
是一种写
  2 ×10 3 + 3 ×10 2 + 4 ×10 1 + 5 ×10 0的方法.

以同样的方式,二进制是一种使用01编写数字的方法,遵循相同的一般想法,但用2替换上面的10.然后在二进制中,
  1111
是一种写
  1 ×2 3 + 1 ×2 2 + 1 ×2 1 + 1 ×2 0的方法
,如果你解决了,那就是等于15(基数10).那是因为它是
  8 + 4 + 2 + 1 = 15.

对于正数而言,这一切都很好.如果你愿意在他们面前贴一个减号,它甚至适用于负数,就像人类用十进制数字做的那样.这甚至可以在计算机中完成,但是从1970年代早期开始我就没有看过这样的计算机.我将留下不同讨论的理由.

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

幸运的是,计算机并不代表无穷大.数字被约束到特定长度(或宽度,如果您愿意).所以让我们回到正二进制数,但具有特定的大小.对于这些示例,我将使用8位数("位").所以我们的二进制数确实是
  00001111

  0 ×2 7 + 0 ×2 6 + 0 ×2 5 + 0 ×2 4 + 1 ×2 3 + 1×2 2 + 1 ×2 1 + 1 ×2 0

为了形成2的补数否定,我们首先补充所有(二进制)数字以形成
  11110000
并将1加到形成
  11110001
但是我们如何理解为-15?

答案是我们改变了高阶位(最左边的位)的含义.对于所有负数,该位将为1.改变将是改变它对其出现的数值的贡献的符号.所以现在我们的11110001被理解为代表
  - 1 ×2 7 + 1 ×2 6 + 1 ×2 5 + 1 ×2 4 + 0 ×2 3 + 0×2 2 + 0 ×2 1 + 1 ×2 0
注意表达式前面的" - "?这意味着符号位的权重为-2 7,即-128(基数为10).所有其他位置保留与无符号二进制数相同的权重.

计算出我们的-15,它是
  -128 + 64 + 32 + 16 + 1
在您的计算器上试一试.这是-15.

在我看到计算机中出现负数的三种主要方式中,为了方便一般使用,2的补码获胜.但它有一个奇怪的地方.由于它是二进制的,因此必须存在偶数个可能的位组合.每个正数可以与其负数配对,但只有一个零.否定零会让你变为零.所以还有一个组合,符号位为1,其他位置为0.相应的正数不符合正在使用的位数.

对于这个数字更奇怪的是,如果你试图通过补充和添加一个来形成积极的,那么你会得到相同的负数.看起来很自然零会这样做,但这是出乎意料的并且根本不是我们习惯的行为,因为除了计算机之外,我们通常会想到无限制的数字,而不是这种固定长度的算术.

这就像是一个奇怪的冰山一角.在表面之下还有更多的等待,但这对于这次讨论来说已经足够了.如果研究定点算术的"溢出",你可能会找到更多.如果你真的想进入它,你也可以研究"模运算".

  • 我喜欢这个答案!解释取 2 的补码并加 1 的工作原理。 (3认同)
  • 虽然其他答案专注于“如何”,但这个答案温和地引导我们“为什么”。它帮助了我。谢谢! (2认同)

小智 18

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

取二进制,例如:1101 [假设空格"1"是符号]等于-3.

使用2的补码我们会这样做...翻转1101到0010 ...添加0001 + 0010 ===>给我们0011. 0011 in positive binary = 3.因此1101 = -3!

我意识到的:

而不是所有的翻转和添加,你可以只做基本方法求解正二进制(假设0101)是(2 3*0)+(2 2*1)+(2 1*0)+(2 0*1)= 5.

用负面做完全相同的概念!(带小扭曲)

以1101为例,例如:

对于第一个数而不是2 3*1 = 8,做 - (2 3*1)= -8.

然后像往常一样继续,做-8 +(2 2*1)+(2 1*0)+(2 0*1)= -3

  • 计算机系统:程序员的观点一书中提到了这种方法。 (2认同)

Cap*_*ult 14

想象一下,你有一个有限数量的位/ trits/digits /无论如何.您将0定义为所有数字为0,并自然向上计数:

00
01
02
..
Run Code Online (Sandbox Code Playgroud)

最终你会溢出.

98
99
00
Run Code Online (Sandbox Code Playgroud)

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

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

因此,为简单起见,我们可以说任何超过50的数字都是负数."0"到"49"代表0到49."99"是-1,"98"是-2,......"50"是-50.

这种表示是十的补充.计算机通常使用二进制补码,除了使用位而不是数字之外,它们是相同的.

关于十个补充的好处是加法才有效.您不需要做任何特殊的事情来添加正数和负数!


小智 5

通过添加给定数字的第1至第1个补码找出两个补码.让我们说我们必须找出两个补码,10101然后找到它的补码,也就是说,01010添加1到这个结果,也就是说01010+1=01011,这是最终的答案.


Ali*_*ter 5

我以里程表为类比,阅读了jng 关于Reddit的精彩解释。

在此处输入图片说明

这是一个有用的约定。如果使用约定,则在二进制中加/减正数的相同电路和逻辑运算仍然可以在正数和负数上工作,这就是为什么它是如此有用且无所不在的原因。

想象一下汽车的里程表在(例如)99999处滚动。如果增加00000,则得到00001。如果减小00000,则得到99999(由于滚转)。如果将99999加1,它将回到00000。因此确定99999表示-1非常有用。同样,确定99998表示-2非常有用,依此类推。您必须停在某个地方,并且按照惯例,数字的上半部分将被视为负数(50000-99999),而下半部分的正数将代表自己(00000-49999)。结果,高位数字为5-9表示所代表的数字为负数,高位数字为0-4表示所代表的数字为正数-与表示二进制补码二进制数符号的最高位完全相同。

我也很难理解这一点。一旦获得并返回以重新阅读书籍文章和解释(那时还没有互联网),结果发现很多描述它的人并不真正理解它。在那之后,我确实写了一本教汇编语言的书(这本书卖了十年很不错)。