我有相当大的数据文件,需要将我的第二列乘以-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位小数之后,这不是太大的问题,但它仍然会篡改我的结果。
答案 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.0885668550493399
和1.08856685504934
是相同数字的表示。
您的结果不会被伪造。你得到了相同的结果。确保计算结果的精度 - 它可能比浮点值的52位精度低很多,因为计算的每个阶段都执行一些舍入。
答案 1 :(得分:1)
如果您不需要更改与输入相比的小数位数,那么这样做应该有效:
awk '{if($2<0){gsub(/-/,"",$2)}else if($2>0){$2="-"$2};print $1,$2}'
不显示数字的浮点表示,消除了精度问题。