感谢您的回复。大多数都很好,提供了不错的链接,所以我就这样说吧,并回答自己的问题。
Caspin发布了这个链接。
他还提到Google Tests使用了ULP比较,当我查看谷歌代码时,我看到他们提到了完全相同的链接到Cygnus软件。
我最终实现了一些算法作为Python扩展的C版本,然后后来发现我也可以用纯Python来做。代码如下所示。
最终,我可能只会把ULP差异添加到我的技巧中。
有趣的是看到在两个相等的数字之间有多少浮点数从未离开内存。我阅读的其中一篇文章或者 Google 代码说4是一个很好的数字…但是在这里,我能达到10。
>>> f1 = 25.4
>>> f2 = f1
>>>
>>> for i in xrange(1, 11):
... f2 /= 10.0 # To cm
... f2 *= (1.0 / 2.54) # To in
... f2 *= 25.4 # Back to mm
... print 'after %2d loops there are %2d doubles between them' % (i, dulpdiff(f1, f2))
...
after 1 loops there are 1 doubles between them
after 2 loops there are 2 doubles between them
after 3 loops there are 3 doubles between them
after 4 loops there are 4 doubles between them
after 5 loops there are 6 doubles between them
after 6 loops there are 7 doubles between them
after 7 loops there are 8 doubles between them
after 8 loops there are 10 doubles between them
after 9 loops there are 10 doubles between them
after 10 loops there are 10 doubles between them
同样有趣的是,当其中一个数被写成字符串并读回来时,在相等的数字之间有多少浮点数。
>>> # 0 degrees Fahrenheit is -32 / 1.8 degrees Celsius
... f = -32 / 1.8
>>> s = str(f)
>>> s
'-17.7777777778'
>>> # Floats between them...
... fulpdiff(f, float(s))
0
>>> # Doubles between them...
... dulpdiff(f, float(s))
6255L
import struct
from functools import partial
def c_mem_cast(x, f=None, t=None):
'''
Do a c-style memory cast
In Python...
x = 12.34
y = c_mem_cast(x, 'd', 'l')
... should be equivalent to the following in c...
double x = 12.34;
long y = *(long*)&x;
'''
return struct.unpack(t, struct.pack(f, x))[0]
dbl_to_lng = partial(c_mem_cast, f='d', t='l')
lng_to_dbl = partial(c_mem_cast, f='l', t='d')
flt_to_int = partial(c_mem_cast, f='f', t='i')
int_to_flt = partial(c_mem_cast, f='i', t='f')
def ulp_diff_maker(converter, negative_zero):
'''
Getting the ULP difference of floats and doubles is similar.
Only difference if the offset and converter.
'''
def the_diff(a, b):
ai = converter(a)
if ai < 0:
ai = negative_zero - ai
bi = converter(b)
if bi < 0:
bi = negative_zero - bi
return abs(ai - bi)
return the_diff
dulpdiff = ulp_diff_maker(dbl_to_lng, 0x8000000000000000)
fulpdiff = ulp_diff_maker(flt_to_int, 0x80000000 )
ulpdiff = dulpdiff
ulpdiff.__doc__ = '''
Get the number of doubles between two doubles.
'''