6 Python 基础数据类型:整型 (int) 与浮点型 (float) 及精度避坑指南
前言
在 Python 编程中,数字是我们最打交道的数据类型。其中,整型 (int) 和 浮点型 (float) 是最基础、最常用的两种。看似简单,但如果不了解底层原理,特别是浮点数的精度问题,很容易在计算金额或科学运算时踩进“深坑”。
整型 (int)
Python 中的整型用于表示整数(没有小数部分的数字),包括正整数、负整数和零。
1. 核心特性:无限精度
与 C/Java 等语言不同,Python 3 的 int 类型没有固定的大小限制(不再区分 int 和 long)。只要你的内存够大,Python 就能处理任意大的整数。这使得 Python 非常适合进行大数运算。
2. 基础用法与进制表示
除了十进制,Python 还支持二进制、八进制和十六进制的直接输入。
# 1. 基础赋值
a = 10
b = -5
c = 0
# 2. 大数运算(自动处理,不会溢出)
big_num = 2 ** 100
print(f"2的100次方: {big_num}")
# 输出: 1267650600228229401496703205376
# 3. 多进制表示
n_bin = 0b1010 # 二进制 (0b 开头) -> 10
n_oct = 0o12 # 八进制 (0o 开头) -> 10
n_hex = 0xA # 十六进制 (0x 开头) -> 10
print(f"二进制: {n_bin}, 八进制: {n_oct}, 十六进制: {n_hex}")浮点型 (float)
浮点型用于表示带小数点的数字,或者使用科学计数法表示的数字。
基础用法
Python 的 float 类型通常对应于 C 语言中的 double(双精度浮点数),遵循 IEEE 754 标准。
# 1. 小数形式
pi = 3.14159
negative = -0.01
# 2. 科学计数法 (e 代表 10 的幂)
large_f = 1.23e9 # 1.23 * 10^9
small_f = 1.5e-3 # 1.5 * 10^-3 (0.0015)
print(f"科学计数法: {large_f}")
print(type(pi)) # <class 'float'>高能预警:浮点数的精度问题
新手在 Python 中最容易遇到的“灵异事件”莫过于此:
print(0.1 + 0.2)
# 你以为会输出: 0.3
# 实际输出: 0.30000000000000004为什么会这样?
这不是 Python 的 bug,而是计算机底层二进制存储机制决定的。
- 十进制中,我们用 $1/10$ 表示 0.1。
- 二进制中,计算机需要用 $1/2, 1/4, 1/8...$ 来拼凑数字。
- 遗憾的是,0.1 在二进制中是一个无限循环小数 (0.0001100110011...)。
由于计算机内存(64位)是有限的,它不得不截断这个无限循环小数。截断就意味着精度的丢失。当你把两个本身就存在微小误差的数相加时,误差被放大,最终显示出来。
解决精度问题的 4 种方案
在涉及金融计算、科学实验等对精度要求极高的场景下,直接使用 float 是不安全的。以下是常见的解决方案:
方案 1:用于展示 —— format 或 round (不推荐用于计算)
如果你只是想把结果打印得好看一点,可以使用格式化字符串或 round()。
- 注意:
round()在 Python 3 中采用“银行家舍入法”(四舍六入五取偶),且round()本身仍返回 float,可能依然带有微小误差。
a = 0.1 + 0.2
# 方法 A: 字符串格式化 (推荐用于展示)
print(f"{a:.2f}") # 输出: 0.30
# 方法 B: round 函数
print(round(a, 2)) # 输出: 0.3round函数还是比较简单的,函数第二个参数表示保留几位小数。
f这个字符串格式化稍微复杂一点,它的语法结构如下:
f"{value:[width][.precision][type]}"value:要格式化的数值width:最小总宽度(可省略).precision:小数点后位数(对f类型有效)type:常用有f(固定小数)、e(科学计数)、g(自动选择)
💡 示例:{a:.2f} 表示“以固定小数形式显示,保留2位小数,不足位数会自动补0”。方案 2:用于比较 —— math.isclose
永远不要使用 == 来判断两个浮点数是否相等。应该判断它们是否“足够接近”。
import math
a = 0.1 + 0.2
b = 0.3
# 错误做法
if a == b:
print("相等")
else:
print("不相等") # 这里会被执行
# 正确做法:使用 math.isclose
# rel_tol 是相对误差,abs_tol 是绝对误差
if math.isclose(a, b, rel_tol=1e-9):
print("数学上相等") # 这里会被执行为什么rel_tol是1e-9?
rel_tol=1e-9(即 0.000000001)并不是随意选的,而是基于浮点数精度的工程经验和IEEE 754 双精度浮点数(float64)的特性得出的一个合理默认值。NumPy、SciPy 等科学计算库也常用 1e-9 或 1e-8 作为默认容差。Python 官方文档明确说明:1e-9 是“适用于大多数情况的合理默认值”。
什么时候使用abs_tol?
abs_tol 适用于你关心的数值范围非常小(接近零)的情况。比如:比较两个接近0的数。
import math
a = 1e-12
b = 0.0
# 仅用 rel_tol 会失败(因为 max(|a|,|b|) ≈ 0,rel_tol * 0 = 0)
print(math.isclose(a, b, rel_tol=1e-9)) # False ❌
# 必须使用 abs_tol
print(math.isclose(a, b, abs_tol=1e-11)) # True ✅新手也不用想那么多,以后遇到了自然再了解即可。
方案 3:金融级精确计算 —— decimal 模块 (推荐)
Python 标准库提供了 decimal.Decimal 类,用于十进制的精确运算。这是解决金额计算问题的标准答案。
关键点:创建 Decimal 对象时,必须传入字符串!
from decimal import Decimal
# 错误示范:传入 float,精度已经丢了
d_wrong = Decimal(0.1)
print(f"错误创建: {d_wrong}")
# 输出: 0.100000000000000005551115123125...
# 正确示范:传入字符串
d1 = Decimal('0.1')
d2 = Decimal('0.2')
d3 = d1 + d2
print(f"正确结果: {d3}") # 输出: 0.3
print(f"类型: {type(d3)}") # <class 'decimal.Decimal'>
# Decimal 可以方便地进行四舍五入
# 设置精度保留2位小数,ROUND_HALF_UP 是标准的四舍五入
from decimal import ROUND_HALF_UP
price = Decimal('1.125')
print(price.quantize(Decimal('0.00'), rounding=ROUND_HALF_UP)) # 1.13方案 4:分数运算 —— fractions 模块
如果你需要处理 $1/3$ 这种在十进制和二进制都是无限循环的数,可以使用分数模块。
from fractions import Fraction
f1 = Fraction(1, 3) # 1/3
f2 = Fraction(1, 6) # 1/6
result = f1 + f2
print(f"分数计算结果: {result}") # 输出: 1/2
print(float(result)) # 输出: 0.5总结
- 整型 (
int):在 Python 3 中拥有无限精度,大胆使用,不用担心溢出。 - 浮点型 (
float):基于 IEEE 754 标准,运算速度快,但存在二进制存储带来的精度误差。 避坑指南:
- 比较:永远不要用
==判断浮点数,请使用math.isclose()。 - 计算:涉及到钱或高精度需求,请务必使用
decimal模块,并且记得传字符串给 Decimal。
- 比较:永远不要用
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
暂无评论数据