Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarify programming faq. #75204

Open
terryjreedy opened this issue Jul 24, 2017 · 7 comments
Open

Clarify programming faq. #75204

terryjreedy opened this issue Jul 24, 2017 · 7 comments
Labels
3.7 (EOL) end of life docs Documentation in the Doc dir type-feature A feature request or enhancement

Comments

@terryjreedy
Copy link
Member

BPO 31021
Nosy @terryjreedy, @mdickinson, @bitdancer, @marco-buttu, @wohlganger, @kgashok
PRs
  • Update programming.rst #2768
  • 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 2017-07-24.21:50:50.287>
    labels = ['type-feature', '3.7', 'docs']
    title = 'Clarify programming faq.'
    updated_at = <Date 2017-09-18.14:29:21.130>
    user = 'https://github.com/terryjreedy'

    bugs.python.org fields:

    activity = <Date 2017-09-18.14:29:21.130>
    actor = 'r.david.murray'
    assignee = 'docs@python'
    closed = False
    closed_date = None
    closer = None
    components = ['Documentation']
    creation = <Date 2017-07-24.21:50:50.287>
    creator = 'terry.reedy'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 31021
    keywords = []
    message_count = 7.0
    messages = ['299023', '299082', '299133', '299136', '299232', '302419', '302457']
    nosy_count = 7.0
    nosy_names = ['terry.reedy', 'mark.dickinson', 'r.david.murray', 'docs@python', 'marco.buttu', 'wohlganger', 'kgashok']
    pr_nums = ['2768']
    priority = 'normal'
    resolution = None
    stage = 'patch review'
    status = 'open'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue31021'
    versions = ['Python 3.6', 'Python 3.7']

    @terryjreedy
    Copy link
    Member Author

    https://docs.python.org/3/faq/programming.html#why-does-22-10-return-3
    "Why does -22 // 10 return -3?
    It’s primarily driven by the desire that i % j have the same sign as j. If you want that, and also want:

    i == (i // j) * j + (i % j)

    then integer division has to return the floor. C also requires that identity to hold, and then compilers that truncate i // j need to make i % j have the same sign as i.

    There are few real use cases for i % j when j is negative. When j is positive, there are many, and in virtually all of them it’s more useful for i % j to be >= 0. If the clock says 10 now, what did it say 200 hours ago? -190 % 12 == 2 is useful; -190 % 12 == -10 is a bug waiting to bite."

    A user noticed that '-190 % 12 == -10' is False, but would be True is '-' were inserted before '12', and posted #2768 to correct the presumed typo.

    It is not a typo, and I will close the issue, but the text as is is confusing. I propose replace "-190 % 12 == -10 is" with "if -190 % 12 were the mathematically equivalent -10, it would be" [a bug waiting to bite]. I don't like the 'bug' part because it would not be a bug, exactly, but it would be bug bait. I am not sure how to improve it though.

    @terryjreedy terryjreedy added the 3.7 (EOL) end of life label Jul 24, 2017
    @terryjreedy terryjreedy added docs Documentation in the Doc dir type-feature A feature request or enhancement labels Jul 24, 2017
    @wohlganger
    Copy link
    Mannequin

    wohlganger mannequin commented Jul 25, 2017

    Modulo is defined mathematically as the remainder of Euclidian division. I.E. a positive r where a % b = r is equivalent to a = b * x + r. I think it confuses the issue to say "-190 % 12 were the mathematical equivalent -10", when that is technically incorrect.

    Computer modulo uses truncated division, which is why -a % b != a % -b.

    "... compilers that truncate i // j need to make i % j have the same sign as i."
    i % j has the same sign as j, not i. I believe that is the typo that has caused the confusion.

    I would replace the last line with :
    "-190 % 12 == -10 is wrong according to the C definition for computer modulo arithmetic."

    @mdickinson
    Copy link
    Member

    Terry: can you clarify which part you think is potentially confusing? I'm having a hard time seeing the text as confusing, but I suspect I'm too close to the subject matter to be able to tell.

    Charles: I think you're missing the point (which does rather reinforce Terry's suggestion that this FAQ could be improved). You say:

    "-190 % 12 == -10 is wrong according to the C definition for computer modulo arithmetic."

    But that's the point: for C (specifically C99[]), -10 is the *correct result from the operation -190 % 12. And that's exactly why this is a FAQ: Python is behaving differently from many other mainstream languages (C, Java, C++, C#, ...) here, so it's useful to understand the justification for this design decision.

    For C in particular, this behaviour is mandated by section 6.5.5p6 of C99, which reads:

    When integers are divided, the result of the / operator is the algebraic
    quotient with any fractional part discarded. If the quotient a/b is
    representable, the expression (a/b)*b + a%b shall equal a.

    The first part of this forces -190 / 12 to be -15 (the result of discarding the fractional part of the true quotient -15.833....); the second then forces -190 % 12 to be (-190) - (-15)*12, which is -10.

    ([*] In C89, the rounding direction of a/b for negative a, and hence the behaviour of a%b, was left implementation defined, but same-sign-as-a appears to have been the dominant behaviour.)

    @bitdancer
    Copy link
    Member

    I think Terry and his OP are reacting to the fact that "-190 % 12 == -10" looks like it is saying that that expression is True in Python, which it is not (and that's the point).

    IMO, another issue is that "and then compilers that truncate i // j need to make i % j have the same sign as i." doesn't have enough connection in the naive reader's mind with "-190 % 12 == -10 is a bug waiting to bite" for easy comprehension.

    A potential fix to both these issues would be to say "if -190 % 12 were equal to -10 in Python (the way it is in most C programs), that would quite often be a bug waiting to happen in code using the % operator."

    @marco-buttu
    Copy link
    Mannequin

    marco-buttu mannequin commented Jul 26, 2017

    Terry thanks for opening this issue.

    The title of the FAQ makes me think that the section wants to clarify why -22 // 10 returns -3. I am a bit confused, maybe because -22//10 == -3 does not surprise me, and so I do not understand the point :(
    This seems to me a section about the module rather than floor division.

    If the section wants to clarify the floor division behavior in Python, IMHO at the beginning of the section we have to explain why -22//10 == -3 may surprise the reader (it is not clear to me, so maybe it could not surprise other readers too), and then the reasons that justify why to have -22//10 == -3.

    @kgashok
    Copy link
    Mannequin

    kgashok mannequin commented Sep 18, 2017

    So, what is the resolution on this?

    @bitdancer
    Copy link
    Member

    I think there is nothing to do here unless Mark likes my suggestion and/or someone comes up with an even better improvement.

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.7 (EOL) end of life docs Documentation in the Doc dir type-feature A feature request or enhancement
    Projects
    None yet
    Development

    No branches or pull requests

    3 participants