二进制补码: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. Python---7函数(调用&定义函数)

    函数 Python内置了很多有用的函数,我们可以直接调用. 要调用一个函数,需要知道函数的名称和参数,比如求绝对值的函数abs(),只有一个参数.可以直接从Python的官方网站查看文档: http: ...

  2. 恭祝2018元旦快乐!转发享福利(⊙o⊙)…

    来源:中国工信出版集团-电子工业出版社赠送给作者的原书. 为感谢2017年你的不离不弃,在2018新年之际来一发,转发朋友圈集齐20个赞,即参与活动, 活动规则: 1   转发朋友圈+集齐20个赞?, ...

  3. PHP的ArrayAccess接口介绍

    在 PHP5 中多了一系列新接口.在 HaoHappy 翻译的你可以了解到他们的应用.同时这些接口和一些实现的 Class 被归为 Standard PHP Library(SPL).在 PHP5 中 ...

  4. 用java实现的微信公众号爬虫

    Published: 2016-11-23 In Spider. tags: Spider 版权声明:本文为博主原创文章,未经博主允许不得转载. 思路: 直接从chuansong.me爬取,由于微信公 ...

  5. 【Network telemetry】谈谈网络遥感技术,从主动探测与被动探测再到Netflow与INT

    [前言] [本篇为原创]网络遥感,Network telemetry,为什么叫“telemetry”呢?我个人的理解是将网络中的数据进行一种“采集”,也就是实际上是一种网络数据的采集手段.由于工作需要 ...

  6. Web中间件常见漏洞总结

    一.IIS中间组件: 1.PUT漏洞 2.短文件名猜解 3.远程代码执行 4.解析漏洞 二.Apache中间组件: 1.解析漏洞 2.目录遍历 三.Nginx中间组件: 1.文件解析 2.目录遍历 3 ...

  7. Ansible-基本概述

    为什么要自动化运维 纯手动软件安装部署方式 我们以 10 台机器部署 Nginx 为例.部署步骤如下: 1.通过 ssh 登录一台机器: 2.yum install -y nginx 或者 获取安装包 ...

  8. ThreadLocal源码探究 (JDK 1.8)

    ThreadLocal类之前有了解过,看过一些文章,自以为对其理解得比较清楚了.偶然刷到了一道关于ThreadLocal内存泄漏的面试题,居然完全不知道是怎么回事,痛定思痛,发现了解问题的本质还是需要 ...

  9. fsLayuiPlugin数据字典使用

    概述 数据字典主要解决下拉框数据填充和数据表格转义处理,一个数据字典可以多处使用. 1.多个页面下拉框使用同样的数据,改一个地方需要把所有页面都要修改 2.数据表格转义代替自己手动写templet解析 ...

  10. C#爬取微博文字、图片、视频(不使用Cookie)

    前两天在网上偶然看到一个大佬OmegaXYZ写的文章,Python爬取微博文字与图片(不使用Cookie) 于是就心血来潮,顺手撸一个C#版本的. 其实原理也很简单,现在网上大多数版本都需要Cooki ...