2015-09-20 57 views
1

我相信,小数点后17位应该足以正确表示一个8字节的浮点数,以便它是往返安全的(转换为字符串,并且没有任何丢失)。浮点到字符串往返测试

但是在这个测试中,数字可以高达23,如果增加迭代次数可能会更高。

这是一个有缺陷的测试,为什么?
你如何确保在Python中float的往返完整性?

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.') 

If an IEEE 754 double precision is converted to a decimal string with at least 17 significant digits and then converted back to double, then the final number must match the original.

回答

2

在我原来的测试中,我使用的是小数字,所以有很多前导零,它们不是有效数字。浮点数需要17 重要的数字才能正确表示。通过像这样改变一行,我使得数字变大了,并且在小数点后只有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)): 
+3

是的,使用'.17g'作为格式是正确的方法。 '.16e'也可以。不要在Python 2上使用'str':它没有提供足够的数字。但'repr'呢。 (在Python 3的最新版本中,'str'和'repr'对于浮点数是相同的。) –

1

只有特定的号码可以准确地在浮点表示。相反,只有某些字符串将被打印为浮点数的表示形式。如果您从其中一个不会打印的字符串开始,您将永远无法将其恢复。所以,你的第一条语句,

我相信,17位小数应该足以正确 代表的8个字节的浮动,使得它往返安全(转换 为字符串和背部没有任何损失) 。

如果我正确理解你,是错误的。

你想要序列化浮点数吗?也就是说,你是否想将它们写入磁盘并在稍后读取它们?如果是这样,你应该将它们存储为二进制文件,而不是字符串。例如,您可以使用pickle模块执行此操作。

+0

这个想法是将浮点数保存在文本文件中。这基本上是我想要完成的。 – mcu

+0

感谢您提供二进制文件。 – mcu

+2

这显然不正确。在二进制<->字符串例程和像NaNs这样的特殊值中存在模错误,可以执行binary-> string-> binary往返并返回原始值。是的,并非所有的二进制值都可以在有限数量的字符串数字中完全表示,但是足够的字符串数字可以转换回二进制数字将回到原始值。 – janneb