计算机处理数字的两大阵营:整数类型(精确、按位宽分档、范围封顶)与浮点数(IEEE 754 近似、范围极大、但 0.1 + 0.2 不等于 0.3)——数学上的【实数】进了计算机就再没有【精确】二字。
3-1 讲了数字的进制写法,这一篇讲数字在内存里的【户口分类】。回收 C++ 课 2.4.1 数值类型(int/double 的分档)与数据库课 4-2(钱用 DECIMAL 那条铁律的根源就在这里)。
一、整数类型:精确但范围封顶
整数类型按【占几个字节、有没有符号】分档,范围是 2 的幂:
| 类型 | 字节 | 范围 |
|---|---|---|
| int8 | 1 | -128 ~ 127 |
| int16 | 2 | 约 ±3.2 万 |
| int32 | 4 | 约 ±21.4 亿 |
| int64 | 8 | 约 ±922 京(9.2x10^18) |
| uint8(无符号) | 1 | 0 ~ 255 |
规律:n 个二进制位能表达 2 的 n 次方个不同值;有符号拿一位存正负,无符号全部用来表示大小。C/C++/Java 都严格按这套分档;Python 的 int 不限大小(2 的 63 次方随便写,内存够就能涨)——这是少数派。
二、浮点数:范围极大但不精确
小数在计算机里用 IEEE 754 标准的浮点格式存:类似科学计数法(符号 x 尾数 x 2 的指数次方)。float64 用 8 字节,能表达 10 的正负 300 多次方——但有效数字只有约 15~16 位十进制,超过的位被【舍入】。
于是出现了本章最著名的一幕:
print(0.1 + 0.2) # 0.30000000000000004
print(0.1 + 0.2 == 0.3) # False
为什么:0.1 和 0.2 在二进制里是无限循环小数(类似十进制的 1/3),存进 64 位必然被截断,两个【近似值】相加,误差就露出来了。这不是 bug,是格式的天花板。
三、结论:三条使用纪律
- 钱一律不用浮点——数据库课 4-2 说【钱用 DECIMAL】,根源就是浮点误差;编程里对应【用整数存最小单位(分)】或十进制库;
- 浮点比较用误差范围——写
abs(a - b) < 1e-9,不写a == b; - 循环计数、下标、数量用整数——精确、快、不截断。
四、动手 Demo:误差现身与正确比较
print(0.1 + 0.2) # 0.30000000000000004
print(0.1 + 0.2 == 0.3) # False
print(abs(0.1 + 0.2 - 0.3) < 1e-9) # True
print(2 ** 100) # Python 整数不封顶:1267650600228229401496703205376
看到什么算成功:0.30000000000000004、False、True、1267650600228229401496703205376。
读结果:第三行用【差的绝对值小于亿分之一】代替【相等】——工程上处理浮点比较的标准姿势;第四行是 Python 整数不封顶的现场(同样的 2 的 100 次方,int64 早就溢出了,见 3-12)。
五、30 秒实验
跑 10 / 3 和 10 // 3——3.3333333333333335 与 3。看真除结果的最后一位:是 5 不是 3——浮点连【看起来能整除的表达式】都在悄悄舍入。
六、常见误区
- 【浮点数就是【能存小数的整数】】——错。它是完全不同的编码(科学计数法式),牺牲精确换范围;整数 21 亿和 float64 表示 21 亿,内部形态毫无相似。
- 【0.1 + 0.2 的结果是 Python 的 bug】——错。IEEE 754 是全行业标准,C/Java/JS 的
0.1 + 0.2一模一样(JS 那张著名截图就是它)。 - 【数字大就用 float】——错。要精确的大整数(如密码学、ID 号)用整数类型或大整数;float 大了照样丢精度——它是【范围大】不是【精确大】。
自测三问(点开对答案)
1. **为什么 0.1 + 0.2 不等于 0.3?** 答:0.1 与 0.2 在二进制下是无限循环小数,IEEE 754 只能存近似值,两个近似值相加误差显形——格式使然,全语言一致。 2. **int32 最大是多少、怎么来的?** 答:2 的 31 次方减 1 = 2147483647;32 位里拿 1 位存符号,剩 31 位表示大小。 3. **程序里比较两个浮点数的正确写法?** 答:`abs(a - b) < 容差`(如 1e-9)——判断【足够接近】而不是【严格相等】。- ☐ 下一节(3-8 数组、静态数组、动态数组、多维数组)
相关笔记
- 十进制数、二进制数、十六进制数 —— 数字表示法的上一课
- 类型转换与溢出 —— 整数范围封顶的后果
- C++ 2.4.1 · 数值类型 —— int/float 分档的语法细节
- 数据库 4-1 · 数据类型 —— 钱用 DECIMAL 的根源
- ⌨️ 编程原理 · 索引 —— 全课路线图