Shell 腳本和在分隔文件中新增大值問題

Shell 腳本和在分隔文件中新增大值問題

我有一個腳本,它讀取分隔文件並為每個記錄添加文件中的第三個元素。對於大多數資料檔案來說,除了一個資料檔案之外,這種方法都可以正常運作。我有一個數據文件,該數據文件中有 193 條記錄。我期待從腳本中返回 2028219.43 。相反,我得到了一個指數數,它似乎已經被四捨五入了。起初我認為透過使用 printf 我會得到數字,但如果數字已經四捨五入,那麼它不會給我回我所期望的結果。

這是我用來讀取分隔資料檔的程式碼。每筆記錄中的資料以 * 分隔:

export clm_total=$( awk -F* '{f1+=$3} END {print f1}' datafile.dat)
export new_clm_total=$(printf "%.2f" $clm_total)

這是我運行腳本時日誌中顯示的內容:

+ export clm_total=2.02822e+06
+ printf %.2f 2.02822e+06
+ export new_clm_total=2028220.00
+ echo 2028220.00

這是資料檔案的範例。記錄還比較多,我覺得沒有必要把193筆記錄全部顯示出來:

CLM*123456789*4820.9***13:A:1**A*Y*Y
CLM*123698547*3642.05***13:A:7**A*Y*Y
CLM*147852369*579.25***13:A:1**A*Y*Y
CLM*789654123*929.8***13:A:1**A*Y*Y

我期待返回的是 2028219.43 我返回的是 2.02822e+06 然後將其格式化為 2028220.00

答案1

awk 對雙精確度浮點數執行算術運算。我不知道你能得到兩位小數的精確結果的確切限制是多少,但你在範圍內。然而這如果數字變大可能會出現問題。如果您需要確保獲得準確的結果,請堅持使用整數並注意溢出,或使用bc執行任意精度算術的函數。

這裡的問題是 awk 正在計算正確的結果,但預設的列印格式是近似的。列印結果時使用明確的格式。

export clm_total=$( awk -F'*' '{f1+=$3} END {printf "%.2f\n", f1}' datafile.dat)

或者,您也可以堅持print更改列印格式以將數字轉換為字串。預設值%.6g會產生您所看到的近似值。

export clm_total=$( awk -F'*' -v CONVFMT='%.2f' '{f1+=$3} END {print f1}' datafile.dat)

答案2

在處理電腦科學中的浮點數學時(特別是awk在您的情況下),您必須注意用於表示系統內資料的底層機制。

我相信這是您在特定情況下面臨的問題。請參閱這篇文章:D.3 浮點數注意事項,了解有關該主題的更多資訊。這篇文章也有助於闡明這個問題:15.2 理解浮點編程

我可以說,在處理浮點數時,awk您似乎只有幾個數字可用於數字的尾數部分,因此,當您繼續累積數字時,您會遇到引入舍入和截斷錯誤的情況,並且您正在失去準確性。

例子

您可以在此處看到我們何時超過閾值並開始使用科學記數法來追蹤實際數字。

$ seq -f "%f" 1413 | awk '{f1+=$1+0.4} END {print f1}'
999556
$ seq -f "%f" 1414 | awk '{f1+=$1+0.4} END {print f1}'
1.00097e+06

相關內容