【发布时间】:2020-12-05 20:50:04
【问题描述】:
我在 Awk 中遇到了一个无法解决的浮点不精确问题。有没有简单的解决办法?
这是我复制浮点不精确问题的示例 Awk 脚本。
BEGIN {
print "PREC = " PREC
print "OFMT = " OFMT
print "CONVFMT = " CONVFMT
a = 1.2 + 3.4
b = 8.9 - 4.3
print "a = " a
print "b = " b
if ( a == b )
print "a == b"
else
print "a != b"
c = 3.2 + 5.4
d = 9.8 - 1.2
print "c = " c
print "d = " d
if ( c == d )
print "c == d"
else
print "c != d"
}
这是上面脚本的输出。
PREC = 53
OFMT = %.6g
CONVFMT = %.6g
a = 4.6
b = 4.6
a != b
c = 8.6
d = 8.6
c == d
为什么 a != b 即使两者具有相同的值?然而,c == d 可以正常工作。
我假设 Awk 有一些内部浮点不精确。仅供参考,我使用的是 Gawk 4.1.4。
我尝试了 PREC、OFMT 和 CONVFMT 的各种值,但找不到合适的值。
例如将 OFMT 和 CONVFMT 更改为 %.6f:
PREC = 53
OFMT = %.6f
CONVFMT = %.6f
a = 4.600000
b = 4.600000
a != b
c = 8.600000
d = 8.600000
c == d
例如将 PREC 更改为 16:
PREC = 16
OFMT = %.6g
CONVFMT = %.6g
a = 4.6
b = 4.6
a != b
c = 8.6
d = 8.6
c == d
基本上,我希望在 BEGIN 中进行一些设置,而不是更改浮点算术和比较所在的每个表达式,因为我的实际 Awk 脚本比上面的示例长得多。
例如我宁愿不必对每个算术和比较表达式使用 sprintf,也不必在按 1e6 缩放后将每个输入数转换为整数并将每个输出数转换为 1e-6。这种方法会非常令人生畏。
仅供参考,输入文件中的浮点数最多有 6 个小数点,但它们可能没有小数点,即它们的范围为 0 到 6 个小数点。
感谢您的帮助。
HN
【问题讨论】:
-
"最多有 6 个小数点" --> 你可以将每个输入缩放 1,000,000 并四舍五入,然后执行你的数学运算吗?
-
@chux 我希望它不会如前所述。除了最终输出,程序还将打印中间。所以,我必须在每次打印时都包含转换。
-
这能回答你的问题吗? Is floating point math broken?
-
@PresidentJamesK.Polk 不完全是。我有点知道这个问题与浮点有关,尽管不完全是。我寻找的学术解释较少,而更多的是在 Awk 中寻找一个简单而优雅的解决方案,而不必显式处理每个算术表达式的不精确性。我希望像 Awk 这样的脚本语言能够让用户不必以低廉的价格处理 C++ 等编译语言中存在的此类繁琐和混乱的问题,包括类型、声明、数组绑定、无符号与有符号数、最大整数等运行时开销。
标签: math awk floating-point comparison precision