尽管 %e,awk 仍不以科学计数法输出

Ros*_*oss 5 bash awk

我正在使用 awk 进行一些基本计算,并希望强制我的输出采用科学计数法。我正在用它OFMT="%.15e"来完成这个任务。在大多数机器上,我得到了预期的输出:

$ awk 'BEGIN { OFMT = "%.15e"; print 4.483923595133619e+29 / 1000 }'
4.483923595133619e+26
Run Code Online (Sandbox Code Playgroud)

但是我的集群上的 awk 版本给出了:

$ awk --version | head --lines=2
GNU Awk 4.0.2
Copyright (C) 1989, 1991-2012 Free Software Foundation.

$ awk 'BEGIN { OFMT = "%.15e"; print 4.483923595133619e+29 / 1000 }'
448392359513361882871234560
Run Code Online (Sandbox Code Playgroud)

为什么 awk 的这个版本/配置没有按照要求输出为科学计数法?我怎样才能便携地得到我想要的结果( 4.483923595133619e+26 )?

Kei*_*son 4

我相信您已经发现了 GNU awk 中长期存在的错误。

GNU awk 行为正确。

POSIX是这样说的:

完全等于整数值的数值(请参阅 ISO C 标准派生的概念)应通过等效于以字符串作为参数调用函数sprintf(请参阅字符串函数)转换为字符串"%d"fmt并且被转换为第一个也是唯一一个参数的数值expr

使用printf而不是设置OFMT并不是解决 gawk bug 的方法。这是代码中错误的解决方案。

任何足够大的浮点值都完全等于整数。

(如果您习惯于具有不同整数和浮点类型的语言,awk 通过值区分整数和非整数的方式可能会有点令人困惑。)

这是正在发生的事情的演示:

$ cat foo.awk
#!/usr/bin/awk -f

BEGIN {
    OFMT="%.16e"
    for (i = 50; i <= 55; i ++) {
        x = 2 ** i - 0.5
        printf("2**%d - 0.5 = %.3f = ", i, x)
        print(x)
    }
}
$ ./foo.awk
2**50 - 0.5 = 1125899906842623.500 = 1.1258999068426235e+15
2**51 - 0.5 = 2251799813685247.500 = 2.2517998136852475e+15
2**52 - 0.5 = 4503599627370495.500 = 4.5035996273704955e+15
2**53 - 0.5 = 9007199254740992.000 = 9007199254740992
2**54 - 0.5 = 18014398509481984.000 = 18014398509481984
2**55 - 0.5 = 36028797018963968.000 = 36028797018963968
$
Run Code Online (Sandbox Code Playgroud)

我最初认为这是 gawk 中的一个错误,我在这里提交了一个错误报告:

https://lists.gnu.org/archive/html/bug-gawk/2023-05/msg00010.html

Andrew J. Schorr 的回复正确地表明这是预期的行为。

https://lists.gnu.org/archive/html/bug-gawk/2023-05/msg00011.html

邮件列表上有更多回复。该文档可能对OFMT和之间的关系不够清楚CONVFMT。我上面引用的 POSIX 措辞是在谈论CONVFMT.

https://lists.gnu.org/archive/html/bug-gawk/2023-05/threads.html