浮点数是二进制的科学计数法:符号位+指数位+尾数位,指数让小数点能浮动——名字就是这么来的。
3.3 说清了误差的来源,这一节看承载它的那个结构:浮点数。
一、先认识科学计数法
小学学的科学计数法是 1.25 × 10³——把有效数字和小数点位置分开写。 这么做的好处是:同一个格式既能表示很大的数,也能表示很小的数。 浮点数换了底数,写成 1.xxxx × 2ⁿ。 于是那三个部分——正负、有效数字、小数点位置——正好对应三个字段。
二、三个字段
符号位:1 位,决定正负。 指数位:单精度 8 位、双精度 11 位,决定这个数有多大。 尾数位:单精度 23 位、双精度 52 位,决定这个数有多细。 加起来:单精度 1+8+23 = 32 位;双精度 1+11+52 = 64 位。 注意尾数位远多于指数位——说明设计时更看重【精细】而不是【极端范围】。
三、小数点为什么会【浮】
整数的小数点位置是固定的(就在最右边),所以叫定点数。 浮点数的小数点位置由指数决定——指数变,小数点就跟着挪,所以叫【浮】。 这就带来两条独立的轴:指数管范围,尾数管精度。 所以浮点数能同时表示 1e-38 和 1e38,但这两头的精度都只有那 23 位。
四、为什么有效数字只有 7 位左右
23 位尾数换成十进制,大约相当于 7 位有效数字;双精度 52 位约相当于 16 位。 所以别指望双精度算出【小数点后 20 位都正确】的结果——真值里就没有那么多位。 这条常识直接决定了很多实践:比较两个浮点数是否相等,本来就该带容差。 而【容差取多大】,就取决于你用单精度还是双精度——这是下一节要补的最后一块。
五、动手 Demo:浮点数就是二进制的科学计数法
小学学的科学计数法是 1.25 × 10³。浮点数换了底数:1.xxxx × 2ⁿ。
for name, total, s, e, m in (("float", 32, 1, 8, 23),
("double", 64, 1, 11, 52)):
print("%s: 共 %d 位 = 符号 %d + 指数 %d + 尾数 %d"
% (name, total, s, e, m))
实跑输出:
--------------------------------------------------------------------
浮点数就是二进制的科学计数法
--------------------------------------------------------------------
小学学的科学计数法是 1.25 × 10³。浮点数换了底数:**1.xxxx × 2ⁿ**。
类型 总位数 符号位 指数位 尾数位 十进制有效位
---------------------------------------------------------------------------
单精度 float 32 1 8 23 约 7 位
双精度 double 64 1 11 52 约 16 位
三个字段各管一件事:
符号位 0 还是 1,决定正负
指数位 小数点落在哪儿,决定这个数有多大
尾数位 有效数字本身,决定这个数有多细
**指数让小数点【浮动】——这就是【浮点数】这个名字的来历。**
也正因为小数点浮着,同一个 32 位既能表示 1e-38 也能表示 1e38,
代价是**有效数字只有那 23 位,超出的部分一律舍弃**。
符号位管正负、指数位管大小、尾数位管精细——三段各司其职。 指数让小数点浮动,这就是【浮点数】这个名字的来历。
30 秒实验
- 查一下你常用语言的 float 是多少位、有效数字大约几位。
- 试试打印 0.1 + 0.2 和 1/3,观察它们各自能显示到第几位。
常见误区
- 以为浮点数只是【带小数点的数】。它是三段结构,小数点位置由指数决定。
- 以为 double 一定够用。52 位尾数约 16 位有效数字,超出的部分本来就不存在。
自测三问(点开对答案)
1. 浮点数由哪三个部分组成? —— 符号位、指数位、尾数位。 2. 单精度和双精度各占多少位? —— 单精度 1+8+23=32 位;双精度 1+11+52=64 位。 3. 指数位和尾数位各决定什么? —— 指数位决定能表示多大/多小的范围,尾数位决定有效数字的精细程度。- ☐ 下一节(3.5 规格化表示法与移码表示法)
相关笔记
- 计算机计算出错的原因 — 误差从哪儿来
- 规格化表示法与移码表示法 — 这两个字段具体怎么填
- 用程序来实际确认一下吧 — 把位拆开亲眼看
- 🔵 计算机基础 · 索引 — 硬件底层的入门课
- ⚙️ 程序是怎样跑起来的 · 索引