首先,让我们回顾一下epsilon
的返回值到底是什么sys.float_info
。
Epsilon (or ) 是满足0.5 + ≠ 0.5 AND 0.5 - ≠ 0.5
的最小数
Python 告诉您,将导致0.5
重复递增或递减的最小数字是epsilon=2.220446049250313e-16
-但这仅适用于值 0.5。您正试图1.0
增加1.0e-17
. 这是一个较大的值(1.0 对 0.5),其增量小于 0.5 的值(1.0e-17 对 2.2e-16)。由于 1.0e-17 的增量值比 1.0 的相对 epsilon 小一个数量级,因此您大致偏离了一个数量级。
你可以在这里看到这个:
这些改变了0.5
>>> 0.5+sys.float_info.epsilon
0.5000000000000002
>>> 0.5-sys.float_info.epsilon
0.4999999999999998
这些值不会:
>>> 0.5+sys.float_info.epsilon/10.0
0.5
>>> 0.5-sys.float_info.epsilon/10.0
0.5
>>> 5.0+sys.float_info.epsilon
5.0
>>> 5.0-sys.float_info.epsilon
5.0
解释:
IEEE 754定义了当今大多数标准计算机上使用的浮点格式(专业计算机或库可能使用不同的格式。) IEEE 754 的64 位格式使用 53 位精度来计算和 52 位存储到浮点数的尾数点值。由于您有一个固定的 52/53 位可以使用,尾数的大小和精度会随着更大/更小的值而变化。那么随着浮点数的相对大小的变化而变化。0.5 的值不同于 1.0 和 100.0 的值。
由于各种非常好的和特定于平台的原因(存储和表示、舍入等),即使您可以使用较小的数字,epsilon 也被定义为对 64 位浮点格式使用 52 位精度。由于大多数 Python 实现使用 C 双浮点数来表示浮点数,因此可以证明这一点:
>>> 2**-52==sys.float_info.epsilon
True
查看您的平台将执行多少位:
>>> 0.5 + 2.0**-53
0.5000000000000001
>>> 0.5 - 2.0**-53
0.4999999999999999
>>> 0.5 + 2.0**-54
0.5 # fail for 0.5 + 54 bits...
>>> 0.5 - 2.0**-54
0.49999999999999994 # OK for minus
>>> 0.5 - 2.0**-55
0.5 # fail for 0.5 minus 55 bits...
您的问题有几种解决方法:
- 您可以使用nextafter的C99 概念来计算适当的epsilon 值。对于 Python,使用 numpy 或 Decimal 类来计算
nextafter
. 更多关于nextafter
我之前的回答这里
- 使用整数。64 位整数将清楚地处理 17 数量级的 epsilon 值,无需四舍五入。
- 使用任意精度数学库。十进制在标准 Python 发行版中。
重要的概念是 的值是相对于值的(如果你是递增或递减)。
这可以在这里看到:
>>> numpy.nextafter(0.0,1.0)-0.0
4.9406564584124654e-324 # a relative epsilon value of 4.94e-324
>>> numpy.nextafter(0.01,1.0)-0.01
1.7347234759768071e-18 # 1e-17 would still work...
>>> numpy.nextafter(0.1,1.0)-0.1
1.3877787807814457e-17 # 1e-17 would >>barely<< work...
>>> numpy.nextafter(0.5,1.0)-0.5
1.1102230246251565e-16 # a relative epsilon value of 1.1e-16
>>> numpy.nextafter(500.0,501.0)-500.0
5.6843418860808015e-14 # relative epsilon of 5.6e-14
>>> numpy.nextafter(1e17,1e18)-1e17
16.0 # the other end of the spectrum...
因此,您可以看到 1e-17 可以轻松地增加 0.0 和 0.1 之间的值,但不会有比这更多的值。如上所示,1e17 的相对值是 16。