Ubuntu

為什麼 gawk(有時?)認為 2.0e-318 > 2.0?

  • February 1, 2020

我正在嘗試使用 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
$ 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 位有效數字的數字將被截斷。要獲得更重要的數字:要求他們。就像%.15g15 一樣(對於 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).

引用自:https://unix.stackexchange.com/questions/564397