GNU Awk格式化长数字时填充输出异常问题求助
问题背景
运行环境
- 系统:
Arch linux 6.15.7-zen1-1-zen - GNU Awk版本:
$ awk -V GNU Awk 5.3.2, API 4.0, PMA Avon 8-g1, (GNU MPFR 4.2.2, GNU MP 6.3.0)
目标文件内容
y.csv内容如下:
4 2016201820192020 5 20162018201920202023 5 20162018201920202024 5 00000000000000002024
异常现象
使用printf/sprintf处理文件时,第2、3行数据的最后4位被错误修改为0704,执行命令及输出如下:
$ awk '{print $1,sprintf("%020d",$2)}' y.csv 4 00002016201820192020 5 20162018201920200704 5 20162018201920200704 5 00000000000000002024 $ awk '{$2=sprintf("%020d",$2);print $1,$2}' y.csv 4 00002016201820192020 5 20162018201920200704 5 20162018201920200704 5 00000000000000002024 $ awk '{printf("%020d\n",$2)}' y.csv 00002016201820192020 20162018201920200704 20162018201920200704 00000000000000002024 $ awk '{printf("%020.0f\n",$2)}' y.csv 00002016201820192020 20162018201920200704 20162018201920200704 00000000000000002024
异常原因
这是浮点数精度丢失导致的问题:
- Awk默认将所有数值类型变量按浮点数处理,而64位双精度浮点数只能精确表示2^53以内的整数(约9×10¹⁵)。
- 第2、3行的
$2值分别是20162018201920202023和20162018201920202024,均超出2^53范围,无法被双精度浮点数精确存储,会被近似为最接近的可表示值,这个近似值的最后4位正好是0704,因此输出时出现错误。 - 第1行的
2016201820192020(约2×10¹⁵)、第4行的2024都在2^53范围内,可被精确表示,所以输出正常。
如果要精确处理这类超大整数,需将其当作字符串处理,避免Awk转换为浮点数,示例命令:
awk '{print $1, sprintf("%020s", $2)}' y.csv
内容的提问来源于stack exchange,提问作者joharr
相关产品推荐
相关产品推荐

