我想在 awk
中使用整数除法来计算两个数字的商,即截断结果。例如:
k = 3 / 2
print k
应该打印1
根据手册,
除法;因为awk中的所有数字都是浮点数,所以结果不会四舍五入为整数
有没有什么解决办法可以得到一个整数值?
原因是我想要获得一个具有整数索引[0到num-1]的数组的中间元素。
使用int
函数获取结果的整数部分,向0截断。这将产生距离结果和0之间最近的整数。例如,int(3/2)
是1,int(-3/2)
是-1。
来源:AWK手册-数字函数
在简单情况下,您可以安全地使用int()
函数,该函数向零截断:
awk 'BEGIN { print int(3 / 2) }' # prints 1
gawk 'BEGIN { print int(-3 / 2) }' # prints -1; not guaranteed in POSIX awk
请记住,awk始终使用双精度浮点数2和浮点运算3。要获取整数和整数运算的唯一方法是使用外部工具,例如标准的expr
实用程序:
awk 'BEGIN { "expr 3 / 2" | getline result; print result; }' # prints 1
这真的很尴尬,又长又慢,但安全可靠且易于移植。
1 在POSIX awk中,仅对正参数保证截断为零:int(x) — 返回将参数截断为整数的值。当 x>0 时,截断应向 0 进行。 GNU awk (gawk) 即使对于负数也使用向 0 截断:int(x) — 返回最接近 x 且位于 x 和零之间并向零截断的整数。例如,int(3) 是 3,int(3.9) 是 3,int(-3.9) 是 -3,int(-3) 也是 -3。
2 数值表达式在 POSIX 的Expressions in awk 中指定为双精度浮点数。
3 所有算术运算都应遵循 ISO C 标准规定的浮点运算语义(请参见Concepts Derived from the ISO C Standard)。 — POSIX awk:算术函数
如果您选择使用浮点数,应该了解它们的怪癖并准备识别和避免相关的错误。以下是几个令人恐惧的例子:
不可表示的数字:
awk 'BEGIN { x = 0.875; y = 0.425; printf("%0.17g, %0.17g\n", x, y) }'
# prints 0.875, 0.42499999999999999
截断误差的累积:
awk 'BEGIN{s=0; for(i=1;i<=100000;i++)s+=0.3; printf("%.10f, %d\n",s,int(s))}'
# prints 29999.9999999506, 29999
舍入误差会破坏比较:
awk 'BEGIN { print (0.1 + 12.2 == 12.3) }' # prints 0
精度随着数量级的增加而降低,导致无限循环:
awk 'BEGIN { for (i=10^16; i<10^16+5; i++) printf("%d\n", i) }'
# prints 10000000000000000 infinitely many times
阅读更多有关浮点数如何工作的内容:
Stack Overflow 标签 floating-point wiki
Wikipedia文章 浮点数
GNU awk 任意精度算术 – 包含特定实现和一般知识的信息
int(3/2+0.25)
。 - user000001awk 'BEGIN {print int(7/8), int (7/8 + 0.25)}'
会产生 0 1
的结果。 - Palec1 /(d / 2)
,其中d
是分母。只要这个值大于浮点误差,它就可以正常工作。 - user000001使用以下方法可以进行安全和快速的awk整数除法:
q=(n-n%d)/d+(n<0)
ceil
类型舍入。存在其他数学上正确的取模概念和因此舍入方法。可能有其他更优选的方法。 - user8017719ceil
函数不等价。 - Marc.2377gawk -v n=-1 -v d=1 'BEGIN{print(n-n%d)/d+(n<0)}'
输出的结果是 0,而在 bash -c 'echo $((-1/1))'
中输出的则是 -1。 - xebeche