Python的epsilon值正确吗?
根据维基百科的说法:
机器精度(Machine epsilon)被定义为:当这个最小的数字加到1上时,结果会和1不同。
在Python中,可以通过sys.float_info.epsilon
来找到这个精度值,它的值相当于2的-52次方。不过,我可以把任何大于2的-53次方的数字加到1上,结果依然会和1不同。按照上面的定义,任何小于机器精度的值加到1上,结果应该是1。这是不是意味着sys.float_info.epsilon
返回了一个错误的值,或者Python使用了其他的精度定义呢?
下面的代码展示了这个问题,浮点数以十六进制格式打印出来。
import sys
import numpy
print 'epsilon=%g' % sys.float_info.epsilon
# output: 2.22045e-16
epsilon = sys.float_info.epsilon
print 'epsilon(hex) = %s' % float.hex(epsilon)
# output: 0x1.0000000000000p-52
one = numpy.float64(1.0)
delta = float.fromhex('0x1.fffffffffffffp-53')
print 'delta = %s' % float.hex(delta)
print 'epsilon - delta = %s' % (float.hex(epsilon-delta))
#output: 0x1.0000000000000p-105
print '\n1.0 + epsilon = %s' % (float.hex(one+numpy.float64(epsilon)))
#output: 0x1.0000000000001p+0
print '\n1.0 + delta = %s' % (float.hex(one+numpy.float64(delta)))
#output: 0x1.0000000000001p+0
# since delta is smaller than epsilon, I expected 0x1.0000000000001p+0
delta1 = float.fromhex('0x1.0000000000001p-53')
print '\n1.0 + %s = %s' % (float.hex(delta1), float.hex(one+delta1))
#output: 0x1.0000000000001p+0
# since delta is smaller than epsilon, I expected 0x1.0000000000001p+0
delta2 = float.fromhex('0x1.0000000000000p-53')
# note: delta2 = epsilon / 2.0
print '\n1.0 + %s = %s' % (float.hex(delta2), float.hex(one+delta2))
# 0x1.0000000000000p+0
得到的输出结果是
epsilon=2.22045e-16
epsilon(hex) = 0x1.0000000000000p-52
delta = 0x1.fffffffffffffp-53
epsilon - delta = 0x1.0000000000000p-105
1.0 + epsilon = 0x1.0000000000001p+0
1.0 + delta = 0x1.0000000000001p+0
1.0 + 0x1.0000000000001p-53 = 0x1.0000000000001p+0
1.0 + 0x1.0000000000000p-53 = 0x1.0000000000000p+0
2 个回答
这个定义是错的:机器精度是一个数字 eps,它的意思是 1+eps 是紧接着 1 的下一个数字。因此,在标准的四舍五入情况下,u = eps/2 是加到 1 上后能得到一个大于 1 的最小数字。这个量 u 通常被称为 单位舍入误差 或 机器单位。
(对于 IEEE64,eps=2^(-52),u = 2^(-53)。)
顺便说一下,对于大多数实际情况,单位舍入误差 u 比 eps 更有用:例如,u 是将一个值四舍五入到标准机器数字时的最大相对误差。
参考文献:Higham, 数值算法的准确性与稳定性,第 37、38 页。
我觉得你看到的情况是Python中的float
类型在精度不够时是怎么处理四舍五入的。你引用的维基百科关于epsilon
的描述似乎没有提到这一点。
在你的例子中,1 + delta
会被四舍五入到1 + epsilon
。虽然float
可以区分delta
和epsilon
之间的差别,但它无法表示1 + delta
和1 + epsilon
之间的差别。正如你在delta2
测试中注意到的,能够被四舍五入到1
而不是1 + epsilon
的最大数似乎是1 + epsilon/2
。
所以,在Python中epsilon
的正确定义可能是:
epsilon
是最小的正浮点数,使得(1 + epsilon) - 1
等于epsilon
。