(GNU)awk(bignumがコンパイルされている)で精度を上げるには、次のようにします。
$ echo '0.4970436865354813' | awk -M -v PREC=100 '{printf("%.18f\n", $1)}'
0.497043686535481300
PREC = 100は、デフォルトの53ビットではなく100ビットを意味します。
そのawkが利用できない場合は、bcを使用します。
$ echo '0.4970436865354813*1.1' | bc -l
.54674805518902943
または、フロートの本質的な不正確さとともに生きることを学ぶ必要があります。
元の行にはいくつかの問題があります:
- 1.1の係数は、1%ではなく10%の増加です(1.01乗数である必要があります)。10%使用します。
文字列から(浮動)数値への変換形式は、CONVFMTによって指定されます。デフォルト値は%.6g
です。これにより、値が小数点以下6桁に制限されます(ドットの後)。これは、のgsub変更の結果に適用され$1
ます。
$ a='0.4970436865354813'
$ echo "$a" | awk '{printf("%.16f\n", $1*1.1)}'
0.5467480551890295
$ echo "$a" | awk '{gsub($1, $1*1.1)}; {printf("%.16f\n", $1)}'
0.5467480000000000
printf形式g
は、末尾のゼロを削除します。
$ echo "$a" | awk '{gsub($1, $1*1.1)}; {printf("%.16g\n", $1)}'
0.546748
$ echo "$a" | awk '{gsub($1, $1*1.1)}; {printf("%.17g\n", $1)}'
0.54674800000000001
両方の問題は次の方法で解決できます:
$ echo "$a" | awk '{printf("%.17g\n", $1*1.1)}'
0.54674805518902947
または
$ echo "$a" | awk -v CONVFMT=%.30g '{gsub($1, $1*1.1)}; {printf("%.17f\n", $1)}'
0.54674805518902947
しかし、これがより高い精度を意味するという考えを理解しないでください。内部の数値表現は、倍のサイズのフロートのままです。つまり、精度が53ビットであり、17桁まで正確に見える場合でも、正しい10進数は15桁しかありません。それはミラージュです。
$ echo "$a" | awk -v CONVFMT=%.30g '{gsub($1, $1*1.1}; {printf("%.30f\n", $1)}'
0.546748055189029469325134868996
正しい値は次のとおりです。
$ echo "scale=18; 0.4970436865354813 * 1.1" | bc
.54674805518902943
これは、bignumライブラリがコンパイルされている場合、(GNU)awkでも計算できます。
$ echo "$a" | awk -M -v PREC=100 -v CONVFMT=%.30g '{printf("%.30f\n", $1)}'
0.497043686535481300000000000000