Strange result with math.atan2()

G

Guest

I think that this results must be the same:

In [3]: math.atan2(-0.0,-1)
Out[3]: -3.1415926535897931

In [4]: math.atan2(-0,-1)
Out[4]: 3.1415926535897931

In [5]: -0 == -0.0
Out[5]: True


This is python 2.4.4c0 on Debian GNU/Linux.


Regards,

Vedran FuraÄ
 
P

Peter Otten

Vedran said:
I think that this results must be the same:

In [3]: math.atan2(-0.0,-1)
Out[3]: -3.1415926535897931

In [4]: math.atan2(-0,-1)
Out[4]: 3.1415926535897931

In [5]: -0 == -0.0
Out[5]: True

Glimpsing at the hardware formats:
'\x00\x00\x00\x00'

-0 and +0 integers are identical while 0.0 and -0.0 floats are not. The
negative sign is therefore lost before the int --> float conversion takes
place.

Peter
 
B

Ben Caradoc-Davies

Vedran said:
I think that this results must be the same:
In [3]: math.atan2(-0.0,-1)
Out[3]: -3.1415926535897931
In [4]: math.atan2(-0,-1)
Out[4]: 3.1415926535897931

-0 is converted to 0, then to 0.0 for calculation, losing the sign. You
might as well write 0.0 instead of -0

The behaviour of atan2 conforms to the ISO C99 standard (Python is
implemented in C). Changing the sign of the first argument changes the
sign of the output, with no special treatment for zero.
In [5]: -0 == -0.0
Out[5]: True

The constant -0 is an integer and is immediately converted to 0 (an
integer). Two's-complement integers have no separate sign bit, and only
one representation for zero. The integer -0 is identical in all respects
to the integer 0

The constant -0.0 is a float, stored as an IEEE 754 bit pattern, and has
a bit used to represent sign. The constants 0.0 and -0.0 compare equal,
and both compare equal to 0, yet 0.0 and -0.0 have distinct bit patterns.

Because Python uses the C implementation of atan2, both arguments are
converted to floats before calculation. -0 is converted to 0, then to 0.0

The behaviour of atan2 is mandated by ISO C99 (ISO/IEC 9899:1999). See
the manuals of some implementers who tabulate these special values:

http://developer.apple.com/documentation/Darwin/Reference/ManPages/man3/atan2.3.html
http://www.ugcs.caltech.edu/manuals/libs/mpfr-2.2.0/mpfr_22.html
 
G

Guest

Ben said:
Vedran said:
I think that this results must be the same:
In [3]: math.atan2(-0.0,-1)
Out[3]: -3.1415926535897931
In [4]: math.atan2(-0,-1)
Out[4]: 3.1415926535897931

-0 is converted to 0, then to 0.0 for calculation, losing the sign. You
might as well write 0.0 instead of -0

The behaviour of atan2 conforms to the ISO C99 standard (Python is
implemented in C). Changing the sign of the first argument changes the
sign of the output, with no special treatment for zero.

http://www.ugcs.caltech.edu/manuals/libs/mpfr-2.2.0/mpfr_22.html

Well, here I can read:

Special values are currently handled as described in the ISO C99 standard
for the atan2 function (note this may change in future versions):

* atan2(+0, -0) returns +Pi.
* atan2(-0, -0) returns -Pi. /* wrong too */
* atan2(+0, +0) returns +0.
* atan2(-0, +0) returns -0. /* wrong too */
* atan2(+0, x) returns +Pi for x < 0.
* atan2(-0, x) returns -Pi for x < 0
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

And the formula (also from that site):
if x < 0, atan2(y, x) = sign(y)*(PI - atan (abs(y/x)))
^^^^^^^

So, you can convert -0 to 0, but you must multiply the result with sign of
y, which is '-' (minus).

Also, octave:

octave2.9:1> atan2(-0,-1)
ans = -3.1416

or matlab:

ans =

-3.1416
 
S

Serge Orlov

Vedran said:
Ben said:
Vedran said:
I think that this results must be the same:
In [3]: math.atan2(-0.0,-1)
Out[3]: -3.1415926535897931
In [4]: math.atan2(-0,-1)
Out[4]: 3.1415926535897931

-0 is converted to 0, then to 0.0 for calculation, losing the sign. You
might as well write 0.0 instead of -0

The behaviour of atan2 conforms to the ISO C99 standard (Python is
implemented in C). Changing the sign of the first argument changes the
sign of the output, with no special treatment for zero.

http://www.ugcs.caltech.edu/manuals/libs/mpfr-2.2.0/mpfr_22.html

Well, here I can read:

Special values are currently handled as described in the ISO C99 standard
for the atan2 function (note this may change in future versions):

* atan2(+0, -0) returns +Pi.
* atan2(-0, -0) returns -Pi. /* wrong too */
* atan2(+0, +0) returns +0.
* atan2(-0, +0) returns -0. /* wrong too */
* atan2(+0, x) returns +Pi for x < 0.
* atan2(-0, x) returns -Pi for x < 0
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

And the formula (also from that site):
if x < 0, atan2(y, x) = sign(y)*(PI - atan (abs(y/x)))
^^^^^^^

So, you can convert -0 to 0, but you must multiply the result with sign of
y, which is '-' (minus).

But you miss the fact that 0 is an *integer*, not a float, and -0
doesn't exist.
Use this code until you stop passing integers to atan2:

from math import atan2 as math_atan2
def atan2(y, x):
if (isinstance(y, int) and y == 0) or (
isinstance(x, int) and x == 0):
raise ValueError("Argument that is an integer zero can \
produce wrong results")
return math_atan2(y, x)

print atan2(-0.0, -0.0)
print atan2(-0, -0)
 
G

Guest

Serge said:
But you miss the fact that 0 is an *integer*, not a float, and -0
doesn't exist.

Yes, you are right, I completely missed that 0 is integer in python, and I
need a float.


Regards,

Vedran FuraÄ
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,053
Latest member
BrodieSola

Latest Threads

Top