awk浮点比较不工作

awk浮点比较不工作,awk,floating-point,Awk,Floating Point,我有一个带有x1,x2和x值的输入文件,我想检查x是否是x1和x2之间的中点。 但这种比较是失败的 示例输入文件 x1=20.9280 x2=20.9600 x=20.9440 x1=20.9280 x2=20.9600 x=20.9440 x1=22.7840 x2=22.8160 x=22.8000 Awk命令 awk -F'[ =]' '{ if(($2 + $4)/2 != ($6)) print ($2 + $4)/2, " ", $6;}' sample 输出 20.944

我有一个带有x1,x2和x值的输入文件,我想检查x是否是x1和x2之间的中点。 但这种比较是失败的

示例输入文件

x1=20.9280 x2=20.9600 x=20.9440
x1=20.9280 x2=20.9600 x=20.9440
x1=22.7840 x2=22.8160 x=22.8000
Awk命令

awk -F'[ =]' '{ if(($2 + $4)/2 != ($6)) print ($2 + $4)/2, " ", $6;}' sample
输出

20.944   20.9440
20.944   20.9440
22.8   22.8000

由于小数点后有额外的零,比较失败。请帮助解决此问题。

这是由于所有平台中常见的浮点比较问题造成的

通过将数字转换为具有4个小数点的浮点,您可以使用此
awk
进行浮点数字比较:

awk -F'[ =]+' '{avg = sprintf("%.4f", ($2 + $4) / 2)} avg != $6 { print avg, $6 }' file

如果您有
gnu awk
,则可以将精度设置为较低的数字:

awk -M -v PREC=30 -F'[ =]+' '{avg = ($2 + $4) / 2; $6 += 0} avg != $6 { print avg, $6 }' file

不是一个真正的anwser,但要展示。在比较浮点数时,它们不相等。我用
printf
替换了
print
,并用足够的小数(20,
%.20f
)替换了修饰符:

奥特普特:

20.94400000000000261480 20.94399999999999906208
20.94400000000000261480 20.94399999999999906208
22.79999999999999715783 22.80000000000000071054

因此,请使用
sprintf
和适当的修饰符(请参阅我使用的
printf
)来控制这些值。

正如其他人所指出的,如果您遇到了问题,那么很可能您只是被常见的浮点运算问题绊倒了,但是由于您所有的输入值都具有相同的精度,您可以去掉
s,将输入数字视为整数,然后乘以2,而不是除以2,以保持整数比较也是:

$ awk -F'[ =]' '{o=$0; gsub(/\./,"")} ($6*2) == ($2+$4){$0=o; print ($2+$4)/2, $6}' file
20.944 20.9440
20.944 20.9440
22.8 22.8000

$ awk -F'[ =]' '{o=$0; gsub(/\./,"")} ($6*2) != ($2+$4){$0=o; print ($2+$4)/2, $6}' file
$

在执行比较之前,您可以使用
sub(/0+$/,“”,$6)
删除
6美元末尾的
0
。。但一般来说,直接比较浮点值是有风险的,通常两个浮点值之间的绝对差值会根据一个较小的值进行检查,比如
0.00001
@EdMorton我认为OP想要打印最后一列与中点计算不匹配的情况,例如
x1=20.9280 x2=20.9600 x=20.9240
(更改的示例)。。但由于代码有问题,三行都被打印出来了,尽管它们在最后一列都有正确的中点。。这就是为什么OP说他们不希望有任何输出,例如有问题的行…@EdMorton所以,OP可能只是在寻找
awk-F'[=]'{gsub(/\./,“”)}($6*2)!=($2+$4)
@Sundeep谢谢,我是个白痴,我错过了
在比较中。是的,我在我的答案中加入了这种转换。嗯,我从你的答案中复制了它;)好把戏顺便说一句!我不经常这样说,但我强烈反对第一种解决办法。由于
sprintf
station,您将创建误报。例如,1.23445和1.23455之间的所有数字都将转换为1.2345。是的,我理解你的观点
sprintf
解决方案仅适用于非gnu awk,它是为OP的输入定制的,OP的输入在所有数字中使用4的刻度,因此显然这里不存在case
1.23445
1.23455
。我不建议使用此解决方案。在本例中,它可能会起作用,但如果数字开始采用不同的“格式”、“范围”、“比例”会怎样?这就是为什么它会显示
,因为所有输入值都具有相同的精度。它只是针对这种特殊情况的简单解决方案。
$ awk -F'[ =]' '{o=$0; gsub(/\./,"")} ($6*2) == ($2+$4){$0=o; print ($2+$4)/2, $6}' file
20.944 20.9440
20.944 20.9440
22.8 22.8000

$ awk -F'[ =]' '{o=$0; gsub(/\./,"")} ($6*2) != ($2+$4){$0=o; print ($2+$4)/2, $6}' file
$