美文网首页计算机科学与技术教与学
CSI讲义2-- 关于二进制补码的若干注记

CSI讲义2-- 关于二进制补码的若干注记

作者: Bintou老师 | 来源:发表于2017-06-28 22:39 被阅读136次

计算机科学关注的是计算而不是计算机。--by Richard Hamming

二进制

二进制补码是在《计算机科学概论》中讲授的基本概念,本注记试图讲述:什么是补码,为什么需要补码,补码的运算规则,而最重要的是试图说明,补码规则为什么是如此定义的。从而引申出一个也许不大准确的结论:计算机科学理论是源于实践又反作用与实践的理论,至少从理论上看是如此。

为什么需要补码

定义补码是为了满足计算机表示负整数(也称带符号整数)的需要。基本常识告诉我们,计算机用二进制来表示数字,即只用0/1两个数字表示数字,如果要表示负数应该怎么办呢?

补码的规则

补码的规则是非常简单的,要表示某正数的负数,只需要对该二进制数取反然后加1 。比如:

0011表示十进制的正整数3,那么-3的补码表示就是:
1. 0011 取反得 1100
2. 1100 + 1 = 1101 。

为方便起见,所有例子如无特殊说明都使用4比特二进制数来表示。

基本上,大部分的同学学到这里也就停止了,规则定下来,我们遵守就是了。只有少数同学或者老师会继续提问,为什么补码的定义是取反加1(而不是其他规则),为什么要这样定义,这样定义的依据是什么?以下我试图解释这个问题。

为了证实表示负数用补码的定义是正确的选择,我们可以从反面出发,看看几种不正确的但显然是非常直观的定义。

直接在正整数之前加符号(所谓原码)

这种想法最最直观直接了。大家看,要表示带符号数,我们必然需要使用一个比特来代表所谓的符号,就选0代表整数,1代表负数,因此,如果表示-3,那只需在+3前面加负号即可,也就是说3是0011,那么-3就是1011 。这样不就很好了吗?

首先注意,4比特二进制在无符号的时候,表示的范围是0~15,即0000~1111 。在表示带符号整数时,因为抽出了一为作为符号位,那么表达的范围就应该是:

0000 ~ 0111 (0~7) : 正数
1000 ~ 1111 (-0~-7) :负数

一个立即需要解决的问题就是0与-0从含义(定义)上怎么区别?而更为重要的是,符号的出现还直接影响了算术运算规则的定义。比如,原本我们很容易定义加法来做正整数运算,比如:

0011+0001= 0100( 3 + 1 = 4),

但是这个加法对带符号数就立即失效了,比如:

0011+1001=1100=(3 - 1= -4),这是错误答案

小结一下,在定义带符号数的时候我们有两个问题需要解决:0与-0该如何区分、定义或者解决,其次,使得无符号的加法在带符号的加法保持相容。

对正整数取反(所谓反码)

这种想法也非常直观。负数与正数不是刚刚相反吗,那么给定一个正二进制数,只需把每一位都取反不就刚好对应一个负数么?比如:

0011(3)的反就是1100(-3)。

此时,四比特的带符号二进制数的范围就是:0000~0111 (0~7,与上一个例子相同) 以及 1000~1111 (-7~-0,注意,与上一个例子相比,但顺序颠倒) 。

我们需要问,刚才的问题解决了没有?稍微分析一下,我们失望地发现局面似乎并无改观。还有一个-0(1111),而且加法也不与正数加法兼容,比如:

0011 + 1100 = 1111 ( 3 + (-3)= -0,本应该是0的。)

再仔细看看,0与-0的区别在哪里?我们稍微乐观点就可以意识到,0000与1111的差距只是差一个1 ?不是吗,1111+1=0000 !于是,补码定义呼之欲出了。

对正整数取反之后再加1 (所谓补码)

重新强调一下:

补码运算规则:最高位比特为符号位,正数为0,负数为1。对某正数求其负数,只需要对该数取反加1。

现在剩下的工作只需要重新考察,在这种运算规则下,刚才两个问题解决了没有?首先,还是看数字的表示范围:

正数:0000 ~ 0111表示 0 ~ 7
负数:1000 ~ 1111表示的是:-8 ~ -1

