classification
Title: cmath module documentation is misleading on branch cuts
Type: Stage:
Components: Documentation Versions: Python 3.10, Python 3.9, Python 3.8, Python 3.7
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: docs@python Nosy List: docs@python, mark.dickinson, rhettinger
Priority: normal Keywords:

Created on 2020-07-08 17:19 by mark.dickinson, last changed 2020-07-08 18:52 by mark.dickinson.

Messages (5)
msg373323 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2020-07-08 17:19
The documentation for the cmath module is misleading on the behaviour near branch cuts. For example, the documentation for cmath.acos says:

   Return the arc cosine of x. There are two branch cuts: One
   extends right from 1 along the real axis to ∞, continuous
   from below. The other extends left from -1 along the real
   axis to -∞, continuous from above.

That "continuous from below" and "continuous from above" language is misleading; in fact what happens on the vast majority of systems (those for which the floating-point format used is IEEE 754 binary64), if the imaginary part of x is zero, the sign of x is used to determine which side of the branch cut x lies.
msg373325 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2020-07-08 17:20
> the sign of x is used [...]

Correction: That should say "the sign of the imaginary part of x is used [...]"
msg373328 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2020-07-08 18:41
+1 for changing the language to match the actual mechanics.


> "the sign of the imaginary part of x is used [...]"

I'm trying to see where this happens.  Is this part of cmath_sqrt?

    if (z.real >= 0.) {
        r.real = s;
        r.imag = copysign(d, z.imag); 
    } else {
        r.real = d;
        r.imag = copysign(s, z.imag);
    }


> "continuous from below" and "continuous from above" 
> language is misleading;

I'm curious, is that language incorrect?  My mental image of a branch cut is a helical graph with the edge cases being continuous from above and below.  Likewise, my mental model for branch cut logic is it resolves multiple possible output values in a way preserves continuity from one side or the other.

In other words, I think about branch cuts in terms of continuity rather than sign preservation.  Is that incorrect?
msg373329 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2020-07-08 18:51
Yes, that looks like the right part of the sqrt code.

For the acos docstring, "continuous from below" implies that for any complex number z that lies exactly _on_ the branch cut, acos(z) is close to acos(w) for a nearby value w just _below_ the branch cut. But that's demonstrably not true: see the change of sign in the real part below:

>>> acos(complex(2.3, -1e-10))  # value just "below" the branch cut
(4.828045495852677e-11+1.475044781241425j)
>>> acos(complex(2.3, 0.0))  # nearby value exactly _on_ the branch cut
-1.475044781241425j

In effect, for a branch cut along the real axis, the sign of the zero in the imaginary part of the argument allows us to be continuous from both sides at once.
msg373330 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2020-07-08 18:52
> [...] see the change of sign in the real part below [...]

Grr. Stupid fingers. That should say "imaginary part", not "real part"
History
Date User Action Args
2020-07-08 18:52:27mark.dickinsonsetmessages: + msg373330
2020-07-08 18:51:22mark.dickinsonsetmessages: + msg373329
2020-07-08 18:41:21rhettingersetnosy: + rhettinger
messages: + msg373328
2020-07-08 17:23:08mark.dickinsonsetassignee: docs@python

nosy: + docs@python
components: + Documentation
versions: + Python 3.7, Python 3.8, Python 3.9, Python 3.10
2020-07-08 17:20:25mark.dickinsonsetmessages: + msg373325
2020-07-08 17:19:22mark.dickinsoncreate