转载自整数二进制补码的数学原理(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内部没有减法逻辑,只有加法。



整数二进制补码的数学原理(two's complement)相关推荐

  1. 二进制补码计算原理详解

    二进制的负数在计算机中采用补码的方式表示.很多人很好奇为什么使用补码,直接使用原码表示多好,看上去更加直观和易于计算.然而事实告诉我们,这种直观只是我们人类的一厢情愿罢了,在计算机看来,补码才是它们最 ...

  2. 十进制转二进制 / 八进制 / 十六进制的手算方法,及其数学原理的通俗解释

    前言:接触计算机的同学学习基础课程时,不免会碰到十进制转二进制 / 八进制 / 十六进制这种问题.常见的方法有"除以2/8/16看余数".本文在介绍方法的前提上,对其数学原理进行了 ...

  3. 计组(COA) Programming1: 整数和二进制补码、整数和NBCD码、浮点数(float)和二进制码(IEEE 754)的相互转换。

    1.整数转化为二进制补码. public String intToBinary(String numStr) {//判断符号boolean isNeg = numStr.charAt(0) == '- ...

  4. 三进制计算机_计算机数学原理之二进制

    上一节我们了解了曲线的矩形逼近,以及由此代表的模拟量的数位表示.基于以上知识, 这节课我们可以开始学习二进制了. 计算机原理之 二进制 对数值的数位表示,我们可以很自然的想起十进制.即所有的数字都用1 ...

  5. 约瑟夫问题与魔术(五)——魔术《自我匹配的奇迹》中的数学原理

    特别通知:2020马丁加德纳聚会已于本周开始在线上举行,MatheMagician也将在10.18周日晚8点带来题为<数学魔术的魅力>讲座,详情请点击: 2020中国纪念马丁·加德纳聚会线 ...

  6. 2---MATLAB将十进制转换成二进制补码

    MATLAB中提供了一个将十进制转换为二进制的函数dec2bin,但是该函数只接收非负整数,也就是不能直接将负数转换为二进制补码.那如何在MATLAB中生成补码呢?我们都知道负数的补码为其反码加1,然 ...

  7. 进制转换小技巧之让你重新认识二进制补码(大师,我悟了)!!!

    前言 我们都知道计算机内部是使用二进制来进行运算的,那么你对于二进制转换为其它进制或者其它进制数转换为二进制数是否熟练于心呢? 与我们现实中的十进制不同,计算机内部使用二进制表示(一般我们书写用十六进 ...

  8. RSA加密算法的数学原理

    文章目录 RSA数学原理 获取两个不相等的质数pq 把p和q相乘,得到n 计算出小于n的自然数中,有多少数与n互质(欧拉函数) 在1和φ(n)之间,选取一个随机质数e 求e和φ(n)的模反元素d(裴蜀 ...

  9. 计蒜客T1182 输出二进制补码(python3.6)

    题目描述 题目链接:https://nanti.jisuanke.com/t/T1182 蒜头君有一个 int 的整数,输出它的 32 位二进制补码. 输入格式 一个整型整数. 输出格式 输出一行,即 ...

最新文章

  1. Xcode 创建.a和framework静态库(转)
  2. AttributeError: module librosa has no attribute output No module named numba.decorators错误解决
  3. [ 浙江大学 程序设计专题 ] 四个专题代码 报告 PPT共享
  4. Istio究竟是干嘛的?
  5. 蓝桥杯-逆序对(java)
  6. java 分句_JAVA按文字,标点符号和引号分割句子
  7. leetcode 95. Unique Binary Search Trees II | 96. Unique Binary Search Trees
  8. 理想的互联网服务后台框架的九个要点
  9. 什么是医疗健康管理系统?
  10. 七本前端(javascript、css)最著名工具书免费下载
  11. 被小伙伴要出来的文章[0]:英语学习
  12. 2ex ey-or 攻防世界
  13. idea中surround with快捷键
  14. linux top VIRT RES SHR SWAP DATA内存参数详解
  15. Delphi 串口通信技术资料
  16. freeRTOS学习(三)
  17. Django Vue 跨域问题
  18. 地图绘制和四色算法,图搜索算法,最小生成树算法,最短路径算法
  19. 微信小程序跳转京东小程序优惠券领取界面
  20. 正则表达式(记忆口诀)

热门文章

  1. 深聊性能测试,从入门到放弃之: Windows系统性能监控(二) 资源监控器介绍及使用。
  2. class 人开枪射击子弹
  3. Vue 爬坑之旅 -- 微信网页授权
  4. 【Echarts】通过柱状图实例,一文让你学会Echarts的基础使用!!!
  5. 【金猿投融展】美创科技——聚焦数据安全 释放数据价值
  6. 最优化原理与方法 BFGS算法及PRP算法
  7. 基于Python实现的手机基站信息经济分析系统 课程报告+源码及数据
  8. 产品经理须知:机会成本和沉没成本
  9. LeetCode#6 ZigZag Conversion
  10. 【小月电子】ALTERA FPGA开发板系统学习教程-LESSON11 IPCORE之PLL详细教程