细心的同学就会立即发现问题说,哎,且慢,怎么多了一个-8出来?不着急,大家只需要对0000~0111这8个数逐个用补码规则求反就会发现,我们得不到1000这个数字,也就是说1000肯定不是-1~-7之间的数。而且运用一般二进制整数的加法来算,-1 (1111)加 -7 (1001) = 1000,那么1000不就刚好是-8么?多了-8出来,刚好-0就没有了。好消息之一!剩下就是继续检查,这种补码运算是否跟原定义的加法相容了。具体例子大家稍微动动笔就知道了。

为什么补码的规则是“取反加1”

其实补码的定义并不神秘,甚至可以说没有任何新东西。本质上,计算机中的算术运算都是mod运算。考虑mod 2^n的加法,比如下面等式:

给定n比特长的正整数x,满足x + x' = 0x'就是x的负数。
x + x' = 0本质上是x + x' = 0 mod 2^n
所以:x' = (2^n - x) mod 2^n
考虑到x<2^n,只需要记为: x' = 2^n - x

例子:

计算8比特数-7的二进制补码(注意,此时是mod 256的加法):
即:2^8 - 7 == 249
验证:00000111取反加1 == 11111001

“取反加1”如何体现?很简单:

2^n = ( 2^n - 1)  + 1 = 1111..11 (n个1) + 1, 
   2^n - x = 1111...11(n个1) + 1 - x ,
   因为,x < 2^n ,所以 1111...11(n个1)  - x 就是对x取反!(Why?请稍微检验一下。)

所以,2^n - x 就是“取反加1”!

换而言之,如果从mod运算的角度去看补码,简直是太简单而且顺理成章了。从这个意义上看,mod运算对计算机的“计算”就显得尤为重要了。

CSAPP中的一种表示法

CSAPP展示了另一种表示法,如图所示:

二进制补码的一种表示法

补充此内容是想说,嗯,其实我说得更清楚。

小结

补码是一个基本概念。在我们讲解这些基本概念的时候,大家往往顾着定义,然后声讨这些所谓的“理论”,声讨老师只教理论,不讲实践,痛心疾首自己学计算机学了好多好多年还不懂什么......

讲完刚才这个例子,我只想问,补码是理论还是一种工程实践?如果它确实是理论(我也相信它是一种理论),如果没有丰富的实践基础可以得出来吗?这个理论难道不是扎根于实践而要深深地影响了实践吗?计算机科学就是这样一种源于实践而要影响实践的学科,而我没有见过不源于实践的理论,也没有见过不应用于实践的理论。

2017年6月29整理修改

相关文章

  • CSI讲义2-- 关于二进制补码的若干注记

    计算机科学关注的是计算而不是计算机。--by Richard Hamming 二进制补码是在《计算机科学概论》中讲...

  • 二进制、八进制、十进制、十六进制转换

    1.负数的二进制使用补码 负数的二进制是采用补码计算的,比如: 1的二进制为:0000 0001 它(正数)的反码...

  • 计算机原码、反码、补码详解

    注:之前查找了关于原码、反码、补码的相关资料,张子秋的博客:原码, 反码, 补码 详解讲的比较透彻。为了方便,现将...

  • 二进制补码

    13 负数同样以二进制码存储,但使用的格式是二进制补码。计算一个数值的二进制补码,需要经过下列3个步骤:(1) 求...

  • 数值是以补码表示的

    正数的补码与原补码相同 负数的补码:将该数的绝对值的二进制数按位取反后再加1 例如:求-10的补码 10的原码: ...

  • 二进制原码、反码、补码运算及标志位

    一、二进制原码、反码、补码的转换 原码: 正整数的原码:这个数的二进制,符号位为0;正整数的原码=补码=反码 例1...

  • 基本数据类型

    一 、内置数据类型 byte 8位、有符号的,以二进制补码表示的整数short 16 位、有符号的以二进制补码表示...

  • 负数在内存中的表示方式

    在计算机中数值是以二进制补码形式存在的。 正数的补码不变 负数的补码为 原码 ->取反 -> 加一以 -112...

  • 2020-04-14

    针对461 汉明距离,一看到,就应该想到位运算,而它的基础是二进制,以及反码,补码,及其运算 对于python 注...

  • 十进制,二进制,以及相互转换

    二进制 计算机以二进制补码的形式保存所有的整数 正数的原码、反码、补码都相同 原码:最高位符号位,正数为0,负数为...

网友评论

    本文标题:CSI讲义2-- 关于二进制补码的若干注记

    本文链接:https://www.haomeiwen.com/subject/rlepcxtx.html