Python Arithmetic Problem

Guilty as charged. I’m not proud of what I did. https://github.com/python/cpython/blob/11fc030b6f9294030f0baa15f3bd4e2293e260e4/Lib/decimal.py#L5528

a--n//a>>1 is (a - (-n//a)) >> 1 right? That is to say, it’s the average of a and n//a, but with ceil rather than floor division? Honestly, for something that’s potentially in a tight loop, that’s a fairly elegant - if a little odd to read - way to do it.

I was thinking of this as the shortest Python obfuscated code contest winner. :smirk:

1 Like

Condition is: “If the division is not even, one of the groups may have fewer members than specified.” So only divmod is required. remainder is number of (fewer) students than specified in one group.

I don’t know what you are saying.

Could you add parenthesis emphasizing the order of operations of how Python interprets it?

Left as an exercise for the reader? :man_shrugging:

All kidding aside, it’s probably worth a few minutes spent with the operator precedence table in the reference manual to see if you can figure it out.

Ugh, I actually dislike that a--n//a>>1. I can never remember the precedence between shift operators and others. I’d write that as (a-n//-a)>>1. Moved the - because a is much smaller than n and thus negates faster, no? (Not that it matters much).

Here’s a way of persuading Python itself to add those parens (by monkeypatching the ast module to always add parentheses in ast.unparse):

Python 3.11.3 (main, Apr  8 2023, 01:16:41) [Clang 14.0.0 (clang-1400.0.29.102)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import ast
>>> ast._Unparser.require_parens = lambda self, precedence, node: self.delimit("(", ")")
>>> ast.unparse(ast.parse("~-0-~ x//y", mode="eval"))
'((~(-0)) - ((~x) // y))'
>>> ast.unparse(ast.parse("--0-- x//y", mode="eval"))
'((-(-0)) - ((-x) // y))'
1 Like

Useful. I actually tried searching exactly for some tool that would do this.

Are the two -- in front of the 0 only cosmetic, or are they there to prevent, I don’t know the “operator” from being ambiguous if there are stuff in front: stuff --0-- x // y.

Just cosmetic/aesthetic: many (but not all) operators in Python look the same when turned upside down, and that property should clearly be high on the list of design considerations.

If you’re concerned about the time cost of the negation, n isn’t used in its nonnegated form anywhere, so it could be negated once before the loop.

1 Like