[HN Gopher] Python, unlike C, has the mod operator always return...
       ___________________________________________________________________
        
       Python, unlike C, has the mod operator always return a positive
       number
        
       Author : tosh
       Score  : 56 points
       Date   : 2021-12-29 20:54 UTC (2 hours ago)
        
 (HTM) web link (twitter.com)
 (TXT) w3m dump (twitter.com)
        
       | the_mitsuhiko wrote:
       | So when Rust implemented this they chose to leave the % operator
       | like in C and hide the one that is more useful for humans behind
       | `rem_euclid`. This is unfortunate but at least it exists.
       | 
       | The RFC that introduced rem_euclid: https://github.com/rust-
       | lang/rfcs/blob/master/text/2169-eucl...
        
         | masklinn wrote:
         | > So when Rust implemented this
         | 
         | For what it's worth, Python does not implement euclidean modulo
         | (it implements flooring division aka "F-definition", proposed
         | by Knuth), so Rust did not implement "this" it implemented an
         | operation which, as far as I can tell, Python doesn't have.
        
           | the_mitsuhiko wrote:
           | The difference between flooring and euclidean modulo is quite
           | irrelevant in practice for the most part. Either way resolve
           | the main issue with truncating modulo that is the issue
           | outlined in the tweet.
        
             | masklinn wrote:
             | > The difference between flooring and euclidean modulo is
             | quite irrelevant in practice for the most part.
             | 
             | It seems quite relevant as it diverges significantly from
             | the assertion put forth in the tweet: Python's remainder
             | takes the sign of the divisor. So flooring division fixes
             | the more common issue but leaves an other one present.
        
               | the_mitsuhiko wrote:
               | The tweet we're discussing:
               | 
               | > python, unlike C, had the mod operator always return a
               | positive number, even if the first argument is negative
               | 
               | That is true for Rust's rem_euclid as well:
               | https://play.rust-
               | lang.org/?version=stable&mode=debug&editio...
        
       | bodhiandpysics1 wrote:
       | When trying to understand C, it's always useful to look at what
       | the pdp-11 did. the pdp-11 didn't have a mod instruction; but its
       | div instruction can be used instead. Div can only take an even
       | numbered register as its dest. That register holds the quotient.
       | The odd numbered register numbered one greater then dest holds
       | the remainder, which for a negative number will naturally be
       | negative. so div easilly be used to calculate a mod-just ignore
       | the quotient, but you'll get a negative value.
        
       | lalaithion wrote:
       | Haskell provides two functions for integer division, div and
       | quot, and two functions for modulus, mod and rem. quot rounds
       | towards 0, and div rounds towards negative infinity. rem is
       | quot's modulus, and mod is div's modulus.
       | 
       | mod is Python's %, rem is C's %.
        
         | tialaramex wrote:
         | In Rust, the integer types [even the unsigned ones where it
         | makes no difference] provide rem_euclid() that gives you a non-
         | negative answer, whereas % is defined to have the same sign as
         | your dividend if it isn't zero.
         | 
         | Having this for unsigned types allows you to write rem_euclid()
         | if that's definitely what you meant even when you aren't sure
         | if the type you'll be using here will be signed (and thus it
         | matters) or not.
         | 
         | Unfortunately Rust's std::ops::Rem trait (the trait which
         | provides the overloadable % operator) does not offer this
         | alternative, so if all you know about a type is that you can
         | apply the modulus operator to it, you only get that operator
         | and there's no uniform way to get a Euclidean remainder
         | instead.
        
       | jinwoo68 wrote:
       | Common Lisp has both `mod` and `rem` together with their matching
       | operation `floor` and `truncate` respectively.
       | 
       | http://clhs.lisp.se/Body/f_mod_r.htm
        
       | tyingq wrote:
       | Perl can do both ways:                 $ perl -E 'say(4 % -3)'
       | -2            $ perl -E 'use integer;say(4 % -3)'       1
        
       | olliej wrote:
       | The IEEE754 remainder function even beats C in that it can return
       | a negative value even if both inputs are positive. IIRC the logic
       | that leads to this is:                   remainder(a, b)
       | n = round(a/b)         return a - n * b
       | 
       | Because it rounds to get n, n * b can be greater than a :D
       | 
       | Even more fun as the original x87 implementation preceded IEEE754
       | its remainder operation (fprem, because it's technically a
       | partial remainder) used truncation rather than rounding as that's
       | the obvious behaviour. To support the IEEE754 specification they
       | had to add fprem1 which performs a rounding operation instead.
       | Hurrah! :D
        
       | mattbee wrote:
       | This bit me the other way in JavaScript a couple of weeks back!
       | I'd been used to Ruby which never returned negative numbers, but
       | JavaScript follows C and it messed me up for 20 minutes.
        
       | Lt_Riza_Hawkeye wrote:
       | My understanding from college was that C doesn't have a modulo
       | operator, if you look at the spec (according to my professor
       | (according to my memory)) it's called the "remainder operator".
       | Modulo and remainder are not the same operation, so both python
       | and C are correct
        
         | masklinn wrote:
         | FWIW there's an entire paper on the subject of these
         | operations: https://core.ac.uk/download/pdf/187613369.pdf
         | 
         | (well a report in TOPLAS really, but that's pretty close)
         | 
         | There are technically 5 different versions of this operation,
         | though only 2 (possibly 3) are in common use. Common Lisp seems
         | to implement all of them except, somewhat oddly, the euclidean
         | version (the "actual modulo"), its mod function is instead a
         | flooring division.
         | 
         | edit: it looks like Python also follows flooring, not
         | euclidean, meaning the quotient is rounded downwards, and per
         | "a = nq + r" the remainder has the sign of the divisor:
         | >>> 5 % -2         -1         >>> divmod(5, -2)         (-3,
         | -1)
         | 
         | The C version is the "truncating" division, meaning the
         | quotient is truncated (rounded towards 0).
        
           | saurik wrote:
           | I kind of get what you are saying syntactically, but the
           | semantics are weird to me as the C version is only defined
           | for integers in the first place so saying that the operator
           | is truncating something is an awkward mental model.
        
             | masklinn wrote:
             | > I kind of get what you are saying syntactically, but the
             | semantics are weird to me as the C version is only defined
             | for integers
             | 
             | Why? Mathematically, dividing two integers yields a real.
             | If you want the result to be an integer, you need to define
             | some rounding operation on the real result to produce an
             | integer.
             | 
             | That is the source of the divergence between C and Python
             | here, C rounds by truncation (towards 0), Python rounds by
             | flooring (towards -inf).
        
               | dragonwriter wrote:
               | > Mathematically, dividing two integers yields a real
               | 
               | Rational, more specifically.
        
               | desio wrote:
               | > Mathematically, dividing two integers yields a real
               | 
               | not true. if you define 'divide' as inverse
               | multiplication over the reals then that is closer to
               | being true (zero is an integer, dividing an integer by
               | zero doesn't yield a real). in that case every real can
               | be expressed as n = a/b where a and b are integers and b
               | != 0 then yes n is a real.
               | 
               | But 'divide' could just as well be defined along the
               | lines of divisibility in number theory (the study of
               | integers) where every integer can be expressed as n = q*b
               | + r, where n,q,b,r are all integers and r >= 0 > b. then
               | you could say that n divide b = q, with r as remainder,
               | and n mod b = r. These are my preferred definition of mod
               | and integer division.
        
               | desio wrote:
               | sorry, rational, not real.
        
               | saurik wrote:
               | Oh, I'm dumb. Sorry. (I got the terms for quotient,
               | dividend, and divisor mixed up.)
        
               | masklinn wrote:
               | > Oh, I'm dumb.
               | 
               | We both know that's not true.
               | 
               | > Sorry. (I got the terms for quotient, dividend, and
               | divisor mixed up.)
               | 
               | No big, brainfarts happen.
        
           | StefanKarpinski wrote:
           | Good paper. Julia implements all versions and overloads `div`
           | and `rem` to take a rounding mode argument. It also gives
           | special names to a few of them and they come in pairs: `div`
           | & `rem`, `fld` & `mod` (`fld` stands for "floored divide" as
           | opposed to `div` which rounds towards zero). The `%` operator
           | does remainder like C, which was a tough call, but we figured
           | being compatible with C was worthwhile for people porting
           | code. It's also less useful in Julia due to default 1-based
           | indexing of arrays; for that there is a `mod1` function that
           | returns a value between 1 and n.
        
           | bee_rider wrote:
           | Somewhere out there in the universe, there's an nightmare
           | that starts with "Well, zero is kind of an unusual number, so
           | for safety sake we've defined our division to always round
           | away from zero. This resulted in an interesting mod
           | operation..."
        
           | aix1 wrote:
           | Also this TR: https://www.microsoft.com/en-us/research/wp-
           | content/uploads/...
        
           | [deleted]
        
         | ollien wrote:
         | Yep. I remember that for my first C assignment in college we
         | had to write a calendar, and leap year calculations needed
         | modulos. I remember distinctly that I tore my hair out trying
         | to figure this out, especially because I was prototyping my
         | math in Python. I eventually resolved that I needed to
         | constantly ensure my sum was > 0 (by adding my modulo base).
        
           | Normal_gaussian wrote:
           | That will only work for cases where a >= -b. For the more
           | general case:
           | 
           | > a mod b = ((a % b) + b) % b
           | 
           | The first remainder bounds it to -b < x < b. Then adding b
           | goes to 0 < x < 2b. Then the second remainder gets th desired
           | 0 <= x < b.
           | 
           | This will not work for b > max_int / 2 (solution in that case
           | is much mkre language dependent)
        
         | eesmith wrote:
         | K&R "The C Programming Language" (1978), p.37:
         | 
         | > The binary arithmetic operators are +, -, *, /, and the
         | modulus operator %.
         | 
         | https://archive.org/details/TheCProgrammingLanguageFirstEdit...
         | 
         | At least, that was the C reference I used in college.
        
           | klodolph wrote:
           | You'll only find that terminology in K&R. The C specification
           | only uses "modulo" to refer to the behavior of unsigned
           | numbers, and uses "remainder" to refer to the behavior of %.
           | This is true of at least several versions of the C standard
           | dating back to 1999, I don't have the C90 spec handy.
        
             | eesmith wrote:
             | Indeed!
             | 
             | The draft version "X3.???-1988" at
             | https://web.archive.org/web/20161223125339/http://flash-
             | gord... (linked-to from Wikipedia) has:
             | 
             | > % modulus operator: 3.3.5
             | 
             | which seems off to a good start for K&R, but then also has:
             | 
             | > remainder operator, %, 3.3.5
             | 
             | and 3.3.5 says "the result of the % operator is the
             | remainder" -- not a whiff of a modulus present there.
             | 
             | Thanks!
        
             | somerando7 wrote:
             | People generally watch tutorials, read programming books,
             | blogs, stackoverflow to learn programming, not the standard
             | of a programming language.
             | 
             | You will find "modulus operator" to refer to % in C in all
             | of the above (other than the standard).
        
               | charcircuit wrote:
               | I think there is the same problem with the conditional
               | operator "?" which a ton of resources name as the ternary
               | operator.
               | 
               | edit: tertiary -> ternary
        
               | eesmith wrote:
               | I know it as "the ternary operator" (used that way in K&R
               | at https://archive.org/details/TheCProgrammingLanguageFir
               | stEdit...), and until about 2 minutes ago had never heard
               | it as "the conditional operator" - even though that's how
               | the spec describes it!
        
               | klodolph wrote:
               | That is what most people do... which is why those of us
               | who write tutorials, write programming books, write blog
               | posts, and write Stack Overflow answers have a
               | responsibility to go to the source.
               | 
               | The more something gets repeated from person to person,
               | the higher chance that somewhere in that chain, somebody
               | screwed up. That's why people like professors, people who
               | run YouTube programming channels, people who answer C
               | questions on Stack Overflow, etc. should generally strive
               | to cut down the number of links in the chain.
        
               | xboxnolifes wrote:
               | The fact that tutorials teach incorrect knowledge does
               | not make the knowledge correct.
        
           | tialaramex wrote:
           | This is also exactly what the ANSI ("Second edition") K&R
           | book I have in front of me says.
           | 
           | It goes on to say: "x % y produces the remainder when x is
           | divided by y" and that "the sign of the result for % are
           | machine-dependent for negative operands, as is the action
           | taken on overflow or underflow".
        
         | kazinator wrote:
         | C only pinned this down in C99. In C90, the sign of the
         | remainder was implementation-defined in those cases in
         | question.
        
         | [deleted]
        
       | superjan wrote:
       | Careful what you wish for. What should -7 / 2 return? -3 kind of
       | makes sense, because 7/2 is 3.
       | 
       | It also desirable to have the remainder consistent with the
       | result of division, such that x = d*r + mod, where r is the
       | result of division. Combine that with the above requires negative
       | mods.
        
         | naniwaduni wrote:
         | It's highly desirable for -7/2 to equal -4, since this lets
         | integer division by powers of two be exactly equivalent to a
         | two's complement arithmetic right shift.
        
         | masklinn wrote:
         | > Careful what you wish for. What should -7 / 2 return? -3 kind
         | of makes sense, because 7/2 is 3.
         | 
         | -4 also makes sense.
         | 
         | > It also desirable to have the remainder consistent with the
         | result of division, such that x = d*r + mod, where r is the
         | result of division. Combine that with the above requires
         | negative mods.
         | 
         | Python's behaviour is consistent with that definition:
         | >>> divmod(-7, 2)         (-4, 1)
         | 
         | -7 = -4 * 2 + 1
        
       | tialaramex wrote:
       | Note that, of course, zero is not "a positive number" since we're
       | operating on the integers here and "signed" zero isn't a thing
       | for either C or Python integers, but I think we all know what
       | Carmack meant here.
        
       | ufo wrote:
       | What other languages also do this? I know Lua is one.
        
         | okl wrote:
         | Wikipedia has got a list:
         | https://en.wikipedia.org/wiki/Modulo_operation#In_programmin...
        
           | masklinn wrote:
           | To explain the key for those who don't want to read the
           | article: "truncated" is C's behaviour, "floored" is Python's.
        
         | mfashby wrote:
         | golang unfortunately also produces negative results from the
         | mod operator
         | 
         | It was quite confusing trying to port this diff algorithm
         | https://blog.robertelder.org/diff-algorithm/
        
       | waynecochran wrote:
       | Doesn't C just do whatever the underlying hardware does for
       | modulo w negative numbers? I have always worked around this by
       | adding N to numerator:                   r = (i + N) % N
       | 
       | which handles cases where i >= -N which is mostly what I run into
       | when i is negative.
       | 
       | I remember Ada having two different operators REM and MOD which I
       | think is the best language choice.
        
         | [deleted]
        
         | masklinn wrote:
         | > I remember Ada having two different operators REM and MOD
         | which I think is the best language choice.
         | 
         | According to Boute 1992,
         | 
         | > The Ada Reference Manual complements integer division (/)
         | with two functions _mod_ and _rem_. The first of these violates
         | the division rule
         | 
         | so it doesn't so much have two different operators as one
         | operator and one broken mess, and its one operator is the
         | truncating division (C-style).
         | 
         | Also a quick check of the Hyperspec (or, again, Boute 1992)
         | shows there are not two but _4_ definitions based on rounding
         | quotients, I think none of which  "always returns a positive
         | number" (which Python also does not do, incidentally).
         | 
         | There is a 5th definition, which Boute 1992 champions, for
         | which the property asserted in the title holds.
        
         | pyjarrett wrote:
         | Ada mod takes the sign of the second operand.
         | 
         | I wouldn't even bother with this, I'd just use a modular type
         | (i.e. unsigned).                   with Ada.Text_IO;
         | procedure Main is            -- Modular type (unsigned) which
         | can take values of [0, 15].            type Nibble is mod 16;
         | Value : Nibble := 0;         begin            -- Prints 0 3 6 9
         | 12 15 2 5 8 11 14 1 4 7 10 13 ...            for I in 0 .. 63
         | loop               Ada.Text_IO.Put_Line (Value'Image);
         | Value := Value + 3;            end loop;         end Main;
         | 
         | Then make that type the index into my circular buffer and then
         | I never need to worry about it.                   type
         | Circular_Buffer is array (Nibble) of Integer;         Buffer :
         | Circular_Buffer;
        
         | Someone wrote:
         | In C this used to be "implementation defined". That changed in
         | C99 and C++11 (https://en.wikipedia.org/wiki/Modulo_operation#I
         | n_programmin..., note c)
         | 
         | Nitpick: it never was "just do whatever the underlying hardware
         | does". C standards try hard to avoid mentioning hardware at all
         | (and, as far as I know, succeed at that), and there's plenty of
         | hardware that doesn't do _mod_ in hardware, yet supports it in
         | C.
        
           | gmiller123456 wrote:
           | You make a good point, but I think he was more generalizing
           | to actual implementations of C compilers. And that does align
           | with my experience.
        
           | alerighi wrote:
           | In C there are ton of things that are hardware dependent. For
           | example the size of every data type is not specified, or the
           | fact that char is signed or unsigned, the representation of
           | signed integers (tough I don't think there still exist a
           | platform that doesn't use 2's complement), ad a ton of other
           | things.
        
           | beervirus wrote:
        
         | kevin_thibedeau wrote:
         | > I remember Ada having two different operators REM and MOD
         | 
         | Taken from Modula-2.
        
         | MobiusHorizons wrote:
         | Btw that code won't work in the general case (where i could be
         | less than -N). For that case you should probably do
         | 
         | r = ((i % N) + N) % N
         | 
         | There may be faster ways, but that should at least be correct
         | for all inputs.
        
           | klodolph wrote:
           | Incorrect for N > INT_MAX/2.
        
         | scotty79 wrote:
         | Not if i is less than -N. Modulo operator that wraps -1 to N-1
         | would be waay better.
        
       ___________________________________________________________________
       (page generated 2021-12-29 23:00 UTC)