【问题标题】:Why Two's Complement?为什么是二进制补码?
【发布时间】:2011-10-14 18:36:20
【问题描述】:

我正在编写一个教程来教孩子(9 到 13 岁)编程。我从计算机本身开始,它们与计算机科学没有太大关系,它更多的是关于解决计算问题的过程。

有了这个起点,我正在引导他们理解机器可以帮助我们解决某些计算问题。人们擅长抽象思维和想象力,但计算机在遵循明确规定的程序方面非常出色。他们可以以惊人的速度一次又一次地做到这一点!

我的教程已经介绍了以二进制格式表示数字。但是你如何表示负数?在任何符号系统中都有很多方法可以做到这一点,但是为计算机选择的系统有一个非常具体的原因:减少添加有符号整数值所涉及的机器数量。我们不想仅仅为了处理负数而构建和构建单独的芯片,我们希望使用我们一直用于自然数运算的相同芯片!

如果有人在街上问你(这看起来完全不切实际)“计算机如何表示负数,为什么要这样表示?”

我的具体问题:

  1. 计算机如何表示负数?

  2. 为什么计算机用这种方式表示负数?

我猜这么多经验丰富的开发人员可能不得不考虑一下这个问题。有些人甚至无法想出答案。我不是想浮夸,这是根据实际经验,我问过专业开发人员这个问题,他们无法回答。他们面无表情。给他们 JBoss 和 JavaBeans,他们会让你充满信心。太搞笑了!我也很纠结这个问题,我每次都必须提醒自己答案,我需要一张纸或白板来制定解决方案。我希望引导学生更好地了解他们正在使用的机器。

【问题讨论】:

标签: computer-science twos-complement


【解决方案1】:

1.计算机如何表示负数?

取正值,反转所有位并加一。

2.为什么计算机用这种方式表示负数?

在 -7 中添加 7 并得出零很容易。位操作很快。


如何让它变得简单?

以 7 和 -7 为例。如果您将 7 表示为 00000111,则找到 -7 反转所有位并加一:

11111000 -> 11111001

现在您可以添加以下标准数学规则:

  00000111
+ 11111001
-----------
  00000000

对于计算机来说这个操作比较简单,基本上就是逐位比较和携带一个。

如果您将 -7 表示为 10000111,这将没有意义:

  00000111
+ 10000111
-----------
  10001110 (-14)

要添加它们,您将涉及更复杂的规则,例如分析第一位和转换值。

不要忘记@trashgod 所说的,在 2 的补码中你只有一个零。要检查它:

00000000
11111111(反转所有位)
00000000(加一)

不同于00000000 (0) 等于10000000 (-0)

【讨论】:

  • 街上的人不会知道比特是什么,也不知道反转它们意味着什么。
  • 好的不错的cmets,感谢您的反馈。但是想象一下,如果你是一个试图理解这一点的 8 岁孩子。 “它让它变得容易”是不够的。他们会立即回过头来,“它如何使它更容易,为什么,我不明白”。他们非常聪明,就像你我那个年纪一样。你的回答很好,但我需要孩子更容易理解的东西。
  • @agf,如果有人在街上问我,我会这样回答。如果问题是关于 2 的补码,这个人可能知道一点是什么。
  • @dvanaria 首先解释了正数是如何用二进制表示的。 如果不先了解这一点,您将无法理解二进制补码。
  • @dvanaria 例如,如果你证明了-(-5) = 5,这也将有助于吸引他们的直觉。这将向他们“证明”加 1 不是破坏性的,即使你加 1 两次,你也会得到原来的数字。
【解决方案2】:

为什么计算机用这种方式表示负数?

我能想到的两大原因:

  • 基本算术运算的简单性。您不必担心检查符号位来决定是加还是减。
  • 表示的唯一性。不必担心负零是很好的,因为没有办法在二进制补码中表示负零。

From Wikipedia:

二进制补码系统的优点是不需要加法和减法电路检查操作数的符号以确定是加还是减。此属性使系统更易于实现并且能够轻松处理更高精度的算术。此外,零只有一个表示,消除了与负零相关的微妙之处,后者存在于一个补码系统中。

【讨论】:

  • 很棒的答案。但我必须向你提出一点挑战,不是要成为一个混蛋,而是因为这个问题与我正在研究的问题非常接近。我从您的回答中猜测您可能无法从逻辑门级别理解 CPU。这听起来确实像我对此很自大,但根本不是这样。我发现这些事情实际上非常困难。所以,我的问题是,构建一个加法器需要多少个逻辑门?假设您只使用 NAND 门构建。这个答案是否似曾相识,还是我离题了?
  • (评论不被视为傲慢,别担心。)我的大学计算机系统课程已经有大约 4 年了,所以我不记得 AND/OR/NOT/XOR/etc 到底是如何内置于闩锁/触发器/等。也就是说,我不确定您的进一步问题是否与教小孩子有关二进制表示的知识立即相关。只是纸上的二进制算术,很清楚二进制补码如何简化事情。
  • 对,好点。但这是相关的。这就是为什么。如果您向孩子灌输有关二进制符号和二进制恭维的详细信息,他们很快就会失去兴趣。但是当你向他们提出一个问题时,即使它很复杂,就像“好的,这是一台可以做 x 和 y 的机器,你能让它在 -5 上加 7 吗?” - 如果它在他们的脑海中闪现:“好吧,机器只能做这件事,但也许我可以改变输入事物的表示方式......”我知道这对于一个 9 岁的孩子来说似乎有些遥远,但事实并非如此。更聪明的孩子会急于解决这类问题。
  • @dvanaria:如果您使用传播进位,则每个位对需要一个 AND 和一个 XOR(因此对于 8 位字节,您需要 16 个门,如果您是仅使用 NAND,您可能会落在 24-48 区域)。我怀疑减法“门”的大小大致相同。当然,如今的 CPU 倾向于在 32 位或 64 位量化器上运行,因此现在节省更多。
  • 现代 CPU 使用超前进位加法器 (en.wikipedia.org/wiki/Carry-lookahead_adder) 来提高速度。像@Vatine 所说的一个简单的波纹进位加法器需要更长的时间,因为进位必须一直传播到最后才能完成操作,并且在进位超前加法器中,进位首先传播(可以更快地完成)然后送入加法器。
