从 01 开始 从 01 开始
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档

晓林

程序猿,自由职业者,博主,英语爱好者,健身达人
首页
  • 📚 计算机基础

    • 计算机简史
    • 数字电路
    • 计算机组成原理
    • 操作系统
    • Linux
    • 计算机网络
    • 数据库
    • 编程工具
    • 装机
  • 🎨 前端

    • Node
  • JavaSE
  • Java 高级
  • JavaEE

    • 构建、依赖管理
    • Ant
    • Maven
    • 日志框架
    • Junit
    • JDBC
    • XML-JSON
  • JavaWeb

    • 服务器软件
    • 环境管理和配置管理-科普篇
    • Servlet
  • Spring

    • Spring基础
  • 主流框架

    • Redis
    • Mybatis
    • Lucene
    • Elasticsearch
    • RabbitMQ
    • MyCat
    • Lombok
  • SpringMVC

    • SpringMVC 基础
  • SpringBoot

    • SpringBoot 基础
  • Windows 使用技巧
  • 手机相关技巧
  • 最全面的输入法教程
  • 最全面的浏览器教程
  • Office
  • 图片类工具
  • 效率类工具
  • 最全面的 RSS 教程
  • 码字工具
  • 各大平台
  • 校招
  • 五险一金
  • 职场规划
  • 关于离职
  • 杂谈
  • 自媒体
  • 📖 读书

    • 读书工具
    • 走进科学
  • 🌍 英语

    • 从零开始学英语
    • 英语兔的相关视频
    • Larry 想做技术大佬的相关视频
  • 🏛️ 政治

    • 反腐
    • GFW
    • 404 内容
    • 审查与自我审查
    • 互联网
    • 战争
    • 读书笔记
  • 💰 经济

    • 关于税
    • 理财
  • 💪 健身

    • 睡眠
    • 皮肤
    • 口腔健康
    • 学会呼吸
    • 健身日志
  • 🏠 其他

    • 驾驶技能
    • 租房与买房
    • 厨艺
  • 电影

    • 电影推荐
  • 电视剧
  • 漫画

    • 漫画软件
    • 漫画推荐
  • 游戏

    • Steam
    • 三国杀
    • 求生之路
  • 小说
  • 关于本站
  • 关于博主
  • 打赏
  • 网站动态
  • 友人帐
  • 从零开始搭建博客
  • 搭建邮件服务器
  • 本站分享
  • 🌈 生活

    • 2022
    • 2023
    • 2024
    • 2025
  • 📇 文章索引

    • 文章分类
    • 文章归档
  • 计算机简史

  • 数字电路

    • 数字与进制
    • 编码与原码、补码、反码
      • 什么是信息
      • 原码
      • 补码
      • 反码
      • 小结
      • 原码、反码、补码对照表
      • 补码与十进制转换
      • 一些术语
  • 计算机组成原理

  • 操作系统

  • Linux

  • 计算机网络

  • 数据库

  • 编程工具

  • 装机

  • 计算机基础
  • 数字电路
2022-12-08
目录

编码与原码、补码、反码

# 30.编码与原码、补码、反码

介绍下计算机常用的编码方式

‍

# 什么是信息

在讲什么是编码之前,先讲一下什么是信息。不同的学科对信息这个单词的解读都不一样。我们这里可以简单的理解为信息就是知识的传递,它描述了一种状态或者一个事实。

那么我们如何传递信息呢?这就需要用到编码。

比如我有这样一个信息:今天是 2020 年 1 月 1 号。我可以用文字的形式将其表示出来,也可以用语音的形式向其表示出来,还可以用手语或者用盲文将其表示出来。在这里文字是一种编码的形式,语音也是一种编码方式。手语和盲文也是一种编码的形式。数字的发明,应该是人类最早的编码文明。

我们这里下一个定义。码制就是表示事物的规则。这里的码制就是指文字,语音,手语和盲文。

将阿拉伯数字表示成其他进制中的数,也是一种编码方式。但我们要注意,即使是在其他进制中,数字也是可以做加减乘除四则运算的,也是可以进位的。

# 原码

我们如果要表示一个数的二进制数方式,我们可以直接写出它的二进制数,但如何表示一个负的二进制数呢?在我们日常使用十进制数进行运算时,我们是用一个负号“-”,放到数字前面表示这是一个负数。

当然我们手工计算二进制时,这样做也是可以的。

而在计算机中,我们并没有表示负号的机制。计算机只能处理 0 或者 1。

那我们可不可以在二进制数之前加一位数,例如 0 表示正数,1 表示负数?当然是可以的。我们称这样的编码方式为原码。

例如 +5 可以这样表示 0 0101​, -5 可以这样表示 1 0101​

但如果我们直接用原码去做二进制计算,是不可以的。例如上述的两个数相加,结果应该是 0,但如果我们这样表示二进制数,和我们想要的结果不符合:

 0 0101
 1 0101
 1 1010 
