Ubuntu
為什麼 gawk(有時?)認為 2.0e-318 > 2.0?
我正在嘗試使用 gawk 找到一列數據的最大值:
gawk 'BEGIN{max=0} {if($1>0+max) max=$1} END {print max}' dataset.dat
dataset.dat
看起來像這樣:2.0
2.0e-318
該命令的輸出是
2.0e-318
明顯小於 2。
我的錯誤在哪裡?
編輯
有趣的是,如果交換輸入文件的行,輸出變為
2.0
編輯 2
我的 gawk 版本是 GNU Awk 4.2.1,API:2.0(GNU MPFR 4.0.2,GNU MP 6.1.2)。
0+ 需要作為每個 $1 的前綴以強制進行數字轉換。max 不需要 0+ - 它在儲存時已經轉換為數字。
Paul--) AWK=' > BEGIN { max = 0; } > 0+$1 > max { max = 0 + $1; } > END { print max; } > ' Paul--) awk "${AWK}" <<[][] > 2.0 > 2.0e-318 > [][] 2 Paul--) awk "${AWK}" <<[][] > 2.0e-318 > 2.0 > [][] 2
2e-318
在 awk 中處理如此小的數字 ( ) 有幾個問題。
- 首先,輸入需要在使用前轉換為數字。這通常是通過添加 0 來完成的。因此,您需要以下內容:
val=0+$1
- 其次,普通雙精度浮點數(53 位尾數和 11 位指數)11 位寬度的指數允許表示 10e-308 和 10e308 之間的數字,因此,普通浮點數將無法表示此類數字。
$ echo '1e-307 1e-308' | awk '{print $1,$1+0,$2,$2+0}' 1e-307 1e-307 1e-308 0
預設 GNU awk 將不接受以下(正常)值
1e-308
。
- 第三,
awk
(CNVFMT 和 OFMT)的預設轉換格式設置為"%.6g"
. 超過 6 位有效數字的數字將被截斷。要獲得更重要的數字:要求他們。就像%.15g
15 一樣(對於 53 位尾數,不要要求超過 17,它可能會撒謊)。- 第四,最好將第一個值設置為第
max
一個輸入。如果輸入的最大值為負,將最大值設置為 0 將失敗。如果您使用的是 GNU awk 並且它已經以任意精度編譯,您可以使用:
$ printf '%s\n' 2e-318 2e-317 2e-307 2e-308 2e-319 | awk -M -v PREC=100 'BEGIN{OFMT="%.15g"}; {val=0+$1}; NR==1{max=val}; {print($1,val,max)}; val>max{max=val} END{print max}' 2e-318 2e-318 2e-318 2e-317 2e-317 2e-318 2e-307 2e-307 2e-317 2e-308 2e-308 2e-307 2e-319 2e-319 2e-307 2e-307
或簡化為您的案例:
awk -M -v PREC=100 ' BEGIN{OFMT="%.15g"}; # allow more than 6 figures {val=0+$1}; # convert input to a (float) number. NR==1{max=val}; # On the first line, set the max value. val>max{max=val} # On every entry keep track of the max. END{print max} # At the end, print the max. ' file # file with input (one per line).