C/C++ C atan2 and floating point

AlexanderProphet

Active Member

Reaction score: 31
Messages: 145

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?
 

shkhln

Well-Known Member

Reaction score: 170
Messages: 459

OP
OP
AlexanderProphet

AlexanderProphet

Active Member

Reaction score: 31
Messages: 145

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?
 

aragats

Daemon

Reaction score: 480
Messages: 1,159

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
 

obsigna

Aspiring Daemon

Reaction score: 531
Messages: 909

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.
 

aragats

Daemon

Reaction score: 480
Messages: 1,159

Code:
SPECIAL VALUES
   atan2(+-0, -0) returns +-pi.
   atan2(+-0, +0) returns +-0.
Yes, it does – just checked. The man page needs to be updated, but how it's related to the OP's question?
«Close to zero» – is not zero.
 

obsigna

Aspiring Daemon

Reaction score: 531
Messages: 909

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.
 

aragats

Daemon

Reaction score: 480
Messages: 1,159

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
 

Eric A. Borisch

Well-Known Member

Reaction score: 229
Messages: 387

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... ;)
 
OP
OP
AlexanderProphet

AlexanderProphet

Active Member

Reaction score: 31
Messages: 145

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...
 
Top