GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — cmath module documentation is misleading on branch cuts · Issue #85417 · python/cpython

cmath module documentation is misleading on branch cuts #85417

New issue
Copy link
New issue
Copy link
Closed
#102046
Closed
cmath module documentation is misleading on branch cuts#85417
#102046
Copy link
Assignees
mdickinson
Labels
3.10 (EOL)end of lifeend of life3.7 (EOL)end of lifeend of life3.8 (EOL)end of lifeend of life3.9 (EOL)end of lifeend of lifedocsDocumentation in the Doc dirDocumentation in the Doc dir

Description

@mdickinson
mdickinson
opened on Jul 8, 2020
Issue body actions
BPO 41245
Nosy @rhettinger, @mdickinson

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields:

assignee = None
closed_at = None
created_at = <Date 2020-07-08.17:19:22.882>
labels = ['3.7', '3.8', '3.9', '3.10', 'docs']
title = 'cmath module documentation is misleading on branch cuts'
updated_at = <Date 2020-07-08.18:52:27.472>
user = 'https://github.com/mdickinson'

bugs.python.org fields:

activity = <Date 2020-07-08.18:52:27.472>
actor = 'mark.dickinson'
assignee = 'docs@python'
closed = False
closed_date = None
closer = None
components = ['Documentation']
creation = <Date 2020-07-08.17:19:22.882>
creator = 'mark.dickinson'
dependencies = []
files = []
hgrepos = []
issue_num = 41245
keywords = []
message_count = 5.0
messages = ['373323', '373325', '373328', '373329', '373330']
nosy_count = 3.0
nosy_names = ['rhettinger', 'mark.dickinson', 'docs@python']
pr_nums = []
priority = 'normal'
resolution = None
stage = None
status = 'open'
superseder = None
type = None
url = 'https://bugs.python.org/issue41245'
versions = ['Python 3.7', 'Python 3.8', 'Python 3.9', 'Python 3.10']

Linked PRs

  • gh-85417: Clarify behaviour on branch cuts in cmath module #102046
  • gh-85417: remove misleaning remarks about branch cuts for platforms without signed zero #102047
  • [3.10] gh-85417: Clarify behaviour on branch cuts in cmath module (GH-102046) #102275
  • [3.11] gh-85417: Clarify behaviour on branch cuts in cmath module (GH-102046) #102276