【解决方案3】:

计算机如何表示负数?

计算机通过计算从零减去该数字所得到的结果来表示负数,使用它们的正常减法规则。也就是说,要找到-5 在二进制中的样子,你从0(二进制)中减去5(二进制):

0  0  0  0 -
0  1  0  1
----------

              (borrow)
-> 1 -> 1 -> 1 ->10 -
   0    1    0    1
   ----------------
   1    0    1    1

..so -5 在二进制中看起来像 1011。

为什么计算机用这种方式表示负数?

因为这样做意味着当计算机在加减数字时,它不必检查其中一些是否为负数:无论如何,数学都是可行的。这使得计算机更简单,更简单的计算机制造成本更低。

【讨论】:

    【解决方案4】:

    写下数轴

    -32768...-1, 0, 1, 2, ... 32767

    向右添加动作。减法向左移动。概念上不错,但我们如何表示标志?

    我们可以使用“有符号的幅度”,其中符号和值是分开的。这会让人感到困惑,因为我们有两条不同符号的平行数轴。

    “有符号幅度”的替代方法是将每个数字编码为另一个数字。

    我们可以为所有数字添加 32768 的偏移量。新的范围是无符号的 0 到 65535。一切仍然有效,对吧?您只需将一个固定的偏差值应用于所有数字。向右添加动作。减法向左移动。 32768可以解码为0。0可以解码为-32768。

    这非常有效。 “编码”一个数字只是增加了一个偏差。 “解码”一个数字只是减去偏差。

    这是另一种编码方案。

    将所有负数移到数轴的另一侧。

    0, 1, 2, ..., 32767, -32768, ... -1

    加法仍然向右移动。取任何数字(有一个例外)。它右边的数字总是更大。

    一个例外是 32767。它右边的数字是“溢出”。

    减法仍然向左移动。取任何数字(有一个例外)。左边的数字总是更小。一个例外是 -32768。它左边的数字是“下溢”。

    编码和解码涉及更多。 0 到 32767 有一个琐碎的编码和解码:什么都不做。这些数字被编码为它们本身。但是,32768 到 65535 是负数的编码。

    【讨论】:

      【解决方案5】:

      Two的补码用于将加法和减法简化为一个可以由一个硬件单元执行的操作。不是从另一个数字中减去一个数字,而是在二进制补码算术中将一个数字的倒数加到另一个数字上。在过去,拥有一个单独的硬件来减法是​​一件大事,所以想出一个用一个单元来执行减法和加法的系统非常有用。

      您可以通过翻转位并加一来找到二进制补码中任何数字的倒数。例如,-1 在四位实现中将表示如下:

       1: 0001
      -1: 1110 + 1 = 1111
      

      您可以通过添加两个来验证这一点:

       0001 + 1111 = 10000
      

      不过,我们使用的是 4 位,因此结果会被截断。我们现在有0000 或0。我们添加了一个数字及其负数并得到零。万岁!

      现在,作为最后一个示例,让我们执行 4 - 6。4 表示为 0100。 6 表示为0110。要获得 -6,请翻转位并加一:1001 + 1 = 1010。 0100 + 1010 = 1110。 1110 是一个负数(所有最高有效数字中带有1 的数字在二进制补码中都是负数)。为了找出它的绝对值,我们翻转位并加 1。0001 + 1 = 0010,或 2。因此,我们相加的结果是 -2。 4 - 6 -2。我们的数学检查出来了。

      恭喜。你现在和电脑一样聪明。

      【讨论】:

        【解决方案6】:

        第一季度。计算机如何表示负数?

        2's compliment method!

        第二季度。为什么计算机以这种方式表示负数?

        以下是 2 的恭维的工作原理:

        对于任意 x,

        x + ~x   = all the bits set  
        x + ~x   = 2^m - 1      (2^m = the range of numbers we opt)  
          -x     = ~x + 1 - 2^m (we can cancel out mod 2^m, which gives)  
          -x     = ~x + 1 
        

        如您所见,2 的恭维是合乎逻辑且易于实现的,并且没有极端情况,这就是为什么它优于其他方法的原因。
        让我们考虑1's compliment,这是一种我在谈论的极端情况的方法,其中存在 0 和 -0(所有未设置的位 = 0,所有位设置 = -0),这意味着要为硬件电路执行更多操作,特别是在数字 x 和 -0 的操作期间。 [维基百科在Avoiding Negative Zero上有很好的例子,你可以看看]

        我希望这个解释能抚慰你孩子的心灵......

        【讨论】:

          猜你喜欢
          • 2017-02-27
          • 2015-08-26
          • 1970-01-01
          • 2012-11-23
          • 1970-01-01
          • 2011-02-05
          • 2020-01-24
          • 2015-04-12
          相关资源
          最近更新 更多