C C atan2 and floating point

Hi,
I've noticed that when I pass values very close to zero to atan2 it still gives an angle of +/- 180 degrees or +/- 90 degrees. But KDE's calculator's atan gives zero for the same inputs. Also the book I am reading (Understanding Digital Signal Processing) gives zeroes in the example I am working through.
I'm guessing these are floating point errors? Though I am surprised because I'm using double precision floats.
I made a hack "atan2" where I test for both values having a magnitude below 0.001 and it works (gives the same answers as the book) - however it is just that: a hack that I'm concerned may come back to bite me.
Any thoughts or suggestions?
 
It matters greatly because the phase relationship of two sinusoids is zero in the book and 90 degrees on my computer. Due to some kind of numerical error involving very tiny values which admittedly may be my fault but I'm inclined to blame FP.
Can anyone else help?
 
Did you read atan2(3)?

After reading that, you want to compare the results of atan2(x, y) with atan(y/x) for some reasonable choices of x and y. Take into account the special cases where the result of y/x becomes negative, zero or infinite. In case you find any significant difference, please write a PR. In case the results are similar, i.e. differences of less than 1e-14, forget it.
 
I've noticed that when I pass values very close to zero to atan2 it still gives an angle of +/- 180 degrees or +/- 90 degrees.
I really don't understand what's wrong with that. From atan2(3):
Code:
   atan2(y, x) :=    atan(y/x)                       if x > 0,
                     sign(y)*(pi - atan(|y/x|))      if x < 0,
                     0                               if x = y = 0, or
                     sign(y)*pi/2                    if x = 0 ≠ y.
Zero is only when both x and y are zeros. Am I missing anything?
Just tested:
Code:
% cat atan.c
#include <stdio.h>
#include <math.h>

int main()
{
    double f1 = 0.00000001;
    double f2 = 0.00000001;

    printf ("atan2(%0.8f, %0.8f)=%f\n", f1, f2, atan2(f1, f2));
}

% cc -o atan -lm atan.c  && ./atan 
atan2(0.00000001, 0.00000001)=0.785398
 
I deleted my first response, because in the meantime I read the atan2(3) manual page on macOS 10.13, and this one knows much more special cases. Now the point is, that the results of the special cases of atan2 on FreeBSD actually resembles much more to the macOS man page than to the one of FreeBSD. Please compare atan2(3) with:
Code:
SPECIAL VALUES
     atan2(+-0, -0) returns +-pi.
     atan2(+-0, +0) returns +-0.
     atan2(+-0, x) returns +-pi for x < 0.
     atan2(+-0, x) returns +-0 for x > 0.
     atan2(y, +-0) returns +pi/2 for y > 0.
     atan2(y, +-0) returns -pi/2 for y < 0.
     atan2(+-y, -infinity) returns +-pi for finite y > 0.
     atan2(+-y, +infinity) returns +-0 for finite y > 0.
     atan2(+-infinity, x) returns +-pi/2 for finite x.
     atan2(+-infinity, -infinity) returns +-3*pi/4.
     atan2(+-infinity, +infinity) returns +-pi/4.

Perhaps a PR should be submitted asking for corrections of the atan2(3) man page.
 
Agreed, the OP’s report is not very conclusive. His values ±180 and ±90 degrees, i.e. ±3.141593... and ±1.570796... would actually be the result of atan2(±0.0, -0.001) = ±3.141593 and atan2(±0.001, 0.0) = 1.570796. However, it is not quite clear what he is talking about.
 
It properly works down to the allowed minimum when the compiler spits out a warning:
Code:
warning: magnitude of floating-point constant too small for type 'double'; minimum is
      4.9406564584124654E-324 [-Wliteral-range]
        double f2 = -1e-324;
At that point it prints:
Code:
atan2(0, -0)=3.141593
With larger numbers it calculates the actual value:
Code:
atan2(1e-300, -1e-300)=2.356194
 
When in doubt, check the source. See also.

KDE's calculator is likely "fixing" or "cleaning" values that are close to +-0 to +0. And as for your code, it depends on what you mean by very close to zero.

All floating point is in error; it's just a question by how much... ;)
 
Thanks everyone for your replies. Sorry for the delay in getting back to you. Yes I formulated the problem very badly. I think what is happening is not due to atan/atan2, but due to the fact that my double precision value has gone through a lot of processing before being passed to atan/atan2. And also post-processing - conversion to degrees.
One day I'm going to post something sensible on here...
 
Back
Top