6b5479e6d036

算是读书笔记吧

二进制编码

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

二进制转十进制

从右到左的第 N 位,乘上一个 2 的 N 次方

0011 =>> 0×2³+0×2²+1×2¹+1×2⁰ = 3

十进制转二进制

用2做短除法

6b5479e6d036

因此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 的标准

它定义了两个基本的格式

用 32 比特表示单精度的浮点数,也就是我们常常说的 float 或者 float32 类型。

用 64 比特表示双精度的浮点数,也就是我们平时说的 double 或者 float64 类型。

单精度float的表示

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

6b5479e6d036

符号位s

1 个比特 -- 记做(−1)^s

有效数位f

23 个比特 -- 记做1.f

指数位e

8 个比特 -- 记做 2^(e)

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

6b5479e6d036

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

6b5479e6d036

举个例子:

6b5479e6d036

计算一个浮点数

1. 整数部分

与十进制相同。除以 2,然后看余数

2. 小数部分

乘以 2,然后看看是否超过 1。如果超过 1,我们就记下 1,并把结果减去 1,进一步循环操作。

知道结果等于0

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

而小数位0.1:

6b5479e6d036

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

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

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

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

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

比如1/2、1/4、1/8

他们在乘2的循环中,一定有一次能使结果等于1,从而推出循环。

而且,需要在有限位数内完成循环。毕竟有效数位f只有23个比特。

参考文献

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