mkc*_*mkc 19 awk arithmetic floating-point
我正在寻找一种方法来告诉 awk 在替换操作中进行高精度算术。这涉及从文件中读取一个字段,并用该值的 1% 增量替换它。但是,我在那里失去了精度。这是问题的简化再现:
$ echo 0.4970436865354813 | awk '{gsub($1, $1*1.1)}; {print}'
0.546748
Run Code Online (Sandbox Code Playgroud)
在这里,我有一个 16 位的小数精度,但 awk 只给出了 6 位。使用 printf,我得到了相同的结果:
$ echo 0.4970436865354813 | awk '{gsub($1, $1*1.1)}; {printf("%.16G\n", $1)}'
0.546748
Run Code Online (Sandbox Code Playgroud)
关于如何获得所需精度的任何建议?
Sté*_*las 18
$ echo 0.4970436865354813 | awk -v CONVFMT=%.17g '{gsub($1, $1*1.1)}; {print}'
0.54674805518902947
Run Code Online (Sandbox Code Playgroud)
或者更确切地说,在这里:
$ echo 0.4970436865354813 | awk '{printf "%.17g\n", $1*1.1}'
0.54674805518902947
Run Code Online (Sandbox Code Playgroud)
可能是你能做到的最好的。使用bc而不是为任意精度。
$ echo '0.4970436865354813 * 1.1' | bc -l
.54674805518902943
Run Code Online (Sandbox Code Playgroud)
小智 6
为了使用 (GNU) awk(编译了 bignum)获得更高的精度,请使用:
$ echo '0.4970436865354813' | awk -M -v PREC=100 '{printf("%.18f\n", $1)}'
0.497043686535481300
Run Code Online (Sandbox Code Playgroud)
PREC=100 表示 100 位,而不是默认的 53 位。
如果 awk 不可用,请使用 bc
$ echo '0.4970436865354813*1.1' | bc -l
.54674805518902943
Run Code Online (Sandbox Code Playgroud)
或者您需要学会忍受浮动固有的不精确性。
在您的原始行中有几个问题:
从字符串到(浮点)数字的转换格式由 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
Run Code Online (Sandbox Code Playgroud)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
Run Code Online (Sandbox Code Playgroud)
这两个问题都可以通过以下方式解决:
$ echo "$a" | awk '{printf("%.17g\n", $1*1.1)}'
0.54674805518902947
Run Code Online (Sandbox Code Playgroud)
或者
$ echo "$a" | awk -v CONVFMT=%.30g '{gsub($1, $1*1.1)}; {printf("%.17f\n", $1)}'
0.54674805518902947
Run Code Online (Sandbox Code Playgroud)但不要以为这意味着更高的精度。内部数字表示形式仍然是双倍大小的浮点数。这意味着 53 位精度,因此您只能确定 15 位正确的十进制数字,即使很多时候最多 17 位数字看起来是正确的。那是海市蜃楼。
$ echo "$a" | awk -v CONVFMT=%.30g '{gsub($1, $1*1.1}; {printf("%.30f\n", $1)}'
0.546748055189029469325134868996
Run Code Online (Sandbox Code Playgroud)
正确的值为:
$ echo "scale=18; 0.4970436865354813 * 1.1" | bc
.54674805518902943
Run Code Online (Sandbox Code Playgroud)
如果 bignum 库已编译为以下版本,也可以使用 (GNU) awk 进行计算:
$ echo "$a" | awk -M -v PREC=100 -v CONVFMT=%.30g '{printf("%.30f\n", $1)}'
0.497043686535481300000000000000
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
22343 次 |
| 最近记录: |