二进制
二进制的存储
无论内部存储器还是外部存储器,都是以 2 进制的方式进行存储的
就如同一张巨大的 excel 表格,每个格子中都可以存放一个
1
或一个0
一大堆 0 和 1 怎么读呀 ?
不妨思考一下:一大堆 0 和 1,你咋知道几个 0 和 1 才表示一个数字 ?显然,如果事先规定好每 x 个 0 和 1 表示一个数字,那不就行了。
所以:我们不妨让每 8
位表示一个数字,多则溢出舍弃
!
存储单位的转换
1 | 1 bit # 1 位 |
2 进制加法
10 进制 | 2 进制 | 8 进制 | 16 进制 |
---|---|---|---|
逢 10 进 1 |
逢 2 进 1 |
逢 8 进 1 |
逢 16 进 1 |
0123456789 | 01 | 01234567 | 0123456789abcdef |
1 | 1 0 0 1 0 0 1 1 |
思考:计算机只能保存 0
和 1
那咋表示负数呢?
1 | 借用数学中 “用已知来研究未知” 的思想 |
既然:我们使用 8 位表示一个数字,多则溢出舍弃
那么我们不妨从“多则溢出舍弃”这里寻找突破口 !
1 | 要想让 x 存在,那么我们只能思考:能否给被加数或结果添加溢出位,以达到让 x 存在的目的 |
故:-1 在计算机中就用 11111111 来表示(即直观上用 -127 表示了 -1)
为了庆祝负数在计算机中有了合理的表示形式,诞生了以下三个名词,以 -1 为例
原码:10000001
反码(符号位不动,其余位取反):11111110
补码(反码加一):11111111
ok,到此为止问题解决,结论:计算机中,负数以补码的形式来存储
意外的收获:我们顺带解决了 -0 和 +0 在计算机存储中的表示方式不一样的问题
0 => 00000000
-0 ==原=> 10000000 ==反=> 11111111 ==补=>
1
00000000(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
补充知识
背景:
十进制的科学计数法表示,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
结论:
因此,在以二进制的形式存储数据的计算机中,浮点数存在误差
(完)