1
2
3

​1 1010​ 表示的是-9!为什么呢?因为我们这里用 0 表示负数,1 表示正数,这其实是一种编码方式,不是一种数学中进位的方式,我们这里将码制跟数制混合起来了,这是一种混合的编码方式。

最高位的 1​ 代表的是这个数是正还是负,而不是表示数字。也就是这样混合编码的话,四则运算就失效了。

所以如果我们要用原码计算,必须先比较出两数的绝对值,然后相减,得到差值。这个方法很麻烦,用电路实现的话还需要用到比较电路和减法电路。

我们知道,二进制的加法是很简单的,无非就是:

  • 0 + 0 = 0
  • 0 + 1 = 1
  • 1 + 1 = 10

即使是多位二进制数,进位也只需要一位一位往前进就行。 ‍ 而如果一旦涉及到减法,就要考虑借位了。而用电路实现借位,是非常麻烦的。我们先来做一道十进制的减法题:

  2 5 3
- 1 7 6
=   7 7
1
2
3

要做这道题,从最右边一列开始。首先,6 比 3 大,所以需要从 5 借 1,这样就变成了 13 减 6,结果是 7。

由于从 5 借了 1,5 就变成了 4,4 比 7 小,所以继续从 2 借 1,14 减 7 等于 7。

2 被借 1 后成为 1,1 减 1 为 0,所以最后结果是 77。

幸运的是,早于十六世纪,法国数学家布莱士·帕斯卡(Blaise Pascal 1623-1662)早已想到办法,通过某种方式,可以将减法变为加法,这样,只需要加法电路,我们就可以完成加减法了!该方法就是补码,计算机中沿用至今。

# 补码

‍ 模、补数:在日常生活当中,可以看到很多这样的事情:

  • 把某物体左转 90 度,和右转 270 度,在不考虑圈数的条件下,最终的效果是相同的;
  • 把分针倒拨 20 分钟,和正拨 40 分钟,在不考虑时针的条件下,效果也是相同的;
  • 把数字 87,减去 25,和加上 75,在不考虑百位数的条件下,效果也是相同的;
  • ……

上述几组数字,有这样的关系:

  • 90 + 270 = 360
  • 20 + 40 = 60
  • 25 + 75 = 100

式中的 360、60 和 100,就是“模”。式中的 90 和 270、20 和 40,以及 25 和 75,就是一对对“互补”的数字。

知道了“模”,求某个数字的“补数”,就是轻而易举的了:如果模为 365,数字 120 的补数为:365 - 120 = 245。

用补数代替原数,可把减法转变为加法。出现的进位就是模,此时的进位,就应该忽略不计。 ‍ 有了补码,我们怎么计算呢?举例,有个小孩,只能认识 100 个数。超过 100,就从 0 开始数。他很小,只会加法,还不会做减法。可以这样教他:减一,就用加上 99 代替。因为:

  • 28 -1 = 27, 减去 1,等于加上 1 的补数, [1] 补 = 模(100) - 1 = 99

  • 28 + 99 = (1)27 ‍ 同样,减二,可以用加上 98 代替;

  • -3,可以用 +97 代替;

  • -4,可以用 +96 代替;

  • …… 以此类推 ‍ 在 100 个数字的范围内:

1、99,是一对互补的数字。

2、98,也是。

用互补的数,代替原数,即可把减法,转换成加法。注意,要忽略进位。 ‍ 有补码的好处:用了补码,就不用借位了。这句话是重点,重点,重点。例如:

28 -1 = 28 - (100 - 99) = 28 + 99 - 100,这样,28 和 99 相加,是不用借位的; ‍ 但我们求 -1 的补码,100 - 99,还是要借位,怎么办呢?我们可以转换成这样:

28 - 1 = 28 -(99 -99 +1) = 28 +99 -99 -1 = 28 + 99 - (99 + 1)= 28 + 99 -100。

我们再举一个例子,求 - 66 的补码:

[66]补 = 模 - 66 = 100 - 66 = 99 + 1 -66 = 99 -66 +1

其中,99 - 66 也是不用借位的。

以上是求补码的原理,也是二进制求补码的原理。 ‍ 现在,我们回到二进制。在八位二进制数字的范围内,共有 256 个数字。0000 0000~1111 1111,即 0~255。

  • 1、255,是一对互补的数字。
  • 2、254,也是。
  • ……以此类推;

那么,-1,就可以用 +255 代替。-2,也就可以用 +254 代替。即:

[-1] 补 =255。

[-2] 补 =254。

计算时,加上正数,是不需要求取补数的;只有进行减法(或者加上负数),才需要对减数求补数。 ‍ 由此,我们引申出补码的定义:

  • 正数不变;

  • 负数即用模减去绝对值。 ‍ 那么,已知一个数 N ,其 8 位字长的补码定义为:

  • [N]补 = X ……………0 <= N <= +127,正数和 0 的补码,就是该数字本身

  • [N]补 = 28-|N|…… -28 <= X < 0,负数的补码,就是用模,减去该数字的绝对值

