将列乘以-1会使用AWK更改结果的最后一位数

时间:2015-03-31 12:59:24

标签: awk floating-point

我有相当大的数据文件,需要将我的第二列乘以-1。 awk命令如下所示:

awk '{printf "%.4f  %.16f\n", $1, $2*-1}' file > file_reverted

这在某些行中完全正常,但在某些行中它在某种程度上向下舍入而不是仅添加0.

-0.094  0.0950083965247825  |  -0.0940  -0.0950083965247825
-0.0935 0.104569121568904   |  -0.0935  -0.1045691215689040
-0.093  0.114995049351066   |  -0.0930  -0.1149950493510660       

错误:

-0.0795 1.08856685504934    |  -0.0795  -1.0885668550493399
-0.079  1.16919985559016    |  -0.0790  -1.1691998555901599

在16位小数之后,这不是太大的问题,但它仍然会篡改我的结果。

2 个答案:

答案 0 :(得分:3)

首先,阅读What every programmer should know about floating point arithmetic。或者,如果您愿意,What very computer scientist should know about floating point arithmetic

您是否看到( - )1.0885668550493399或( - )1.08856685504934与您正在进行的操作无关。 除了符号外,数字相同

$ echo 1.08856685504934 | awk '{printf "%.16f %.16f\n", $1, -$1}'      
1.0885668550493399 -1.0885668550493399

正在发生的事情是您打印的数字比存储的数字更精确。打印数字之间的差异是10 -16 ,小于数字的2 -52 ,因此在awk的浮点的52位尾数中无法表达数字。这是保持打印输出和解析阶段的精确度所必需的。1.08856685504933991.08856685504934是相同数字的表示。

您的结果不会被伪造。你得到了相同的结果。确保计算结果的精度 - 它可能比浮点值的52位精度低很多,因为计算的每个阶段都执行一些舍入。

答案 1 :(得分:1)

如果您不需要更改与输入相比的小数位数,那么这样做应该有效:

awk '{if($2<0){gsub(/-/,"",$2)}else if($2>0){$2="-"$2};print $1,$2}'

不显示数字的浮点表示,消除了精度问题。