More on NaN and atan2


To ng-spice-devel@ieee.ing.uniroma1.it
From Al Davis <aldavis@ieee.org>
Date Wed, 1 Nov 2000 15:26:11 -0800
Delivered-To mailing list ng-spice-devel@ieee.ing.uniroma1.it
Mailing-List contact ng-spice-devel-help@ieee.ing.uniroma1.it; run by ezmlm
Reply-To ng-spice-devel@ieee.ing.uniroma1.it

In a previous mail (Re: [ng-spice-devel] ACS converted to automake,
autoconf) which really discussed some regression mismatches, I
attempted to explain some NaN results from ACS.

Since then, I looked at the code for atan2, to get a further
understanding of this issue.  I am not sure whether it is a problem
or not.

In ACS, the apparent culprit is line 40 in u_xprobe.h:
        rv = std::arg(_value)*RTOD;

_value has type complex<double>.

std::arg returns the "argument" of a complex number, or its angle, in
radians.

*RTOD converts radians to degrees.

Underneath, std::arg simply calls atan2, which, simply put, returns
atan(y/x), with some help to deal with singularities and put it in
the correct quadrant.

The implementation is system dependent.  In glibc, it depends on your
CPU.  For i386 and derivatives, it is done in hardware.  For m68k it
isn't, and the software version has about 80 lines to deal with the
nuances, eventually calling atan(y/x) or atan(x/y) in most cases.

I thought about what if x is not really 0 but some very small number.
Even if it actually computes y/x, which might be huge, atan(huge) is
well defined. (pi/2).

It is clear that for x==0, it returns either 0, +pi, or -pi,
depending whether y is 0, +, or -  without actually computing y/x.

The Linux man page on atan2 doesn't say anything about this.  The
FreeBSD man page explains in great detail why 0 is the correct answer
for atan2(0,0), and that the standard says that this is the correct
behavior.


So, I could do either of 3 things:

1. Nothing.  The only effect is that on an HP, the phase of
complex(0,0) is displayed as NaN.   This only really matters if you
are reading the file with another program that expects a number.  (A
plotter?)  I am not aware of any other systems that do this.

2. Add a "ATAN2_IS_BROKEN" section to md.h and md.cc that replaces it
with a local one if needed.

3. Just use a local atan2.  The only use of it is not speed-critical,
but I don't like this idea.  The library functions are there to be
used.  Even if it would work, I would rather slap the hand of the
broken systems.

For now, I am leaning toward #1, but for #2 I could almost copy the
code from  sysdeps/m68k/fpu/e_atan2.c  in glibc, or possibly handle
the x==0 case and pass it on to the system atan2 for others.  (like
the "HAS_EXP_BUG" that is there now.)  (Some systems overflow when
you do exp(big_negative_number) when it should just return 0.)

al.

Partial thread listing: