二进制补码

转载 2016年09月12日 16:26:04

转载地址:整数二进制补码的数学原理(two's complement)

最近重新学习CPU体系结构,对使用二进制补码原理来消除带符号数和无符号数计算差异,以及整合减法运算器到加法运算器,从而简化CPU硬件设计的原理很感兴趣,所以特地思考了下,查看了一些网上关于two's complement的文章,但大部分还是太过学术,经过整理,我想以一种比较简洁的方式表达出来。为了简单起见,我使用了4位字长的寄存器作为例子,32位和64位道理一样。想了解补码更为科学的数学原理可以参考wikipedia关于one's complement、two's complement的相关文章。

硬件设计以简洁为目标,所以整数的运算最好只有加法,而且不用对符号位进行特殊处理,能达到这个目标吗?当然可以,那就是使用补码(two's complement),所谓补码其实是针对带符号数来说的,其意思就是正数使用原码,而负数使用2的字长的指数减负数的绝对值表示,即x = pow(2, word_length) - abs(x),这个补码的简单计算方法就是我们计算机书中常说的,将x绝对值取反加1。现在你知道补码的真正计算方法了吧。为什么要将负数表示成这样呢?这是有数学原理的,这正是本文需要阐释的内容,充分了解后对CPU常用指令编程就打下了坚实的基础(general purpose instructions都是针对整数的),以后可能还会增加关于浮点数计算规范的文章。

现在我们来看一个减法:
7 - 6     (式1)
能把它变成一个加法吗?我来试试:
7 + (16 - 6)- 16    (式2)
16是4位寄存器最小的溢出数(2**4 **表示pow运算),以上两个式子是完全等价的,在我们看来比较繁琐的第二个式子却正是CPU内部整数计算单元所采用的方法,由于一些特殊原因,CPU只需要计算第一个加法,其余两个减法分别由编译器、人或寄存器自动截断完成了。
经过前面的叙述,我们知道了16 - 6就是-6在4位字长机器上的补码,这步计算一般是编译器完成的,将负数直接存储为补码形式,这里是1010。我们来看看CPU如何计算:
  0 1 1 1        (7)
+ 1 0 1 0     (10)
-----------   ----------
1 0 0 0 1     (17)

以上式子完成了式(2)中前两步计算,还需要减16才能得到正确结果,神奇的地方到了,因为机器是4位字长,所以第五位1直接丢弃掉了,就是溢出,这相当于自动减了16,所以最后结果就是0001,等于1,完成了式2个所有计算,得到了正确结果,现在你应该明白了为什么会选择最小溢出数所为补码转换中的被减数了吧,就是为了完成自动溢出,从而实现最后的减法。

再来看看2个负数相加,看看CPU是如何把它们当纯粹二进制运算而结果却丝毫不差的:
(-6) + (-7)  (式3)
依据上面的规律换成如下式子
[(16 - 6) - 16] + [(16 - 7) - 16]    (式4)
其中(16 - 6)和(16 - 7)部分已经由编译器完成,就是对应负数的补码,让我们来看看CPU的计算内容:
  1 0 1 0     (10)
+ 1 0 0 1      (9)
-----------   ------
1 0 0 1 1      (19)

式4中还需要减2个16,这里第5位已经自动溢出减了一个16,我们还要减一个16才能得到正确结果,可是寄存器中结果0011,光凭这个结果,我不知道这到底是最终值还是还需要减16,这可太糟糕了,产生这个问题的原因是如果使用全部4位寄存器存储值时,会产生带符号数二进制歧义问题,打个比方,-9用二进制补码表示是(16 - 9),二进制为0111,居然和整数的7是一样的,光凭这串二进制我无法知道它是-9还是7,好吧,我确实聪明,想到了一个办法,嘿嘿,让我们来看看4位寄存器能存储的二进制有哪些:
0 0 0 0
0 0 0 1
0 0 1 0
0 0 1 1
0 1 0 0
0 1 0 1
0 1 1 0
0 1 1 1
1 0 0 0
1 0 0 1
1 0 1 0
1 0 1 1
1 1 0 0
1 1 0 1
1 1 1 0
1 1 1 1
我可以将最高位数字当作解释数字符号的标志,如果是0我就当正数解释,如果是1我就当负数解释,当正数解释后不用再减16,直接就是最终结果,而如果是负数则还需要减个16才是最终结果,因为我们是用16-x来表示-x的,正好正数负数对半(假设0是正数),再回到上面那个问题,(-6) + (-7)CPU寄存器中最终为0011,我当应该当正数解释,正数不用减16,所以最后等于3,不对!应该是-13,还需要减个16才对,可我们刚说了正数不用减。到底哪里出问题了?大家思考下。
原来如果我们将二进制用以上阐述的方式解释,决定了4位二进制表示的数的范围只能是[-8~7],实际上寄存器如果从左端溢出的话,其值是在[...0\1\2\3\4\5\6\7\-8\-7\-6\-5\-4\-3\-2\-1\0...]不断循环的,也就是说刚才的-13从-8向左数5位,又循环回到了3,我们必须有办法判断溢出情况,如果我们把寄存器中的二进制当无符号数解释,那很简单,只要最高为产生进位那就溢出了,可如果当带符号数解释,如何看最后的值是否溢出呢?
这是个补码数学原理的精髓所在,有了这个推理,CPU才能做到同等处理带符号数和无符号数,我们来仔细分析下数学上的原理,在CPU看来寄存器中的就是纯粹的二进制,相当于无符号数,如果两个数相加时,最高位产生了进位,则表示结果肯定位于[16~30],如果次高位向最高位产生了进位则表示结果低3位相加结果范围位于[8~14],由于最高位溢出被丢弃,表示对最终结果减了16,而次高位向最高位产生进位,表示最终结果最小为8,现在就有如下几种结论:
(1)最高位有进位,次高位有进位,则最终结果位于[-8~6]
(2)最高位有进位,次高位无进位,则最终结果位于[-16~-9]
(3)最高位无进位,次高位有进位,则最终结果位于[8~14]
(4)最高位无进位,次高位无进位,则最终结果位于[0~7]
而我们带符号的解释方法,决定了数的范围为[-8~7],怎么样一眼就看出该如何判断带符号数计算是否溢出了吧!

然我们来看看CPU EFLAGS寄存器中最常用的6个标志位CF,PF,AF,ZF,SF,OF,我只解释CF和OF,其余的4个都很好理解,CF表示两个操作数进行二进制整数计算时最高位发生了进位,很显然可以用来判断无符号数是否溢出,而OF是寄存器次高位是否向最高位发生进位的标志(进位1,否则为0)与CF位的XOR值,是不是很神奇,就是我们最后阐述的四项规则,正好用来判断带符号整数是否溢出。

是不是无法想象在一般书上一笔带过的整数计算用的补码规范后面却隐藏了这么多原理,正是这些特性,决定了处理器设计时采用二进制补码进行整数计算,他使带符号数和无符号数的加减运算全部用无符号数加法运算实现,使电路实现大为简化,增加了处理器效率,减少了设计制造成本。但整数的乘法/除法运算却无法这样处理,这就是为什么有带符号的乘除指令而加法和减法却没有,从一定意义上讲,其实减法指令只是加法指令的一个包装,因为CPU内部没有减法逻辑,只有加法。

二进制中补码计算简单详实的讲解

首先说明一点这篇博文是基于网络资料 写作而来,尊重知识,广泛传播;可能你就需要它。但是转载请注明出处本博文参考链接 参考资料 参考资料本文说明一个基本的问题,补码的问题。负数在计算机中如何表示?举...
  • JQ_AK47
  • JQ_AK47
  • 2015年04月28日 16:39
  • 10860

二进制数的补码及运算(1)

本人研究不深,如有错误请不吝赐教!! 1.正数的补码表示 正数的补码 = 原码 负数的补码 = {原码符号位不变} + {数值位按位取反后+1}    or      = {原码符号位不变} + {数...
  • moon9999
  • moon9999
  • 2017年02月25日 22:04
  • 2207

java 二进制(原码 反码 补码),位运算,移位运算,约瑟夫问题

一.二进制,位运算,移位运算 1.二进制 对于原码, 反码, 补码而言, 需要注意以下几点: (1).Java中没有无符号数, 换言之, Java中的数都是有符号的; (2).二进制的最高位是...
  • liuhaomatou
  • liuhaomatou
  • 2014年11月24日 14:36
  • 7006

二进制补码乘法及其FPGA实现

  • 2012年01月05日 16:57
  • 393KB
  • 下载

二进制的源码补码

  • 2013年05月03日 01:18
  • 19KB
  • 下载

二进制补码乘法及其FPGA实现

  • 2009年08月14日 19:40
  • 142KB
  • 下载

-128有8位二进制表示的原码、反码和补码

一、模的概念(我只列举一个例子,具体请查数学中的 "同余模")        在日常生活中,有许多化减为加的例子。例如,时钟是逢12进位,12点也可看作0点。        当将时针从 10点 调...
  • u010561359
  • u010561359
  • 2013年05月28日 21:42
  • 895

二进制(原码、反码、补码)

二进制(原码、反码、补码)
  • dabing69221
  • dabing69221
  • 2013年12月15日 20:55
  • 4994

二进制原码,反码以及补码实战

学了好长时间,今天终于真正理解了计算机中负数的存储,终于理解了补码的运算!我们很多人在初学有关进制知识的时候,大都学得头大,特别是在关于二进制补码表示,以及补码与十进制负整数的相互转换的时候,学完之后...
  • u011763190
  • u011763190
  • 2016年04月16日 11:56
  • 863

二进制补码记数法和余码记数法

目前,计算机表示整数普遍采用的就是二进制补码记数法。它是用固定数目的二进制位来表示整数,通常是32位。...
  • qiaoer2017
  • qiaoer2017
  • 2016年12月13日 15:03
  • 1669
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:二进制补码
举报原因:
原因补充:

(最多只允许输入30个字)