二进制补码: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. 基于物理的渲染——间接光照

    在前面的文章中我们已经给出了基于物理的渲染方程: 并介绍了直接光照的实现.然而在自然界中,一个物体不会单独存在,光源会照射到其他的物体上,反射的光会有一部分反射到物体上.为了模拟这种环境光照的形式,我 ...

  2. 全平台Markdown笔记软件——Notable

    简介 The markdown-based note-taking app that doesn't suck. 一款简介.跨平台的本地笔记软件,github地址:https://github.com ...

  3. 从游戏到汽车 “明星IP”的发财轨迹

    "明星IP"的发财轨迹" title="从游戏到汽车 "明星IP"的发财轨迹"> 移动互联网时代的开启,不仅彻底重构了大众生 ...

  4. JavaScript中prompt的使用

    */ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.js * 作者:常轩 * 微信公众号:Worldhel ...

  5. jq拖拽插件

    (function ($) { var move = false; //标记控件是否处于被拖动状态 var dragOffsetX = 0; //控件左边界和鼠标X轴的差 var dragOffset ...

  6. property 属性

    #propery 属性"""内置装饰器函数,只在面向对象中使用."""#计算圆的面积,圆的周长 from math import pi cl ...

  7. mac 使用命令行向 github 提交代码

    让 mac 本地和自己的 github 网站建立连接(ssh) 下载安装 git 网址: https://git-scm.com/downloads 查看安装是否成功: git -version $ ...

  8. node跨域方法

    第一种:jsonp 参看用nodejs实现json和jsonp服务 第二种:res.wirteHeadnode部分 var http = require('http') var url = requi ...

  9. ubuntu16.04设置开机自启服务

    网上说了开机自启有许多种方法: 1.最简单的是:在/etc/rc.local的exit 0前面加上你启动服务的脚本文件路径 注:这个脚本文件应写绝对路径! 2.网上:修改rc.local开头的#/bi ...

  10. Jessica's Reading Problem POJ - 3320

    Jessica's Reading Problem Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 17562   Accep ...