二进制补码:Why & How

学习计算机原理或者语言的底层操作难免会遇到用二进制补码表示负数的问题。由于一些书本上对于采用补码的原因没有详细解释,很多人会认为这只是一种规定,但实际上采用补码是因为这种表示方法拥有实际的优势。而对于求补码的方法“按位取反再加一”,给出解释的资料就更少,本文试图给出二进制补码的优势和求法的简单解释。


Why

首先回答为什么要使用补码的问题。补码是一种计算机中负数的表示方法,当然,计算机中可以表示负数的方法不止补码一种,但目前几乎只有补码这种方法得到了广泛运用。数字的表示方法影响到数字在计算机中的存储和运算,下面对比三种可行的负数表示法来说明补码在这两方面的优势。

  • 带符号的原码

    最容易想到的负数表示方法就是将一个二进制位用来表示数的符号,例如规定数字的最高位是0时为正数,是1时为负数,把这一最高位加在负数绝对值的二进制表示(也即原码)的前面。这种方法非常直观易懂,例如310可以被表示为00112而-310可以表示为10112。我们平时在进行整数运算时可以把符号当作减号,但计算机执行简单的加法时并不会这样处理,以-310+310为例,计算机将00112+10112相加后得到11102=610从而产生了完全错误的结果。当然通过额外的电路或者程序可以让计算机像我们一样处理负号,但这会增加电路成本或影响性能。

  • 偏置数制

    为了解决运算负数在计算机中的运算问题,可以让存储的二进制值表示它的值减去某个数得到的数字。例如,对于三位二进制数,规定计算机存储的二进制数a实际上表示的是a-4对应的数字。这样0002不再表示010而是-410,而1002才表示010。这样的三位二进制数可以表示[-4, 3]范围内的所有整数,而由于并不存在需要额外处理的符号位,直接对偏置数制表示的二进制数进行加法得到的结果总是正确的。这种表示法的问题在于,要想得到存储的二进制数原来表示的数字,总要将其再加上某个数值——虽然稍显麻烦,但这已经比带符号原码在每次运算时都要处理符号要进了一大步。

  • 补码

    补码是一种兼具上面两种表示法特点和优势的数制。补码同样使用二进制数的最高位来表示符号,并规定最高位为1时表示负数。不同于带符号的原码的是,当表示负数时,补码采用偏置数制。例如,表示-410时,首先将-410+810得到偏置数1002,然后在前面加上符号位1得到11002,即是-4的四位二进制补码;正数的表示方法则与带符号的原码完全相同。注意这里所说的偏置数制与上述的略有不同,这里的二进制表示和实际数值差8而不是4,这是因为我们想利用低三位表示[-8,-1]范围的数。补码的正数和负数加法都很好理解,因为正数加正数或负数加负数并不涉及符号位的变化。而对于正数加负数,补码也能得到正确的结果,以-210+310为例,11102+00112=00012,注意到最高位因为来自低位的进位而由1变成了(1)0,最高位产生的进位溢出而被忽略,这样的溢出不会造成运算结果出错所以无需顾虑。补码表示法下的负数加上正数时,若正数大于等于负数的绝对值,将产生一个向最高位的进位而改变符号,从而保证了结果的正确性。你也许要为偏置数制争辩,尽管补码可以让正数容易得到,但负数却还是需要额外的运算。下面将展示这种计算可以是相对简单的。

How

至于如何从负数的原码得到补码,几乎所有的教科书都给出了“绝对值按位取反再加一”这一捷径,但关于其中道理能阐明的却很少。对最高位取反很容易理解,因为绝对值为正,需要变换符号才能表示负数,我们着重讨论低位的情况。以4位二进制补码为例,除最高位外的低3位实际上表示该负数a比-8大了多少(例如-210的补码11002的低三位1002=610表示-2比-8大6),也即:

a+8=a-(-8)

换句话说,这是求该负数的绝对值比8小了多少:

a-(-8)=8-(-a)=8-|a|

不过我们更希望能用710去减掉a的绝对值,因为710是01112,而01112去减掉任意一个[110, 710]内的数(也即[00012, 01112]内的数)的差正好是被减数的按位取反(对于每一位,1-0=1;1-1=0)。但记住,我们要求的值是与8的差,如果用7去减就要再加一补回来:

8-|a|=7-|a|+1

这就是按位取反再加一的原理,尽管我们是用4位二进制补码来演示的,对于更高位数也很容易想象到推广的情形。 值得一提的是,虽然上面的分析是从方便我们计算的角度考虑的,但实际上“按位取反再加一”是为了方便计算机计算而产生的技巧(取反和加一都是很容易实现的操作),也同时是补码相对于其他两种表示法的优越性所在。

