英文:
Awk not outputting in scientific notation despite %e
问题
我使用awk进行一些基本计算,并希望强制输出科学计数法。我使用OFMT="%.15e"
来实现这一点。在大多数机器上,我得到了预期的输出:
$ awk 'BEGIN { OFMT = "%.15e"; print 4.483923595133619e+29 / 1000 }'
4.483923595133619e+26
但是我的集群上的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
为什么这个版本/配置的awk没有按要求输出科学计数法?如何能够以可移植的方式获得我想要的结果(4.483923595133619e+26
)?
英文:
I am using awk for some basic calculations and want to force my output to be in scientific notation. I am using OFMT="%.15e"
to accomplish this. On most machines, I get the expected output:
$ awk 'BEGIN { OFMT = "%.15e"; print 4.483923595133619e+29 / 1000 }'
4.483923595133619e+26
But a version of awk on my cluster gives:
$ 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
Why is this version/configuration of awk not outputting to scientific notation as requested? How can I portably get my desired result (4.483923595133619e+26
)?
答案1
得分: 4
Here's the translated content:
<strike>我认为您发现了GNU awk中的一个长期存在的错误。</strike>
GNU awk的行为是正确的。
这里是[POSIX所说的内容](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/awk.html):
> 具有与整数值完全相等的数值将通过等效于使用字符串`"%d"`作为`fmt`参数以及将要转换的数值作为第一个唯一的`expr`参数的`sprintf`函数(请参阅String Functions)来转换为字符串。
使用`printf`而不是设置`OFMT`不是解决gawk错误的方法。这是解决您的代码中的错误的方法。
任何足够大的浮点值都与整数完全相等。
(awk通过它们的值来区分整数和非整数的方式可能会让人感到困惑,如果您习惯了具有明确整数和浮点类型的语言。)
这里是发生的示例:
```bash
$ 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
$
最初我认为这是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
请注意,我已根据您的要求省略了代码部分,并只提供了翻译的内容。
<details>
<summary>英文:</summary>
<strike>I believe you've found a longstanding bug in GNU awk.</strike>
GNU awk is behaving correctly.
Here's [what POSIX says](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/awk.html):
> A numeric value that is exactly equal to the value of an integer (see Concepts Derived from the ISO C Standard) shall be converted to a string by the equivalent of a call to the `sprintf` function (see String Functions) with the string `"%d"` as the `fmt` argument and the numeric value being converted as the first and only `expr` argument.
Using `printf` rather than setting `OFMT` is not a workaround for a gawk bug. It's the solution to the bug in your code.
Any sufficiently large floating-point value is exactly equal to an integer.
(The way awk distinguishes between integers and non-integers by their values can be a bit confusing if you're accustomed to languages that have distinct integer and floating-point types.)
Here's a demonstration of what's happening:
$ 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
250 - 0.5 = 1125899906842623.500 = 1.1258999068426235e+15
251 - 0.5 = 2251799813685247.500 = 2.2517998136852475e+15
252 - 0.5 = 4503599627370495.500 = 4.5035996273704955e+15
253 - 0.5 = 9007199254740992.000 = 9007199254740992
254 - 0.5 = 18014398509481984.000 = 18014398509481984
255 - 0.5 = 36028797018963968.000 = 36028797018963968
$
I initially thought this was a bug in gawk, and I submitted a bug report here:
https://lists.gnu.org/archive/html/bug-gawk/2023-05/msg00010.html
A reply from Andrew J. Schorr correctly says that this is the expected behavior.
https://lists.gnu.org/archive/html/bug-gawk/2023-05/msg00011.html
There have been more responses on the mailing list. The documentation is probably insufficiently clear about the relationship between `OFMT` and `CONVFMT`. The POSIX wording I cited above is talking about `CONVFMT`.
https://lists.gnu.org/archive/html/bug-gawk/2023-05/threads.html
</details>
# 答案2
**得分**: 1
I did run
awk 'BEGIN { OFMT = "%.15e"; print 4.483923595133619e+29 / 1000 }'
using **gawk 4.2.1** and it did give
448392359513361882871234560
I was unable to find reason for that, but determined that using [`printf`][1] does what you want, that is
awk 'BEGIN { printf("%.15e\n", 4.483923595133619e+29 / 1000) }'
using **gawk 4.2.1** did give
4.483923595133619e+26
Observe need to apply line terminator yourself (`\n` means newline). Please try it with your `awk` and write if it does work as intended.
[1]: https://www.gnu.org/software/gawk/manual/html_node/Printf-Examples.html
<details>
<summary>英文:</summary>
I did run
awk 'BEGIN { OFMT = "%.15e"; print 4.483923595133619e+29 / 1000 }'
using **gawk 4.2.1** and it did give
448392359513361882871234560
I was unable to find reason for that, but determined that using [`printf`][1] does what you want, that is
awk 'BEGIN { printf("%.15e\n", 4.483923595133619e+29 / 1000) }'
using **gawk 4.2.1** did give
4.483923595133619e+26
Observe need to apply line terminator yourself (`\n` means newline). Please try it with your `awk` and write if it does work as intended.
[1]: https://www.gnu.org/software/gawk/manual/html_node/Printf-Examples.html
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论