Python的epsilon值正确吗?

6 投票
2 回答
17676 浏览
提问于 2025-04-18 03:33

根据维基百科的说法:

机器精度(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 个回答

4

这个定义是错的:机器精度是一个数字 eps,它的意思是 1+eps 是紧接着 1 的下一个数字。因此,在标准的四舍五入情况下,u = eps/2 是加到 1 上后能得到一个大于 1 的最小数字。这个量 u 通常被称为 单位舍入误差机器单位
(对于 IEEE64,eps=2^(-52),u = 2^(-53)。)

顺便说一下,对于大多数实际情况,单位舍入误差 u 比 eps 更有用:例如,u 是将一个值四舍五入到标准机器数字时的最大相对误差。

参考文献:Higham, 数值算法的准确性与稳定性,第 37、38 页。

7

我觉得你看到的情况是Python中的float类型在精度不够时是怎么处理四舍五入的。你引用的维基百科关于epsilon的描述似乎没有提到这一点。

在你的例子中,1 + delta会被四舍五入到1 + epsilon。虽然float可以区分deltaepsilon之间的差别,但它无法表示1 + delta1 + epsilon之间的差别。正如你在delta2测试中注意到的,能够被四舍五入到1而不是1 + epsilon的最大数似乎是1 + epsilon/2

所以,在Python中epsilon的正确定义可能是:

epsilon是最小的正浮点数,使得(1 + epsilon) - 1等于epsilon

撰写回答