文章目录
计算机存储那些事儿
总所周知,计算机中的存储都是使用二进制。目前的计算机系统对于实数的存储主要是两个方面,一个分类整型,另一类主要是浮点型。在认识计算机系统的整型存储之前,回忆一下,原码、反码、补码的转换过程。
1.原码、反码、补码的计算
1.1 原码
- 将一个整数转换成二进制数,就是其原码。
例如:
18
---->0001 0010
1.2 反码
- 正数:反码=原码
- 负数:原码中除符号位外,按位取反。
例如:
18
---->0001 0010
-18
–1>1110 1101
1.3 补码
- 正数:补码=原码
- 负数:反码加1
例如:
18
---->0001 0010
-18
–1>1110 1110
2. 计算机中整数的存储
计算机中整数的存储主要是用补码的方式存储。
🔔疑问:为什么一定要使用补码的方式。
本节内容,主要分类两个部分:1.无符号数 2.有符号数,并且所有示例都以8位二进制(1个字节)来列举,8位二进制数能表示2的8次方(256)个数
2.1 无符号整数的存储
_ _ _ _ | _ _ _ _
以左示的1个字节来表示有无符号数,能表示从0000 0000,
到1111 1111
的数。
因为是无符号数,所以既是正数,在计算机存储中使用补码,和原码一致。
0000 0000 ------ 0
0000 0001 ------ 1
0000 0002 ------ 2
…
…
…
1111 1110 ----- 253
1111 1110 ------ 254
1111 1111 ------ 255
即在_ _ _ _ | _ _ _ _
这样的8位进制中,会出现256种组合,对应了从0到255的数
2.2 有符号整数的存储
- 有符号数会将第一位作为符号位,1位负 0位正
- 最大值
0111 1111
------127 - 从
0000 0000
到01111 1111
代表十进制的 0到127,共128个数,前文提到 8位二进制数 能表示 256个数,意味着还有128个数没表示,剩下的128个就是-128 到 -1
,这128个负数就是用补码表示。
在引入下一节之前,看看原码中如何使用8位二进制表示负数:
1000 0000
---- (-0) 到1111 1111
------ (-127)
⚠️这里也就发现了,如果使用原码,并不能表示到-128,同时还会出现两个零,0000 0000 (+0)
1000 0000 ( -0)
2.2.3 为什么用使用补码来表示负数?
- 计算机体系中只有加法器,利用加法器做减法运算。形如
a - b = a + ( - b )
,利用加法器做减法运算,主要利用了补码的本质特性。
补码的本质是一个代替负数的正数,那么🔔补码是如何代替一个负数,使得加法器能做减法运算呢?
答:
- 首先,认识一下另一种补码的计算方式(区别于前文的反码加1),
m^n + 负数
--------m代表:进制数(二进制就是2,十进制就是10),n代表:位数。
例如:用8位二进制的补码表示-18 = 2^8 + (-18) = 256 - 18 = 237 -------(将237转换为无符号位的二进制)-------》1110 1101
- 其次,以
2位数的10进制
为例,展示补码如何代替一个负数,并利用加法器做减法运算❗️❗️❗️
👉10进制中的减法运算:30 - 10 = 20
👉-10的补码:10^2 + (-10) = 90
👉利用加法来计算:30 + 90 =1
20
🔑前文已经说明2位数的十进制
,所以丢弃百位的1
,即1
20—>20,以此利用加法与补码,得到了减法的结果。- 最后,以
8位的二进制演示
。
👉 30的二进制补码(原码):0001 1110
👉 - 10 的补码:1111 0110
🔑 计算过程:0001 1110 + 1111 0110 ---------------- 1 0001 0100
丢弃最高位,即·
1 0001 0100
改变成0001 0100
= 20
⚠️扩展:由此可以看出,计算机其实解析二进制数据一直都是以无符号的方式(正数),只不过负数的存储用了其补码,而负数的补码其实就是正数。除此之外,用丢弃超限的最高位方法,巧用加法器,实现了减法操作,从而使计算机体系中,可以区分正负数。
- 使用补码表示负数,可以避免使用原码表示负数中出现
+0 -0 两个零的清空
,确保了零值的唯一性。 - 由上确定了一个0值,多出来的一个,就可以当作-128。
🎁-128的补码:2^8 + (-128) = 1000 0000,既使用 原码中的
-0
来表示了-128
3. 计算机中浮点数的存储
计算机中浮点数的存储主要是依据了IEEE754标准,来对计算机中浮点数的存储进行约定。
3.1 IEEE754标准
IEEE754 主要是采用了科学计数法的方式来对计算机中的浮点数进行存储。
首先简单介绍下如何使用科学计数法来表示二进制数,对于一个二进制数N
,可以使用N = S × 2^P
来表示,其中S称为尾数,P称为阶码。
📢📢📢📢📢📢注意事项📢📢📢📢📢📢📢
- P和S 都要使用二进制来表示。
- S是N所有的有效数字位
其中上述的内容,其实也就是十进制中标准规则,与其不同的是十进制变成了二进制。
IEEE754标准中将浮点数的表示分为了三个部分:
1️⃣符号位:0为正,1为符
2️⃣有偏指数位:表示指数,可以使用此有偏指数计算出上文中的P
3️⃣小数位:表示浮点数中的小数部分
浮点数常见的类型主要是单精度与双精度,单精度占32位,双精度占64位。
📢单精度浮点数(32位):
1️⃣符号位:占1位
2️⃣指数位:占8位
3️⃣小数位:占23位
📢单精度浮点数(64位):
1️⃣符号位:占1位
2️⃣指数位:占11位
3️⃣小数位:占52位
⚠️注意事项⚠️:指数位(图中绿色区域)以无符号的原码解析表示,前文2.2.3节中的扩展也提到了计算机其实解析二进制数据一直都是以无符号的方式(正数)。
那么一个浮点数是如何用上图所示方式来存储浮点数呢?或者说如何把上图所示的储存内容转换成浮点数呢?
主要是以下公式为例(储存内容转换成浮点数的公式):
(-1)^sign × 1.fraction × 2^(exponent - 127)
⚠️:由上,所以符号位为0 即是正,相反为1既负。
⚠️:1.fraction 既是尾数。
为什么尾数是1.fraction,而不是0.fraction呢?
答:IEEE754的标准规定,小数点的左边只能且必须有一个1。
为什么如此规定?
答:节约内存,小数点左边如果是0开始的话,本事就没多大意义,但是如果是默认从1开始,可以节约存放1
的内存空间。
⚠️:(exponent - 127)既是阶码,原本机器中储存的是有偏指数 需要 减去 127,此处127也称为移码
以单精度为例,展示如何将机器中的存储内容转换为浮点数。
假设:计算机中一块地址中 存储有一单精度浮点数0 -0111 1111-01000000000000000000000
,以-
隔开3部分方便举例。
公式计算:(-1)^0 × 1.01000000000000000000000 × 2^(0111 1111 - 0111 1111)
ℹ️这里将 127写成了二进制
=1 × 1.01000000000000000000000 × 2^(124 - 127)
ℹ️这里又将解码部分写回了十进制
=1.01000000000000000000000 × 2^(-3)
ℹ️意味着将尾数的小数点左移3位!
=0.00101
ℹ️转换为十进制即为 0.15625
同样以单精度与0.15625为例,示例如何将浮点数转换为IEEE754下的存储内容
0.15625------转换为二进制----------> 0.00101-------转换为科学计数表示法,使小数点左边有一个1---------->1.01 × 2^(-3)
由上,为正,符号位为0,小数位为01并补0直到有23位,指数位:-3 + 127(移码)。
3.2 为什么需要使用127的移码?
以单精度浮点数为例,指数位有八位,既指数可表示的范围为0~255。
指数全为正数,即科学计数表示法中,原数据 = 尾数中小数都是往右移的结果
,不能往左移。
如何表示负数?
❓使得移码,表示负数。❓
(0~255) - 127 = (-127 ~ 128)
由此,以这种移码的方式可以使得指数表示到负数,所以 指数需要加上偏移量才能在计算机中存储。
3.3 如果指数范围确定后,那原本二进制的范围是多少呢?
⚠️上节说到,以减去127移码的方式,实现了指数可以负数,但是指数的范围确实-126~127
⚠️
IEEE754中有明确的标准,小数点左边必须有一位1。所以尾数一定是1.fraction
那么单精度上能表示的最小正数既是
当fracion为00000000000000000000001
------》1.00000000000000000000001 × 2^(-126)
---------转换为二进制的IEEE754存储标准--------》0 00000001 00000000000000000000001
同理最大整数 也可以推到出来。
3.4 指数范围中剩下的 -127 和128 去哪里了?
前面看到指数范围去掉了-127与128,而-127与128有些特殊用途。
3.4.1 规格数与非规格数(规约数与非规约数)
IEEE754规定,按照尾数位隐藏的整数部分是 1. 还是0. 可以将浮点数划分为两类: normal number(规格数) 和 subnormal number(非规格数)
所以上述讲解中,中都是规格数。
1.fraction------》规格数
0.fraction------》非规格数
- 非规格数:如果指数位全是0,则这个数就是非规格数。例如,
0 00000000 ******************
,那么其尾数就是 0.fraction。
0(1) 00000000 0000****0000
—》表示正负0
0(1) 00000000 不全为0
-------》表示十分接近0的浮点数
- 特殊数:如果指数位全是1,即这个数可能是无穷大或者NaN。
0(1) 11111111 0000****0000
—》 表示正负无穷大
0(1) 11111111 不全为0
—》 表示NaN