2015-09-20 64 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