对于每个版本的awk在其溢出到0之前所考虑的最小数字似乎存在差异:
mawk 1.3.4 | mawk 1.9.9.6 | macos内置的nawk
都显示2^-1074
或4.94 x 10^-324
,而gawk 5.1.0 (w/o激活GMP或MPFR)终止于
2^-1023
或1.11 x 10^-308
哪一个是符合IEEE 754标准的?
=====================================
ps:谢谢大家的回复。我用gawk找到了两种变通方法:exp(-log(2)*(1024-1+52-1))
或
2^-(1024-1) * 2^-(52-1)
- 我把它打得更详细,以便更容易地了解数字是如何推导出来的。简写为
exp(-1074 * log(2))
(2^-51) * (2^-1023)
根据GNU AWK手册-设置精度
gawk
使用全局工作精度;它不跟踪精确:单个数字的精确性或准确性执行算术运算操作或调用内置函数将结果舍入到当前工作精度。默认工作精度为53位,您可以使用预定义的变量PREC
对其进行修改。你也可以将值设置为所示的预定义的不区分大小写的字符串之一在表16.4中,模拟IEEE 754二进制格式。
表16.4:PREC
PREC | IEEE 754二进制格式 | "half" | 16位一半精度 |
---|---|---|---|
single"> | 基本32位单精度 | ||
基本64位双精度 | |||
基本128位四元组精度 | |||
256位八元组精度 |
IEEE-compliance:所有的awk版本都是IEEE兼容的,并且可以用双精度或用户定义的精度表示正常和次正常数字(参见cfr)。Daweo的回答)。在GNU-awk的情况下,你可以看到不正常的数字:
$ awk 'BEGIN{print (2^-1023)/2}'
5.56268e-309
此外,IEEE-754规定:
对于下溢的默认异常处理应该总是提供一个舍入的结果。检测细小度的方法不影响所提供的舍入结果,该结果可能为零、次正常或±bemin。
在GNU awk的情况下,在2^-1024的情况下,底流作为零值返回。
GNU awk and2^-1024
:那么为什么GNU awk在计算2^-1024
时返回0.0
,而可以计算(2^-1023)/2
呢?
查看源代码时,您会发现,如果幂是一个负整数,则通过它的倒数计算(请参阅下面的代码片段)。这意味着GNU awk将2^-1024计算为1.0/2^1024。但是2^1024不能表示为双精度数。最大的双精度数是2^1023 × (1 + (1 − 2−52)) < 2^1024
。因此,对于2^-1024的计算,指数溢出导致为零。
static AWKNUM
calc_exp_posint(AWKNUM x, long n)
{
AWKNUM mult = 1;
while (n > 1) {
if ((n % 2) == 1)
mult *= x;
x *= x;
n /= 2;
}
return mult * x;
}
/* calc_exp --- calculate x1^x2 */
AWKNUM
calc_exp(AWKNUM x1, AWKNUM x2)
{
long lx;
if ((lx = x2) == x2) { /* integer exponent */
if (lx == 0)
return 1;
return (lx > 0) ? calc_exp_posint(x1, lx)
: 1.0 / calc_exp_posint(x1, -lx);
}
return (AWKNUM) pow((double) x1, (double) x2);
}