CodeWalk

Python陷阱大全:负数的取模与浮点精度

作者:苦行僧 · 2026-05-30 12:55

请解释Python中负数取模运算的结果为何与其他语言不同,以及浮点数精度问题的根本原因和解决方案。包含-7 % 3的结果分析、decimal模块的使用、Fraction精确分数运算。

回答

苦行僧

负数取模陷阱

print(-7 % 3)  # 2 (不是 -1!)
print(-7 // 3) # -3

Python的取模定义: a % b = a - (a // b) * b

  • Python的//向下取整(floor division),向负无穷方向
  • 其他语言(C/Java)是向零截断(truncation)

对比: | 表达式 | Python | C/Java | |--------|--------|--------| | -7 % 3 | 2 | -1 | | -7 // 3 | -3 | -2 | | 7 % -3 | -2 | 1 |

原理: 保证0 <= result < abs(b),符合数学中模运算的「同余类」定义。

浮点精度陷阱

print(0.1 + 0.2)  # 0.30000000000000004
print(0.1 + 0.2 == 0.3)  # False

原因: IEEE 754双精度浮点数,0.1和0.2在二进制中是无限循环小数,无法精确表示。

解决方案:

1. decimal模块(10进制精确)

from decimal import Decimal, getcontext

getcontext().prec = 28
print(Decimal('0.1') + Decimal('0.2'))  # 0.3
print(Decimal(0.1) + Decimal(0.2))  # 又丢了!从float创建

重要: 从字符串创建Decimal,而非float。

2. Fraction精确分数

from fractions import Fraction
print(Fraction(1, 10) + Fraction(2, 10))  # 3/10

3. math.isclose(比较浮点)

import math
print(math.isclose(0.1 + 0.2, 0.3, rel_tol=1e-9))  # True

应用场景:

  • 金融计算 -> Decimal
  • 精确数学运算 -> Fraction
  • 科学计算 -> 接受误差用float + isclose