二进制补码:Why & How的更多相关文章

  1. 利用ZYNQ SOC快速打开算法验证通路(1)——MATLAB浮点数与定点二进制补码互转

    最近本人一直在学习ZYNQ SOC的使用,目的是应对科研需要,做出通用的算法验证平台.大概思想是:ZYNQ PS端负责与MATLAB等上位机数据分析与可视化软件交互:既可传输数据,也能通过上位机配置更 ...

  2. java基础 二进制补码

    二进制补码: 1.计算机系统的内部以二进制形式存储数据. 2.在Java程序中输入的十进制的数据都会被自动转换为二进制,Java内部也以二进制来进行数值运算,但返回的结果是十进制. 二进制补码的原理: ...

  3. 二进制补码除法——计算机底层整数除法模拟之Java实现

    前面讲到布思算法的计算机底层模拟的时候,我们是借助于一个可以储存.表示任意N位的二进制补码的BinaryQueue实现的,现在我们模拟计算机底层整数除法还是要借助于它: BinaryQueue类代码: ...

  4. Day05_C操作符及二进制补码计算

    回顾:  1.数据类型  2.二进制(八进制,十六进制) --------------------------------------------------------- 计算机中不可以使用负号表示 ...

  5. 任意N位二进制的补码实现——队列存放

    正在学习计算机组织与结构,为了写一些底层的算术操作模拟,比如一个二进制补码数的加减乘除,发现这很麻烦,因为不管是什么语言,都只提供了8位.32.64位等部分位数的补码形式,那么怎么实现任意任意位的补码 ...

  6. int abs(int number)函数有感: 求补码和通过补码求对应的整数 C++(增加:数字的二进制表示中1的个数)

    #include "limits.h" #include "math.h" int abs(int number) { int const mask = num ...

  7. 二进制原码、反码、补码以及Java中的<< 和 >> 和 >>> 详细分析

    1.计算机二进制系统中最小单位bit 在计算机二进制系统中: bit (位) :数据存储的最小单元. 简记为b,也称为比特(bit),每个二进制数字0或1就是一个位(bit),其中,每 8bit = ...

  8. 一道int与二进制加减题

    int dis_data = 32769; if( dis_data > 0x7fff)  dis_data -= 0xffff; printf("%d\n",dis_dat ...

  9. WindowsPhone-GameBoy模拟器开发六--[转]指令系统实现必读:补码

    网上有同行写了些好文章,在此就不现丑了,贴上连接,放在这里为了补充系列的完整性 计算机为什么选用二进制补码 为什么补码重要?因为计算机中内存.寄存器里面存的数都是用补码表示的!

随机推荐

  1. 根据现有的数据库自动生成Django model

    Django引入外部数据库还是比较方便的,首先在setting里面设置你要连接的数据库类型和连接名称,地址之类,和创建新项目的时候一致 运行下面代码可以自动生成models模型文件 python ma ...

  2. Java學習筆記(基本語法)

    本文件是以學習筆記的概念為基礎,用於自我的複習紀錄,不過也開放各位的概念指證.畢竟學習過程中難免會出現觀念錯誤的問題.也感謝各位的觀念指證. 安裝JDK 在Oracle網站中找自己系統的JDK下載位置 ...

  3. 有关PHP的可变函数

    事情的起因是这样子的,最近看到一道题,问的是 <?php $_POST['a']($_POST['b']);?> 这句代码有什么问题,答案很明显因为PHP的可变函数这个特性,导致了任意代码 ...

  4. Golang: chan定义问题(7)

    通常都是定义读写双向的 chan,定义单向 chan 问题. 专栏的介绍可以参考 <GotchaGolang专栏>,代码可以看<宝库-Gotcha>. 通过 只写 chan 传 ...

  5. Python爬虫-百度模拟登录(一)

    千呼万唤屎出来呀,百度模拟登录终于要呈现在大家眼前了,最近比较忙,晚上又得早点休息,这篇文章写了好几天才完成.这个成功以后,我打算试试百度网盘的其他接口实现.看看能不能把服务器文件上传到网盘,好歹也有 ...

  6. C#面向对象--属性

    一.属性(Property)作为类和结构的成员,是对字段的一种封装方式,实际上是一种特殊的方法,被称为访问器(Accessor),从而隐藏实现和验证代码,有助于提高字段读取和赋值的安全性和灵活性: 1 ...

  7. vijos 1011 清帝之惑之顺治

    背景 顺治帝福临,是清朝入关后的第一位皇帝.他是皇太极的第九子,生于崇德三年(1638)崇德八年八月二ten+six日在沈阳即位,改元顺治,在位18年.卒于顺治十八年(1661),终24岁. 顺治即位 ...

  8. Unity C# Scoket Thread

    关于 Scoket和Thread 也没什么要说的,网上有很多资料.但是需要注意的是 Scoket和Thread 都需要创建和杀死.不然一定会造成程序假死.好了上代码 服务器: using System ...

  9. 测试后的iview的表格

    <template>   <GPage bg>     <div>       <div class="table">        ...

  10. iOS围绕某点缩放或旋转的AnchorPoint的设定

    经常会遇到需求,要求手势的缩放或者旋转操作,要求动作变化围绕某一个特定点,或者是两指的中心点,或者是某一个点. 这个问题首先要清晰的知道,iOS各个view的层次关系.特别是,要清除的知道,当前vie ...