Activity

  1. mdickinson commented on Jul 8, 2020

    @mdickinson
    mdickinson
    on Jul 8, 2020
    MemberAuthor
    More actions

    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.

  2. mdickinson commented on Jul 8, 2020

    @mdickinson
    mdickinson
    on Jul 8, 2020
    MemberAuthor
    More actions

    the sign of x is used [...]

    Correction: That should say "the sign of the imaginary part of x is used [...]"

  3. mdickinson
    added
    docsDocumentation in the Doc dirDocumentation in the Doc dir
    3.7 (EOL)end of lifeend of life
    3.8 (EOL)end of lifeend of life
    3.9 (EOL)end of lifeend of life
    3.10 (EOL)end of lifeend of life
    on Jul 8, 2020
  4. mdickinson
    assigned
    docspython
    on Jul 8, 2020
  5. rhettinger commented on Jul 8, 2020

    @rhettinger
    rhettinger
    on Jul 8, 2020
    Contributor
    More actions

    +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?

  6. mdickinson commented on Jul 8, 2020

    @mdickinson
    mdickinson
    on Jul 8, 2020
    MemberAuthor
    More actions

    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.

  7. mdickinson commented on Jul 8, 2020

    @mdickinson
    mdickinson
    on Jul 8, 2020
    MemberAuthor
    More actions

    [...] see the change of sign in the real part below [...]

    Grr. Stupid fingers. That should say "imaginary part", not "real part"

  8. ezio-melotti
    transferred this issue fromon Apr 10, 2022
  9. skirpichev commented on Feb 18, 2023

    @skirpichev
    skirpichev
    on Feb 18, 2023
    Member
    More actions

    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.

    @mdickinson, it seems that some MP libraries use different convention, e.g.:

    >>> from mpmath import acos
    >>> acos(2 + 1e-10j)
    mpc(real='5.773502691896258e-11', imag='-1.3169578969248168')
    >>> acos(complex(2))
    mpc(real='0.0', imag='1.3169578969248168')
    >>> acos(2 - 1e-10j)
    mpc(real='5.773502691896258e-11', imag='1.3169578969248168')
    >>> acos(-2 + 1e-10j)
    mpc(real='3.1415926535320584', imag='-1.3169578969248168')
    >>> acos(complex(-2))
    mpc(real='3.1415926535897931', imag='-1.3169578969248168')
    >>> acos(-2 - 1e-10j)
    mpc(real='3.1415926535320584', imag='1.3169578969248168')

    Ditto Mathematica. That's exactly "continuous from below ... and ... continuous from above." from the cmath docs.

    Shouldn't we adjust the implementation instead?

  10. mdickinson commented on Feb 18, 2023

    @mdickinson
    mdickinson
    on Feb 18, 2023
    MemberAuthor
    More actions

    Shouldn't we adjust the implementation instead?

    Definitely not! The implementation was very deliberately written this way. It's based on Kahan's "Branch Cuts for Complex Elementary Functions" paper, and it agrees with C99's Annex G and many other languages.

  11. skirpichev commented on Feb 19, 2023

    @skirpichev
    skirpichev
    on Feb 19, 2023
    Member
    More actions

    Ok, I see. Looks a bit surprising for complex analysis, but I see why it does make sense with signed zero floating-point arithmetics.

    But it seems, that the current docs contains (since 2008) a note ("On platforms with hardware and system-level support for signed zeros, functions involving branch cuts are continuous on both sides of the branch cut: the sign of the zero distinguishes one side of the branch cut from the other. On platforms that do not support signed zeros the continuity is as specified below."). With this remark in mind - the acos docs seems correct, isn't?

    Edit: So far, after 5ea052b - IEEE 754 support is a strict requirement. IIUIC, we can just leave the above remark (or like C11's Annex G "The functions are continuous onto both sides of their branch cuts, taking into account the sign of
    zero. For example, csqrt (−2±i0) = ±i sqrt(2).") and skip all "continuous from" notes for all functions. Does it make sense as pr?

  12. mdickinson commented on Feb 19, 2023

    @mdickinson
    mdickinson
    on Feb 19, 2023
    MemberAuthor
    More actions

    the current docs contains (since 2008) a note [...]

    Indeed - I wrote that note. :-)

    the acos docs seems correct, isn't

    Technically correct, yes, but I think unhelpful in its current form: it relies on someone reading the documentation also reading that note, rather than just reading the direct description of the relevant function.

    It's been almost 15 years since I wrote that note, and in those 15 years IEEE 754 has only increased its overwhelming dominance. The descriptions should describe what happens on the 100% of systems whose C double has signed zeros, rather than describing the behaviour on the 0% of systems where the C double doesn't support signed zeros. We could then update the note to note what happens on systems where the double doesn't support signed zeros, or we could just throw it out altogether. I'd probably go for the latter - the non-signed-zero systems are pretty much entirely hypothetical at this point.

  13. mdickinson
    added a commit that references this issue on Feb 19, 2023

    pythongh-85417: Clarify behaviour on branch cuts in cmath module

    ed5c0a5
  14. mdickinson
    self-assigned this
    on Feb 19, 2023
  15. skirpichev
    added a commit that references this issue on Feb 19, 2023

    pythongh-85417: remove misleaning remarks about branch cuts for platf…

    15170d1
  16. mdickinson
    closed this as completedin #102046on Feb 19, 2023
  17. mdickinson
    added a commit that references this issue on Feb 19, 2023

    gh-85417: Clarify behaviour on branch cuts in cmath module (#102046)

    b513c46
  18. jaraco
    added a commit that references this issue on Feb 20, 2023

    pythongh-85417: Clarify behaviour on branch cuts in cmath module (pyt…

    3c6360e
  19. carljm
    added 2 commits that reference this issue on Feb 20, 2023

    Merge branch 'main' into inlinecomp2

    9f0fc5b

    Merge branch 'main' into inlinecomp

    544b30c
  20. miss-islington
    added 2 commits that reference this issue on Feb 26, 2023

    pythongh-85417: Clarify behaviour on branch cuts in cmath module (pyt…

    03491ad

    pythongh-85417: Clarify behaviour on branch cuts in cmath module (pyt…

    c95dd17
  21. mdickinson
    added 2 commits that reference this issue on Feb 26, 2023

    [3.10] gh-85417: Clarify behaviour on branch cuts in cmath module (GH…

    601c9db

    [3.11] gh-85417: Clarify behaviour on branch cuts in cmath module (GH…

    626f471
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

  • @mdickinson
    mdickinson

Labels

3.10 (EOL)end of lifeend of life3.7 (EOL)end of lifeend of life3.8 (EOL)end of lifeend of life3.9 (EOL)end of lifeend of lifedocsDocumentation in the Doc dirDocumentation in the Doc dir

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    You are visitor 01402503 — GeezerVison does not store the pages you look up.
    Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.