5.4.3 比较
涉及浮点值的比较很容易出错,每一步计算都可能由于数值表示而引入误差。isclose()函数使用一种稳定的算法来尽可能减少这些误差,同时完成相对和绝对比较。所用的公式等价于:
abs(a-b) <= max(rel_tol * max(abs(a)mabs(b)),abs_tol)
默认地,isclose()会完成相对比较,容差被设置为1e-09,这表示两个值之差必须小于或等于1e-09乘以a和b中较大的绝对值。向isclose()传入关键字参数rel_tol可以改变这个容差。在这个例子中,值之间的差距必须在10%以内。
import math
INPUTS = [
(1000,900,0.1),
(100,90,0.1),
(10,9,0.1),
(1,0.9,0.1),
(0.1,0.09,0.1),
]
print('{:^8}{:^8}{:^8}{:^8}{:^8}{:^8}'.format(
'a','b','rel_tol','abs(a-b)','tolerance','close'
))
print('{:-^8} {:-^8} {:-^8} {:-^8} {:-^8} {:-^8}'.format(
'-','-','-','-','-','-'),)
fmt = '{:8.2f}{:8.2f}{:8.2f}{:8.2f}{:8.2f}{!s:>8}'
for a,b,rel_tol in INPUTS:
close = math.isclose(a,b,rel_tol=rel_tol)
tolerance = rel_tol * max(abs(a),abs(b))
abs_diff = abs(a - b)
print(fmt.format(a,b,rel_tol,abs_diff,tolerance,close))
0.1和0.09之间的比较失败,因为误差表示0.1。
运行结果:
要使用一个固定或“绝对”容差,可以传入abs_tol而不是rel_tol。
import math
INPUTS = [
(1.0,1.0 + 1e-07,1e-08),
(1.0,1.0 + 1e-08,1e-08),
(1.0,1.0 + 1e-09,1e-08),
]
print('{:^8} {:^11} {:^8} {:^10} {:^8}'.format(
'a','b','abs_tol','abs(a-b)','close'
))
print('{:-^8} {:-^11} {:-^8} {:-^10} {:-^8}'.format(
'-','-','-','-','-'
),)
for a,b,abs_tol in INPUTS:
close = math.isclose(a,b,abs_tol=abs_tol)
abs_diff = abs(a - b)
print('{:8.2f}{:11}{:8}{:0.9f}{!s:>8}'.format(
a,b,abs_tol,abs_diff,close))
对于绝对容差,输入值之差必须小于给定的容差。
运行结果:
nan和inf是特殊情况。
import math
print('nan,nan:',math.isclose(math.nan,math.nan))
print('nan,1.0:',math.isclose(math.nan,1.0))
print('inf,inf:',math.isclose(math.inf,math.inf))
print('inf,1.0:',math.isclose(math.inf,1.0))
nan不接近任何值,包括它自身。inf只接近它自身。
运行结果: