Awk:为什么向上取整数字对范围无效?

时间:2018-07-25 13:21:38

标签: awk floating-point range rounding

尝试了解以下代码为何会打印我所需的0-30范围

awk 'BEGIN{n=300;k=sprintf("%.0f",n/10);x=k*1;for (i=0;i<=x;i++) print i}' /dev/null

同时,以下代码将仅打印0-3之间的数字

awk 'BEGIN{n=300;k=sprintf("%.0f",n/10);for (i=0;i<=k;i++) print i}' /dev/null

是否有更好的方法将数字四舍五入并打印范围?

2 个答案:

答案 0 :(得分:1)

您希望sprintf()为您做什么?它真正要做的就是将所需的数字转换为字符串,因此以后的比较是基于字符串的,而不是基于数字的,这就是为什么您遇到问题的原因,因为字符串"4"大于字符串"30" 。 btw行的末尾不需要/ dev / null。您只需要:

awk 'BEGIN{n=300;k=n/10;for (i=0;i<=k;i++) print i}'

实际上,我看到您说过一些关于四舍五入的数字,这是您希望sprintf会做的吗?大多数[s] printf实现都会进行无偏四舍五入,因此它会将.5朝四舍五入,而不是您所期望的向上或向下。考虑使用此方法来控制舍入方向:

$ awk 'BEGIN{x=6.5; print x, int(x), sprintf("%.0f",x), int(x+0.5)}'
6.5 6 6 7

$ awk 'BEGIN{x=7.5; print x, int(x), sprintf("%.0f",x), int(x+0.5)}'
7.5 7 8 8

在上面请注意,对于正数,int(x)总是四舍五入,int(x+0.5)总是四舍五入,而sprintf("%0.f",x)则四舍五入到最接近的偶数。还要对负数执行此操作:

$ awk 'BEGIN{x=1; print x, "down:", int(x<0 ? x-0.5 : x), "up:", int(x<0 ? x : x+0.5)}'
1 down: 1 up: 1
$ awk 'BEGIN{x=0.5; print x, "down:", int(x<0 ? x-0.5 : x), "up:", int(x<0 ? x : x+0.5)}'
0.5 down: 0 up: 1
$ awk 'BEGIN{x=0; print x, "down:", int(x<0 ? x-0.5 : x), "up:", int(x<0 ? x : x+0.5)}'
0 down: 0 up: 0
$ awk 'BEGIN{x=-0.5; print x, "down:", int(x<0 ? x-0.5 : x), "up:", int(x<0 ? x : x+0.5)}'
-0.5 down: -1 up: 0
$ awk 'BEGIN{x=-1; print x, "down:", int(x<0 ? x-0.5 : x), "up:", int(x<0 ? x : x+0.5)}'
-1 down: -1 up: -1

有关更多信息,请参见https://www.gnu.org/software/gawk/manual/gawk.html#Round-Function,但我不明白为什么该功能如此复杂。

答案 1 :(得分:0)

GNU Awk文档中可以很明显地看出,sprintf返回的字符串类型需要在循环期间转换为整数

awk 'BEGIN{n=300;k=sprintf("%.0f",n/10);for (i=0;i<=k+0;i++) print i}' /dev/null
#                                                   ^^^^ adding +0 casts any string type to an 
#                                                       numeric type in awk

尽管在第一个示例中,由于您拥有变量x(您将其乘以1并在for循环中使用该变量),因此进行了强制转换。

就像Ed的评论一样,您只需在一次for循环迭代中执行一次即可

awk 'BEGIN{n=300;k=(sprintf("%.0f",n/10)+0); for (i=0;i<=k;i++) print i}' /dev/null