1. 浮点数的核心概念
(1) 有效数字(Significant Digits)
有效数字是浮点数中实际能精确表示的数字位数,包括整数和小数部分的总位数。例如:
123.45 的有效数字是 5 位(1, 2, 3, 4, 5)。
0.00123 的有效数字是 3 位(1, 2, 3)。
(2) 精度与存储结构
浮点数的精度由 尾数(mantissa/fraction)位数 决定,遵循以下公式:
浮点类型二进制位数十进制有效数字总存储空间
float32
23 位尾数
~6-7 位
4 字节(32 位)
float64
52 位尾数
~15-17 位
8 字节(64 位)
2. 整数和小数部分的「共享」关系
浮点数的有效数字是 整体计算的,整数部分和小数部分的位数共享总有效位数。例如:
数值 123456.789(假设 float32,7 位有效数字):
整数部分 123456 占 6 位。
小数部分只能精确到 1 位(.7),总有效数字为 123456.7。
数值 0.0000123456789(float32):
有效数字为 1.234567,即 7 位(忽略前导零)。
关键结论
整数部分位数越多,小数部分的精度越低。
数值的绝对值越大(如 1e20),小数部分的有效位数越少。
3. 浮点数的实际限制
(1) float32(单精度)
最大整数范围:约 ±3.4×1038
小数精度:~6-7 位有效数字。
import numpy as np
a = np.float32(100000.1234567)
print(a) # 输出: 100000.12(丢失部分小数精度)
(2) float64(双精度)
最大整数范围:约 ±1.8×10308
小数精度:~15-17 位有效数字。
b = np.float64(123456789012345.123456789)
print(b) # 输出: 123456789012345.12(保留约 15 位有效数字)
浮点数的精度陷阱
(1) 无法精确表示某些十进制小数
例如,0.1 在二进制中是无限循环小数,导致存储误差:
c = np.float32(0.1)
print(c) # 输出: 0.1(实际存储值为近似值,如 0.10000000149)
(2)累加误差
多次操作后误差会累积:
sum_float32 = np.float32(0.0)
for _ in range(10):
sum_float32 += np.float32(0.1)
print(sum_float32) # 输出: 1.0000001(而非精确的 1.0)
最佳实践
优先使用 float64:
除非内存受限,否则选择双精度以保留更多有效数字。
arr = np.array([1.234567890123456789], dtype=np.float64)
避免直接比较浮点数:
使用容差方法检查相等性:
a = np.float64(0.1 + 0.2)
b = np.float64(0.3)
print(a==b) # 输出: false
高精度需求场景:
使用 decimal.Decimal(Python 内置高精度库):
from decimal import Decimal
d = Decimal('0.1') + Decimal('0.2')
print(d == Decimal('0.3')) # 输出: True
总结
整数和小数共享有效数字位数,总位数由浮点类型(float32/float64)决定。
理解浮点数的限制可以避免程序中的逻辑错误。
有效数字位数是浮点数精度的核心指标,而非独立的小数或整数位数。