浮动到字符串往返测试
Float to String Round-Trip Test
我相信 17 位小数应该足以正确表示一个 8 字节的浮点数,因此它是往返安全的(转换为字符串并返回没有任何损失)。
但在这个测试中,这个数字可以高达 23,如果你增加迭代次数,可能会更高。
这是一个有缺陷的测试吗?为什么?
以及如何确保 Python 中浮点数的往返完整性?
def TestLoop():
sFormat = ''
success = True
ff = [1.0/i for i in range(1,10000000)]
for n in range(17, 31):
sFormat = '{{:.{:d}f}}'.format(n)
success = True
for f in ff:
if f != float(sFormat.format(f)):
success = False
break
if success:
return(n)
return(-1)
n = TestLoop()
print('Lossless with ', n, ' decimal places.')
在我最初的测试中,我对小数进行运算,所以有很多前导零,它们不是有效数字。浮点数需要 17 significant 数字才能正确表示。通过像这样改变一行,我把数字变大了,小数点后只有 16 位就成功了。
ff = [10000000.0/i for i in range(1,10000000)]
最好的方法似乎是完全不使用 format()
,而是使用 repr()
或 str()
。
此代码在这里成功:
def TestLoop():
for i in range(1, 10000000):
f = 1.0 / i
if f != float(repr(f)):
print('Failed.')
return
print('Succeeded.')
return
TestLoop()
另一种可行的方法是在小数点后使用 17 位数字,但使用 g
格式化程序而不是 f
。这使用指数,因此前导零被消除。
if f != float('{:.17g}'.format(f)):
我相信 17 位小数应该足以正确表示一个 8 字节的浮点数,因此它是往返安全的(转换为字符串并返回没有任何损失)。
但在这个测试中,这个数字可以高达 23,如果你增加迭代次数,可能会更高。
这是一个有缺陷的测试吗?为什么?
以及如何确保 Python 中浮点数的往返完整性?
def TestLoop():
sFormat = ''
success = True
ff = [1.0/i for i in range(1,10000000)]
for n in range(17, 31):
sFormat = '{{:.{:d}f}}'.format(n)
success = True
for f in ff:
if f != float(sFormat.format(f)):
success = False
break
if success:
return(n)
return(-1)
n = TestLoop()
print('Lossless with ', n, ' decimal places.')
在我最初的测试中,我对小数进行运算,所以有很多前导零,它们不是有效数字。浮点数需要 17 significant 数字才能正确表示。通过像这样改变一行,我把数字变大了,小数点后只有 16 位就成功了。
ff = [10000000.0/i for i in range(1,10000000)]
最好的方法似乎是完全不使用 format()
,而是使用 repr()
或 str()
。
此代码在这里成功:
def TestLoop():
for i in range(1, 10000000):
f = 1.0 / i
if f != float(repr(f)):
print('Failed.')
return
print('Succeeded.')
return
TestLoop()
另一种可行的方法是在小数点后使用 17 位数字,但使用 g
格式化程序而不是 f
。这使用指数,因此前导零被消除。
if f != float('{:.17g}'.format(f)):