different AWK flavors with diff smallest double value

120 Views Asked by At

there appears to be discrepancy regarding what each flavor of awk considers the smallest figure before it underflows to zero:

mawk 1.3.4 | mawk 1.9.9.6 | macos built-in nawk
all say 2^-1074
or 4.94 x 10^-324

but gawk 5.1.0 (w/o activating GMP or MPFR) ends at
2^-1023
or 1.11 x 10^-308

which one is the IEEE 754-compliant one here ?

=====================================

ps : thanks for everyone's replies. i found 2 workarounds with gawk :

exp(-log(2)*(1024-1+52-1))

or

2^-(1024-1) * 2^-(52-1)
  • i typed it out more verbosely to make it easier to follow along regarding how the figures were derived. for shorter hand,they're

exp(-1074 * log(2))
(2^-51) * (2^-1023)

2

There are 2 best solutions below

0
Daweo On

According to GNU AWK manual - Setting precision

gawk uses a global working precision; it does not keep track of the precision or accuracy of individual numbers. Performing an arithmetic operation or calling a built-in function rounds the result to the current working precision. The default working precision is 53 bits, which you can modify using the predefined variable PREC. You can also set the value to one of the predefined case-insensitive strings shown in Table 16.4, to emulate an IEEE 754 binary format.

Table 16.4: Predefined precision strings for PREC

PREC IEEE 754 binary format
"half" 16-bit half precision
"single" Basic 32-bit single precision
"double" Basic 64-bit double precision
"quad" Basic 128-bit quardruple precision
"oct" 256-bit octuple precision

As you might deduce from above default setting (53-bit) is none of IEEE 754. You need to set PREC to one of above if you need behavior compliant with IEEE 754.

3
kvantour On

IEEE-compliance: all awk versions are IEEE compliant and can represent normal and subnormal numbers in double-precision or in the precision defined by the user (cfr. Daweo's answer). In case of GNU-awk you can see denormal numbers as:

$ awk 'BEGIN{print (2^-1023)/2}'
5.56268e-309

Furthermore, IEEE-754 states that:

The default exception handling for underflow shall always deliver a rounded result. The method for detecting tininess does not affect the rounded result delivered, which might be zero, subnormal, or ±bemin.

In case of GNU awk, the underflow is returned as a zero value in case of 2^-1024.

GNU awk and 2^-1024: So why does GNU awk return 0.0 when computing 2^-1024 but it can compute (2^-1023)/2?

When looking in the source-code, you find that if the power is a negative integer, it is computed via it's inverse (see code snippet below). This means that GNU awk computes 2^-1024 as 1.0/2^1024. But 2^1024 cannot be represented as a double precision number. The largest double-precision number is 2^1023 × (1 + (1 − 2−52)) < 2^1024. Hence, the exponent overflows leading to zero for the computation of 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);
}