二进制

二进制的存储

无论内存还是磁盘,都是以 2 进制的方式进行存储的

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

了解储存单位的转换

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
5
6
# 二进制加法

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 那咋表示负数呢?

注意:为了让数字的表示更有规律,我们用每 8 位表示一个数字,多则溢出舍弃

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 是不存在的!
-------------------
0 0 0 0 0 0 0 0

再次明确:我们使用 8 位表示一个数字,多则溢出舍弃!那么我们尝试从“多则溢出舍弃这里寻找突破口”!

1
2
3
4
5
6
7
8
9
10
11
12
要想让 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

1
2
3
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

(完)