10

我有一个管道分隔的提要文件,它有几个字段。因为我只需要几个,所以我想用awk捕获它们来进行测试。但是,我注意到printf如果我使用"%d". 如果我使用它可以正常工作"%s"

提要文件样本:

[jaypal:~/Temp] cat temp

302610004125074|19769904399993903|30|15|2012-01-13 17:20:02.346000|2012-01-13 17:20:03.307000|E072AE4B|587244|316|13|GSM|1|SUCC|0|1|255|2|2|0|213|2|0|6|0|0|0|0|0|10|16473840051|30|302610|235|250|0|7|0|0|0|0|0|10|54320058002|906|722310|2|0||0|BELL MOBILITY CELLULAR, INC|BELL MOBILITY CELLULAR, INC|Bell Mobility|AMX ARGENTINA SA.|Claro aka CTI Movil|CAN|ARG|

我有兴趣捕捉second columnwhich is 19769904399993903

这是我的测试:

[jaypal:~/Temp] awk -F"|" '{printf ("%d\n",$2)}' temp
19769904399993904   # Value is changed

但是,以下两个测试工作正常 -

[jaypal:~/Temp] awk -F"|" '{printf ("%s\n",$2)}' temp
19769904399993903   # Value remains same

[jaypal:~/Temp] awk -F"|" '{print $2}' temp
19769904399993903   # Value remains same

所以这是"%d"不能处理长整数的限制。如果是这样,为什么它会在数字上加一而不是截断它?

我已经尝试BSDGNU使用awk.

版本信息:

[jaypal:~/Temp] gawk --version
GNU Awk 4.0.0
Copyright (C) 1989, 1991-2011 Free Software Foundation.

[jaypal:~/Temp] awk --version
awk version 20070501
4

7 回答 7

12

GNU awk 4.1开始,您可以使用--bignum-M

$ awk 'BEGIN {print 19769904399993903}'
19769904399993904

$ awk --bignum 'BEGIN {print 19769904399993903}'
19769904399993903

§ 命令行选项

于 2014-12-27T18:33:20.140 回答
5

我相信这种情况下的基础数字格式是 IEEE 双精度数。所以改变的值是浮点精度误差的结果。如果确实有必要将大值视为数字并保持准确的精度,那么使用 Perl、Ruby 或 Python 之类的具有处理任意精度算术的能力(可能通过扩展)可能会更好。

于 2012-01-13T22:17:20.520 回答
4

更新:最新版本的 GNU awk 支持任意精度算术。有关更多信息,请参阅GNU awk 手册

原始帖子内容: XMLgawk 支持浮点数的任意精度算术。所以,如果安装xgawk是一个选项:

zsh-4.3.11[drado]% awk --version |head -1; xgawk --version | head -1
GNU Awk 4.0.0
Extensible GNU Awk 3.1.6 (build 20080101) with dynamic loading, and with statically-linked extensions

zsh-4.3.11[drado]% awk 'BEGIN {
  x=665857
  y=470832
  print x^4 - 4 * y^4 - 4 * y^2
  }'
11885568

zsh-4.3.11[drado]% xgawk -lmpfr 'BEGIN {
  MPFR_PRECISION = 80
  x=665857
  y=470832
  print mpfr_sub(mpfr_sub(mpfr_pow(x, 4), mpfr_mul(4, mpfr_pow(y, 4))), 4 * y^2)
  }'
1.0000000000000000000000000
于 2012-01-15T13:01:42.533 回答
4

@Mark Wilkins 和@Dennis Williamson 已经部分回答了这个答案,但我发现可以在不丢失精度的情况下处理的最大 64 位整数是 2^53。例如 awk 的参考页 http://www.gnu.org/software/gawk/manual/gawk.html#Integer-Programming

(对不起,如果我的答案太旧了。我想在他们像我一样花太多时间在这之前,我仍然会分享给下一个人)

于 2014-02-26T01:31:25.420 回答
1

您遇到了awk 的浮点表示问题。我认为您无法在 awk 框架内找到一种解决方法来准确地对大量数字执行算术运算。

我能想到的唯一可能(也是粗略)的方法是将大量数字分解成更小的块,执行数学运算并再次加入它们,或者更好地使用 Perl/PHP/TCL/bsh 等比 awk 更强大的脚本语言。

于 2012-01-13T22:28:38.783 回答
0

在 Solaris 11 上使用 nawk,我通过在末尾添加(连接)一个 null 将数字转换为字符串,然后%15s用作格式字符串:

printf("%15s\n", bignum "")   
于 2016-01-15T18:14:43.683 回答
0

关于精度的另一个警告:错误堆积与额外的操作::

echo 19769904399993903 | mawk2 '{ CONVFMT = "%.2000g";
                                     OFMT =   "%.20g"; 
        } {
           print;
           print +$0; 
           print $0/1.0
           print $0^1.0; 

           print exp(-log($0))^-1; 
           print exp(1*log($0))
           print sqrt(exp(exp(log(20)-log(10))*log($0))) 
           print (exp(exp(log(6)-log(3))*log($0)))^2^-1   
        }'
19769904399993903
19769904399993904
19769904399993904
19769904399993904
19769904399993912
19769904399993908
19769904399993628 <<<—— -275
19769904399993768 <<<—- -135

前几个仅相差不到 10。最后 2 个方程具有三位数的增量。

对于需要调用辅助数学函数的任何版本,仅获取 -M bignum 标志是不够的。还必须设置 PREC 变量。

对于这个例子,设置PREC=64OFMT="%.17g"应该就足够了。

谨防将 OFMT 设置得太高,相对于 PREC,否则你会看到这样的奇怪现象:

gawk -M -v PREC=256 -e '{ CONVFMT="%.2000g"; OFMT="%.80g";... } '

19769904399993903
19769904399993903.000000000000000000000000000000000000000000000000000000000003734
19769904399993903.000000000000000000000000000000000000000000000000000000000003734
19769904399993903.000000000000000000000000000000000000000000000000000000000003734
19769904399993903.000000000000000000000000000000000000000000000000000000000003734

因为80 位有效数字至少需要精度265.75,所以基本上266-bits,但 gawk 足够快,您可以安全地将其预设为 PREC=4096/8192 而不必每次都担心

于 2021-11-17T05:28:45.213 回答