我有一个名为“test.txt”的文本文件,其中包含多行,其中的字段用分号分隔。我正在尝试使用field3的值>除了字段中的数字之外,除去所有内容>将它与前一行中字段3的值进行比较>如果值是唯一的,则将字段3值及其与最后一个值之间的差值重定向到名为“differences.txt”的文件。
到目前为止,我有以下代码:
awk -F';' '
BEGIN{d=0} {gsub(/^.*=/,"",$3);
if(d>0 && $3-d>0){print $3,$3-d} d=$3}
' test.txt > differences.txt
当我尝试运行以下文本时,这非常正常:
field1=xxx;field2=xxx;field3=111222222;field4=xxx;field5=xxx
field1=xxx;field2=xxx;field3=111222222;field4=xxx;field5=xxx
field1=xxx;field2=xxx;field3=111222333;field4=xxx;field5=xxx
field1=xxx;field2=xxx;field3=111222444;field4=xxx;field5=xxx
field1=xxx;field2=xxx;field3=111222555;field4=xxx;field5=xxx
field1=xxx;field2=xxx;field3=111222555;field4=xxx;field5=xxx
field1=xxx;field2=xxx;field3=111222777;field4=xxx;field5=xxx
field1=xxx;field2=xxx;field3=111222888;field4=xxx;field5=xxx
输出,如预期:
111222333 111
111222444 111
111222555 111
111222777 222
111222888 111
但是,当我尝试运行以下文本时,我会得到完全不同的,意外的数字 - 我不确定这是否是由于字段长度增加还是其他原因?
试验:
test=none;test=20170606;test=1111111111111111111;
test=none;test=20170606;test=2222222222222222222;
test=none;test=20170606;test=3333333333333333333;
test=none;test=20170606;test=4444444444444444444;
test=none;test=20170606;test=5555555555555555555;
test=none;test=20170606;test=5555555555555555555;
test=none;test=20170606;test=6666666666666666666;
test=none;test=20170606;test=7777777777777777777;
test=none;test=20170606;test=8888888888888888888;
test=none;test=20170606;test=9999999999999999999;
test=none;test=20170606;test=100000000000000000000;
test=none;test=20170606;test=11111111111111111111;
输出,带有意外值:
2222222222222222222 1111111111111111168
3333333333333333333 1111111111111111168
4444444444444444444 1111111111111111168
5555555555555555555 1111111111111110656
6666666666666666666 1111111111111111680
7777777777777777777 1111111111111110656
8888888888888888888 1111111111111111680
9999999999999999999 1111111111111110656
100000000000000000000 90000000000000000000
任何人都可以看到我出错的地方,因为我显然错过了一些东西......而且这让我很精神!!
非常感谢! :)
答案 0 :(得分:3)
第二个示例输入中的数字太大。
虽然程序的逻辑是正确的,
使用非常大的整数进行计算时会出现精度损失,例如2222222222222222222 - 1111111111111111111
导致1111111111111111168
而不是预期的1111111111111111111
。
请参阅The GNU Awk User’s Guide中的详细说明:
正如已经提到的,awk使用硬件双精度和64位IEEE二进制浮点表示来表示大多数系统上的数字。像9,007,199,254,740,997这样的大整数具有二进制表示,虽然有限,但长度超过53位;它也必须四舍五入到53位。可以存储在C double中的最大整数通常与double的最大可能值相同。如果您的系统double是IEEE 64位双精度数,则此最大可能值是一个整数,可以精确表示。还应该了解整数?
如果你想知道什么是最大的整数,这样它和所有较小的整数可以存储在64位双精度而不会丢失精度,那么答案就是2 ^ 53。下一个可表示的数字是偶数2 ^ 53 + 2,这意味着您不可能以整数格式进行gawk打印2 ^ 53 + 1。由64位双精确表示的整数范围是[-2 ^ 53,2 ^ 53]。如果你在使用64位双精度数的awk中看到超出此范围的整数,你有理由对输出的准确性非常怀疑。
正如@EdMorton在评论中指出的那样,
如果您的Awk是使用MPFR支持编译的,并且您指定了-M
标志,则可以使用任意精度算术。
有关详细信息,请参阅15.3 Arbitrary-Precision Arithmetic Features。