二进制的存储

无论内部存储器还是外部存储器,都是以 2 进制的方式进行存储的

就如同一张巨大的 excel 表格,每个格子中都可以存放一个 1 或一个 0

一大堆 0 和 1 怎么读呀 ?

不妨思考一下:一大堆 0 和 1,你咋知道几个 0 和 1 才表示一个数字 ?显然,如果事先规定好每 x 个 0 和 1 表示一个数字,那不就行了。

所以:我们不妨让每 8 位表示一个数字,多则溢出舍弃

存储单位的转换

1
2
3
4
5
6
7
8
9
10
11
1 bit				# 1 位

1 Byte = 8 bit # 1 字节

1 KB = 1024 Byte

1 MB = 1024 KB

1 GB = 1024 MB

...

2 进制加法

10 进制 2 进制 8 进制 16 进制
101 21 81 161
0123456789 01 01234567 0123456789abcdef
1
2
3
4
   1 0 0 1 0 0 1 1
1 0 1 0 1 0 0 1
-------------------
1 0 0 1 1 1 1 0 0

思考:计算机只能保存 01 那咋表示负数呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
借用数学中 “用已知来研究未知” 的思想

现实生活中:

数字前添加 + 表示正数,+ 可省略不写

数字前添加 - 表示负数

比葫芦画瓢,既然我们用每 8 位表示一个数字,那么我们可不可以用第 1 位来表示正负号呢 ?比如:

0 代表正数

1 代表负数

按照我们的想法,数字 -1 就被表示成了

1 0 0 0 0 0 0 1

验证一下我们的想法,比如计算一下 1 + (-1)

0 0 0 0 0 0 0 1
+ 1 0 0 0 0 0 0 1
------------------
1 0 0 0 0 0 1 0 => -2

验证失败,故 => `在计算机中,负数不能直接表示成其二进制的方式`

重来!我们期望 00000001 + (-1的二进制表示) => 00000000,不妨设 -1 的二进制表示为 x

0 0 0 0 0 0 0 1
+ x => 显然这里的 x 是不存在的 !思考怎样才能让这个 x 存在 ?
-------------------
0 0 0 0 0 0 0 0

既然:我们使用 8 位表示一个数字,多则溢出舍弃

那么我们不妨从“多则溢出舍弃”这里寻找突破口 !

1
2
3
4
5
6
7
8
9
10
11
要想让 x 存在,那么我们只能思考:能否给被加数或结果添加溢出位,以达到让 x 存在的目的

显然如果给被加数添加溢出位,那么 x 仍然不存在

而如果给结果添加一个溢出位 1,即将结果写成 100000000,x 就存在了!

0 0 0 0 0 0 0 1
+ 1 1 1 1 1 1 1 1 <=> x
-------------------
(1) 0 0 0 0 0 0 0 0

故:-1 在计算机中就用 11111111 来表示(即直观上用 -127 表示了 -1)

为了庆祝负数在计算机中有了合理的表示形式,诞生了以下三个名词,以 -1 为例

原码:10000001

反码(符号位不动,其余位取反):11111110

补码(反码加一):11111111

ok,到此为止问题解决,结论:计算机中,负数以补码的形式来存储

意外的收获:我们顺带解决了 -0 和 +0 在计算机存储中的表示方式不一样的问题

0 => 00000000

-0 ==原=> 10000000 ==反=> 11111111 ==补=> 100000000(1溢出)=> 00000000

注意:

在原码反码补码的问题上,一般不讨论正数,因为这三个概念本身就只是问了让负数在计算机中有合理的表示而诞生的

非要说的话,那正数的原反补都是该正数的二进制

习题

1
cout << (unsigned int)(-1)

先不管无符号这一回事,有符号的 -1 是以补码存储的

原:10000000 00000000 00000000 00000001
反:11111111 11111111 11111111 11111110
补:11111111 11111111 11111111 11111111

所谓无符号,就是将符号位变为数据位

所以输出结果就是

11111111 11111111 11111111 11111111

即:2^32 - 1


补充知识

背景:在计算机中,数据都是以二进制的形式存储的

:对于有符号数,请写出 1000 0000 的十进制表示形式

分析

有符号 => 若 1 是符号位 => 则说明这是一个负数 => 计算该负数的原码:1000 0000 => 0111 1111 => 0000 0000 => 得出 0,这与该数是个负数相矛盾 => 说明 1 是数据位 => 说明符号位溢出了 => 若符号位是 0,即:0 1000 0000 => 128 => 与最大值 2^7-1,即 127 相矛盾 => 说明符号位是 1,即:1 1000 0000 => 计算该负数的原码:1 1000 0000 => 1 0111 1111 => 1 1000 0000 => -128,恰好是最小值 -2^7

其实,仅从 1000 0000 第一位是 1,我们就可以立即下结论这肯定是个负数,尽管这个 1 有可能是数据位

补充知识

背景:

十进制的科学计数法表示,eg:十进制的 1.5 => 1 * 10^0 + 5 * 10^(-1)

二进制的科学计数法表示,eg:二进制的 1.1 => 1 * 2^0 + 1 * 2^(-1) => 这也就转成了十进制 !!!

二进制的科学计数法表示,eg:二进制的 11.111 => 1 * 2^1 + 1 * 2^0 + 1 * 2^(-1) + 1 * 2^(-2) + 1 * 2^(-3) => 这也就转成了十进制 !!!

分析:

不难发现:有的十进制数是无法用二进制精确表示的

比如十进制的 0.1 就无法用二进制精确表示,1/16 + 1/32 + 1/256 + … 约等于 0.1,你只能无限趋近 0.1 但永远也到不了 0.1

结论:

因此,在以二进制的形式存储数据的计算机中,浮点数存在误差

(完)