浮點誤差最佳範例

浮點誤差最佳範例:question.vi (8.0 KB)

NI的工程師回覆了,原文如下:

Hi…張先生

這個問題我們內部之前也引起熱烈的討論
我想這是浮點運算的error造成的。
在浮點運算中3.4, 0.1這些數字都不是完完全全剛好,而是用非常非常靠近的數字來代替。
以這題來說,0.1事實上不是0.1,可以把顯示位數加大,然後改成single,(用double的話問題會在,但是顯示不出來,因為error的部份在小數點太多位的地方),就會看到乘出來的數字不是34,而是多一點點。
這不是LV才有的問題,用任何程式語言寫都是一樣的喔!!

在LabVIEW裡有兩種解法:

  1. 使用 In Range and Coerce.vi (如附檔)
  2. 轉成非浮點數處理, 依需求乘上一個倍數(如1000), 轉成整數後, 再做運算, 最後再除回來
    3.使用將representation轉換成 single precision 或extend precision. 這兩種資料格式就不會有這種問題

NI AE 吳嘉信

另一網友回覆如下:

沒錯!!終於提到重點了,使用LabVIEW相當方便,線拉一拉程式就寫好了,可是其實程式在背後幫我們做的很多動作,其中一項就是type conversion,你可能原本定義為single的資料型態,一乘上一個double的constant後就變成double。所以,LabVIEW還保留data type conversion的一些function,你可以強制定義輸出資料型態,尤其當你在做數值分析大量數學運算,這是一定要注意的。否則經過成千上萬次的運算後,誤差的累計可能把你推演的結果給推翻掉。下面有兩個相關連結,有興趣的可以看看。

IEEE 制定的浮點數規格http://bbs.ee.ntu.edu.tw/boards/Programming/17/5.html

數值方法的誤差:數值方法中的主要誤差來源.pdf (186.8 KB)

上文所提出解決方案中,我的意見如下:

  1. 使用 In Range and Coerce : 應該是目前想的到最適合的solution,可能需要包成subvi,做數值運算時用來替代原本的equal.vi。
  2. 轉成非浮點數處理, 依需求乘上一個倍數(如1000), 轉成整數後, 再做運算, 最後再除回來:把問題搞得太複雜,不建議。
  3. 使用將representation轉換成 single precision 或extend precision. 這兩種資料格式就不會有這種問題 :也可以,但全部改成extend precision太浪費記憶體,轉換來轉換去誰都會頭暈。

希望的Solution: 既然有效位數都算得出來,為什麼在比較時不四捨五入比較有效位數就好,反正很少有實驗可以精確到小數點下超過10位的。但這要看要看NI要不要解決,我試過LabVIEW6.1也有這種情形。