Question

I get six different results when dividing by zero in mawk:

$ echo | awk '{print -1/0 }' ; echo $?
-inf
0
$ echo | awk '{print 0/0 }' ; echo $?
-nan
0
$ echo | awk '{print 1/0 }' ; echo $?
inf
0
$ echo | awk '{printf ("%i\n", -1/0) }' ; echo $?
-2147483647
0
$ echo | awk '{printf ("%i\n", 0/0) }' ; echo $?
-2147483647
0
$ echo | awk '{printf ("%i\n", 1/0) }' ; echo $?
2147483647
0

I get a "success" exit code for each case.

  1. Why does this happen?
  2. What can I do about it? Do I always have to check for zero divisors before doing a division or is there a way I can rely on awk's error handling and exit codes?
Was it helpful?

Solution

I'm guessing you are using mawk, none of awk, nawk or gawk have this behaviour, division by zero is not supported on those.

Your answers are +inf for positive infinity, nan for "not a number" and -inf for negative infinity, all as expected. These are only output when printing a float, i.e. with %.6g which is the default OFMT (default format used for printing numbers).

$ mawk 'BEGIN {printf ("%i\n", 1/0) }'
2147483647
$ mawk 'BEGIN {printf ("%f\n", 1/0) }'
inf
$ gawk 'BEGIN {printf ("%f\n", 1/0) }'
gawk: fatal: division by zero attempted

When you print explicitly with "%i" you get +HUGE or -HUGE instead, this is converted to an int (signed 32-bit in your case) and printed as + or - (2^31-1).

The usual practice is to always check for divide by zero, ideally minimising the number of times you need to check by reorganising your expressions -- divide by zero causes other implementations of awk to simply terminate.

When mawk is building it detects the capabilities of your C math library:

$ ./configure
[...]
checking handling of floating point exceptions
    division by zero does not generate an exception
    overflow does not generate an exception
    math library supports ieee754

You can get "standard" behaviour if you build with NOINFO_SIGFPE defined:

$ ./configure CFLAGS="-DNOINFO_SIGFPE"
$ make clean && make
$ ./mawk 'BEGIN {printf ("%f\n", 1/0) }'
mawk: run time error: division by zero
    FILENAME="" FNR=0 NR=0

(though this isn't documented, it may not be something you should rely on).

OTHER TIPS

After trying different AWK "dialects" I came to the following conclusion:

Trying awk:

echo | awk '{print -1/0 }' ; echo $?

I am getting:

awk: (FILENAME=- FNR=1) fatal: division by zero attempted
2

Trying gawk:

echo | gawk '{print -1/0 }' ; echo $?

I am getting:

gawk: (FILENAME=- FNR=1) fatal: division by zero attempted
2

Trying mawk:

echo | mawk '{print -1/0 }' ; echo $?

I am getting:

-inf
0

If I were you, I would try to identify your "default dialect" (awk --version) and I would try to use another dialect like gawk and read the exit status in order to understand what happened.

PS: I am running Ubuntu 11.10.

PS: In my case awk is an alias for gawk.

it's not even that hard to find combinations where even gnu gawk exhibits different behavior depending on calling flags :

(these tests are also more fool-proof since the output is only based behavior of which awk/start-up opton is being called, instead of parameter constants that can be manually overwritten.

the gawk notations i've used myself (GMP/MPFR are self-explanatory) -

E = -e aka standard call
S = -S `—-sandbox`
P = -P `--posix`
c = -c `—-traditional`
n = -n `--non-decimal-data`
    #  (-nan):x:gawk-S/c/E/mpfr
    #  (+inf):x:gawk-n/P
    #  (+nan):x:gawk-GMP/GMP+mpfr
    #   ( 0 ):x:nawk
    #   (inf):x:mawk
    #   (nan):x:mawk2

      x = -log((log(0)*log(0))^-log(-0))/(-"0xABCD")^-!-"";

    # (+nan) :gawk-GMP/MPFR
    #        (NaN:mpfr_log())
    #  (nan) :nawk/mawk/mawk2
    # (-nan) :gawk-E/P/c

        x = log(log((-log(0))/-log(0)));

    # (-inf):nawk
    #  (inf):mawk/mawk2
    # (+inf):gawk-ALL

        y = log(log((-log(0))^-log(0)));

    # (-inf):gawk-GMP
    # (-inf):nawk
    # (-nan):gawk-P/E/c
    #  (nan):mawk/mawk2

        z = log(-log(1))-(-"")^-!-"";

    # (+nan):gawk-GMP
    #  (inf):mawk/mawk2
    #  (nan):nawk
    # (+inf):gawk-except-GMP

        z = log(-log(0))-(-"")^-!-"";

    # (-inf):nawk/gawk-GMP
    #  (inf):mawk/mawk2
    # (+inf):gawk-except-GMP

        z = -(-"")^-!-"";

    #  (inf):nawk
    #  ( 0 ):gawk-GMP
    # (-inf):all others

        xn = (-"")^-!"";

these examples may not be exactly just division by zero, but it does highlight that at the edge cases, their behavior varies rather wildly. here's a collated table to make it easier to follow :

    a = log(log((-log(0))^-log(0)));
    b = log(log((-log(0))/-log(0)));;
    c = -log((log(0)*log(0))^-log(-0))/(-"0xABCD")^-!-"";
    d = log(-log(0))-(-"")^-!-"";
    e = log(-log(1))-(-"")^-!-"";

/usr/local/bin/nawk  ::  -inf ::  nan ::   0  ::  nan :: -inf ::
---------------------------------------------------------------
/usr/local/bin/mawk  ::   inf ::  nan ::  inf ::  inf ::  nan ::
---------------------------------------------------------------
/usr/local/bin/mawk2 ::   inf ::  nan ::  nan ::  inf ::  nan ::
---------------------------------------------------------------
/usr/local/bin/gawk -e:: +inf :: -nan :: -nan :: +inf :: -nan ::
/usr/...,/gawk -l mpfr:: +inf :: -nan :: -nan :: +inf :: -nan ::
/usr/local/bin/gawk -S:: +inf :: -nan :: -nan :: +inf :: -nan ::
/usr/local/bin/gawk -c:: +inf :: -nan :: -nan :: +inf :: -nan ::
---------------------------------------------------------------
/usr/local/bin/gawk -P:: +inf :: -nan :: +inf :: +inf :: -nan ::
/usr/local/bin/gawk -n:: +inf :: -nan :: +inf :: +inf :: -nan ::
----------------------------------------------------------------
/usr/local/bin/gawk -M:: +inf :: +nan :: +nan :: +nan :: -inf ::
----------------------------------------------------------------
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top