# [Python-ideas] checking for identity before comparing built-in objects

Mark Dickinson dickinsm at gmail.com
Fri Oct 12 21:22:37 CEST 2012

On Fri, Oct 12, 2012 at 7:42 PM, Joshua Landau
<joshua.landau.ws at gmail.com> wrote:
> Can you give me a more explicit example? When would you not *want* f(-0.0)
> to always return the result of f(0.0)? [aka, for -0.0 to warp into 0.0 on
> creation]

A few examples:

(1) In the absence of exceptions, 1 / 0.0 is +inf, while 1 / -0.0 is
-inf.  So e.g. the function exp(-exp(1/x)) has different values at
-0.0 and 0.0:

>>> from numpy import float64, exp
>>> exp(-exp(1/float64(0.0)))
0.0
>>> exp(-exp(1/float64(-0.0)))
1.0

(2) For the atan2 function, we have e.g.,

>>> from math import atan2
>>> atan2(0.0, -1.0)
3.141592653589793
>>> atan2(-0.0, -1.0)
-3.141592653589793

This gives atan2 a couple of nice invariants:  the sign of the result
always matches the sign of the first argument, and atan2(-y, x) ==
-atan2(y, x) for any (non-nan) x and y.

(3) Similarly, for complex math functions (which aren't covered by
IEEE 754, but are standardised in various other languages), it's
sometimes convenient to be able to depend on invariants like e.g.
asin(z.conj()) == asin(z).conj().  Those are only possible if -0.0 and
0.0 are distinguished;  the effect is most visible if you pick values
lying on a branch cut.

>>> from cmath import sin
>>> z = complex(2.0, 0.0)
>>> asin(z).conjugate()
(1.5707963267948966-1.3169578969248166j)
>>> asin(z.conjugate())
(1.5707963267948966-1.3169578969248166j)

You can't take that too far, though:  e.g., it would be nice if
complex multiplication had the property that (z * w).conjugate() was
always the same as z.conjugate() * w.conjugate(), but it's impossible
to keep both that invariant and the commutativity of multiplication.
(E.g., consider the result of complex(1, 1) * complex(1, -1).)

--
Mark