计算机的书上,一般,都有这个定义式。 ‍ 我们引申下补码的通用定义:对于有效数字(不包含符号位)为 n 位的二进制数 N,它的补码 (N) comp 表示如下:

  • (N) comp= N (当 N 为正数)
  • (N) comp= 2n-N…… (当 N 为负数)

但是,求补码的过程中,还是有涉及到借位,怎么办呢?我们可以这样:例如有效位数为 8,求 (-26) 10的二进制补码,我们可以先求出其二进制原码为: 0001 1010

然后,就是用 28 - 0001 1010:

1 0000 0000
- 0001 1010
1
2

‍ 为了不借位,我们可以将 28 变成 2 -1 + 1。 因为 28 = 2 -1 + 1

其中,2 -1 = (1111 1111)2 ‍ 那么,28 - 0001 1010 可以变成这样子:

  1111 1111 
+         1
- 0001 1010
1
2
3

‍ 我们调换下顺序:

  1111 1111 
- 0001 1010
+         1
1
2
3

‍ 因为在一个二进制数中,只有 0 和 1,1 是最大的, 1 减去 1, 1 减去 0,都不用借位。而且,我们观察到,1-1=0, 1-0 = 1

从结果来看,我们把被减数的每一个结果取反(1取反得0,0取反得1),就能得到结果,我们还要必要做减法吗?

(1111 1111) - (0001 1010) 的结果,和我们直接取反(0001 1010) 的结果,是一样的。然后我们再加上 1,不就得到补码了吗? ‍ 练习:-10 的原码:1000 1010 -10 的补码:1111 0110 符号位是 1 ‍

# 反码

由此我们引申出的定义:二进制数 N 的反码 (N)inv 的定义:

  • (N)inv = N 当 N 为正数
  • (N) inv= 2n - 1 - N 当 N 为负数

2n - 1 是 n 位全为 1 的二进制数,所以求负数的补码的时候,只要将负数的每一位 1 改为 0, 0 改为 1,也就是取反,就可以得到反码了。后续我们会看到,在电路上,实现取反一个二进制数是很容易的(至少比实现借位方便)。 ‍

# 小结

我们求补码的话,一般是采用取反加一的办法,希望你能理解它的原理,而不是死记硬背。

# 原码、反码、补码对照表

这里以 4 位二进制数为例 (8 位的太多了)

十进制数 二进制原码(带符号数) 二进制反码 二进制补码
+7 0111 0111 0111
+6 0110 0110 0110
+5 0101 0101 0101
+4 0100 0100 0100
+3 0011 0011 0011
+2 0010 0010 0010
+1 0001 0001 0001
+0 0000 0000 0000
-1 1001 1110 1111
-2 1010 1101 1110
-3 1011 1100 1101
-4 1100 1011 1100
-5 1101 1010 1011
-6 1110 1001 1010
-7 1111 1000 1001
-8 1000 1111 1000

‍

# 补码与十进制转换

如何通过负数的二进制补码求十进制数? 可以看成 第一位是 -127 的权重,在清华大学的课程这样说道:

image.png​

大家看最高位,在以前的编码的时候,我们是不是把它当成了一个符号位?所谓符号位是不是认为它不带大小,对吗?

但是如果当你进行补码编码的时候,我们可以当它是一个带符号的,同时也是带大小的这么一个权值,一个负的权值。

例如我们求 (1001)2 的补码,表示的十进制数是多少,两种方法:

  • 减一后取反。 1001 - 1 = 1000 ,取反后就是 0111 ,也就是 -7 的补码
  • 我们可以理解为,第一位二进制数是带符号的, 后续的每一位二进制数都是不带符号的,那么 (1001)2 就可以理解为是 1×(-23) + 0 × 22 + 0×21 + 1×20 = - 8 + 1 = -7 ‍ 数字 0 ~+127,直接就是补码。

数字 -128 ~ -1,是用 128~255 当作补码。

# 一些术语

最后说一些英文术语:

补码:Complement,英语里又叫 two's complement(对 2 求补)

反码:Inverse code

有些教材会称反码为 1 的补码, 1's Complement

上次更新: 2025/5/5 17:15:09
数字与进制
概述-计算机组成原理(北大-陆俊林)

← 数字与进制 概述-计算机组成原理(北大-陆俊林)→

最近更新
01
学点统计学:轻松识破一本正经的胡说八道
06-05
02
2025 年 5 月记
05-31
03
《贫穷的本质》很棒,但可能不适合你
05-27
更多文章>
Theme by Vdoing | Copyright © 2022-2025 | 粤 ICP 备 2022067627 号 -1 | 粤公网安备 44011302003646 号 | 点击查看十年之约
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式