计算机组成原理--二进制编码


算是读书笔记吧

极客时间--深入浅出计算机组成原理


二进制编码

二进制和我们平时用的十进制,其实并没有什么本质区别,只是平时我们是“逢十进一”,这里变成了“逢二进一”而已。每一位,相比于十进制下的 0~9 这十个数字,我们只能用 0 和 1 这两个数字。

  • 二进制转十进制

从右到左的第 N 位,乘上一个 2 的 N 次方
0011 =>> 0×2³+0×2²+1×2¹+1×2⁰ = 3

  • 十进制转二进制

用2做短除法

因此13这个十进制数,对应的二进制数,就是 1101。

  • 原码表示法

一个二进制数最左侧的一位,当成是对应的正负号,比如 0 为正数,1 为负数,这样来进行标记。

0011 表示 +3、1011表示 -3

但是对于0:1000 代表 0, 0000 也代表 0。

  • 补码表示法

一个二进制数最左侧的一位,表示-1ⁿ

1011 换算成十进制为:−1×2³+0×2²+1×2¹+1×2⁰=−5

0000 表示 0,1000 在这样的情况下表示 -8。


字符编码

  • ASCII 码

ASCII 码就好比一个字典,用 8 位二进制中的 128 个不同的数,映射到 128 个不同的字符里。

比如,小写字母 a 在 ASCII 里面,就是第 97 个,也就是二进制的 0110 0001,对应的十六进制表示就是 61。而大写字母 A,就是第 65 个,也就是二进制的 0100 0001,对应的十六进制表示就是 41。

在 ASCII 码里面,0-9每一个数字都对应这一个8位编码。所以很多时候我们在存储数据的时候,要采用二进制序列化这样的方式,而不是直接用CSV 或者 JSON进行存储。

  • 字符集(Charset)

字符集,表示的可以是字符的一个集合

我们日常说的 Unicode,其实就是一个字符集,包含了 150 种语言的 14 万个不同的字符。
随着计算机的普及,越来越多的语言加入了Unicode。
现在,他用32位,4个字节表示一个字符。

  • 字符编码(Character Encoding)

类似一种传输协议,对Unicode编码后的编号进行压缩。

Unicode本身的字符集是32位的,那么每个字符都用4个字节传输,对欧美而言,一下就要用原来ASCII码时代四倍的资源传输或者保存一样的文档。于是,出现了uft-8,utf-16,utf-32这些编码方案。
把字符的代码通过这个编码方式映射成传输时的编码,在使用Unicode字符集保持通用性的同时节约流量和硬盘空间。

  • UTF-8编码

UFT-8编码可以保证最大限度的节约空间

相对于Unicode这种大家固定的UTF-8的编码称之为变长码。其大受欢迎的主要原因就是对欧美而言,在保留Unicode通用性的情况下避免了流量和空间的浪费。

用UTF-8在接收时,接到一个编码如果是合法的8位编码,就可以直接把它判定为字符,这就给了Unicode字符集在表示英语时和ASCII一样的效率。如果是不合法的,那继续读一个字节,读的两个字节16位如果是合法的,判别为一个字符,再不行继续读下去。

  • 为什么UTF-8成为主流

计算机世界绝大部分传输的都是英文以及数字,编码之后UTF-16要两倍于UTF-8的空间

  • 为什么计算机不直接使用UTF-8进行编码

UTF-8虽然更加节省空间,但是解析起来相对定长编码更加麻烦。

不从头扫描一遍,你不知道第几个字符在哪个位置上,这在处理的时候非常浪费时间。
现在很多语言/程序的处理办法,是使用源于原始UTF-16的一个定长编码,只处理字符码在16位以内的字符,不支持超过16位的罕见字。这种16位定长的编码方式被称为UCS-2。

  • 锟斤拷

锟斤拷,是一串经常在搜索引擎页面和其他网站上看到的乱码字符。乱码源于GBK字符集和Unicode字符集之间的转换问题。

 `未知字符`  ==(**Unicode**)==>  `U+FFFD`  ==(**UTF-8**)==>`\xef\xbf\xbd`
`\xef\xbf\xbd\xef\xbf\xbd`  ==(**GB2312**)==> `锟斤拷`
  • GBK

是汉字专用的字符编码方式
GBK、GB2312等与UTF8之间都必须通过Unicode编码才能相互转换:

GBK、GB2312--Unicode--UTF8
UTF8--Unicode--GBK、GB2312
  • 烫烫烫

如果你用了 Visual Studio 的调试器,默认使用 MBCS 字符集。“烫”在里面是由 0xCCCC 来表示的,而 0xCC 又恰好是未初始化的内存的赋值


定点数

一种二进制来表示十进制的编码方式

  • BCD 编码(Binary-Coded Decimal)

我们把最右边的 2 个 0~9 的整数,当成小数部分;把左边 6 个 0~9 的整数,当成整数部分。这样,我们就可以用 32 个比特,来表示从 0 到 999999.99 这样 1 亿个实数了。

它的运用非常广泛,最常用的是在超市、银行这样需要用小数记录金额的情况里。在超市里面,我们的小数最多也就到分。这样的表示方式,比较直观清楚,也满足了小数部分的计算。


浮点数

float类型

  • IEEE 的标准

它定义了两个基本的格式

  1. 用 32 比特表示单精度的浮点数,也就是我们常常说的 float 或者 float32 类型。
  2. 用 64 比特表示双精度的浮点数,也就是我们平时说的 double 或者 float64 类型。
  • 单精度float的表示

单精度的 32 个比特可以分成三部分:


  1. 符号位s
    1 个比特 -- 记做(−1)^s
  2. 有效数位f
    23 个比特 -- 记做1.f
  3. 指数位e
    8 个比特 -- 记做 2^(e)

综合科学计数法,我们的浮点数就可以表示成下面这样:


当然,有一些特殊的表示:


举个例子:


  • 计算一个浮点数

1. 整数部分
与十进制相同。除以 2,然后看余数
2. 小数部分
乘以 2,然后看看是否超过 1。如果超过 1,我们就记下 1,并把结果减去 1,进一步循环操作。
知道结果等于0

比如9.1、整数位9换算成1001

而小数位0.1:


结果是000110011…这里的“0011”会无限循环下去。所以,这也是为什么0.1无法被正确的表示为浮点数的原因。

1001后拼接上000110011… 也就是 1001.000110011…

进行位移之后为 1.001000110011… × 2^3

  • 什么样的数无法被精准的表示成浮点数

二进制能精确地表示位数有限且分母是2^n的小数

比如1/2、1/4、1/8
他们在乘2的循环中,一定有一次能使结果等于1,从而推出循环。
而且,需要在有限位数内完成循环。毕竟有效数位f只有23个比特。


参考文献

utf-8和Unicode的区别
计算机中为何不直接使用 UTF-8 编码进行存储而要使用 Unicode 再转换成 UTF-8 ?
GB2312、GBK与UTF-8的区别
百度百科--锟斤拷
# 为什么0.1+0.2不等于0.3

推荐阅读更多精彩内容