9 ms·
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 calle
by Lt_Riza_Hawkeye 5y ago
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 5y agoFWIW there's an entire paper on the subject of these operations: https://core.ac.uk/download/pdf/187613369.pdf 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).
- aix1 5y agoAlso this TR: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/divmodnote-letter.pdf https://www.microsoft.com/en-us/research/wp-content/uploads/...
- cormacrelf 5y agoThis one is very concise, great as a reference, you can remind yourself of which negatives go where in an instant.
- saurik 5y agoI 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 5y ago> 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).
- saurik 5y agoOh, I'm dumb. Sorry. (I got the terms for quotient, dividend, and divisor mixed up.)
- masklinn 5y ago> 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.
- DonHopkins 5y agoJust don't divide by zero. That's how you get black holes!
- dragonwriter 5y ago> Mathematically, dividing two integers yields a real Rational, more specifically.
- desio 5y ago> 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.
- deleted 5y ago[deleted]
- StefanKarpinski 5y agoGood paper—it was the primary source we looked at when implementing these operations in Julia. Specifically, 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.
- thaumasiotes 5y ago> 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. After thinking about this, what I really want is a way to access an array with an unadjusted number and tell the array to do whatever modulizing is necessary. e.g. instead of a[small] a[mod1(big)] I'd like to have something more like a{small} a[big]
- bee_rider 5y agoHmm. This means we'd have to do mod every time we accessed an array which seems not great, right? But probably it could be optimized away for the common/easy cases.
- dmurray 5y agoJulia already has bounds checking at runtime on array access, so you could do the mod operation only if the bounds check fails. But I don't get how this would practically work. Would each array have a preferred n that is used for the mod operation? For most situations where that makes sense, using a 2d array seems more logical.
- 5y ago
- bee_rider 5y agoSomewhere 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..."
- Supermancho 5y agoPonylang.io - There is a similar operation (toward zero) https://stdlib.ponylang.io/builtin-Integer/#div_unsafe https://stdlib.ponylang.io/builtin-Integer/#div_unsafe and, in Ponylang, i/0 usually results in 0.
- staticassertion 5y agoI think this is a bit different. Pony's div is total, and in order to be total div by 0 is 0, which is not a particularly absurd idea. That said, I do feel that Pony should have added a 'panic' concept and then forced actors to handle panics, but that's me.
- deleted 5y ago[deleted]
- kibwen 5y ago> which is not a particularly absurd idea It's not completely untenable, but it's still kinda janky. I've never heard of any mathematical argument that justifies division by zero yielding 0; contrast 0^0, which at least has an argument for yielding 1: http://mathscitech.org/articles/zero-to-zero-power http://mathscitech.org/articles/zero-to-zero-power
- duskwuff 5y ago> I've never heard of any mathematical argument that justifies division by zero yielding 0 0/x = 0 for all x except zero; defining 0/0=0 removes that exception.
- deleted 5y ago[deleted]
- eesmith 5y agoK&R "The C Programming Language" (1978), p.37: > The binary arithmetic operators are +, -, *, /, and the modulus operator %. https://archive.org/details/TheCProgrammingLanguageFirstEdition/page/n43/mode/2up?q=modulus https://archive.org/details/TheCProgrammingLanguageFirstEdit... At least, that was the C reference I used in college.
- tialaramex 5y agoThis 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".
- klodolph 5y agoYou'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.
- somerando7 5y agoPeople 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 5y agoI think there is the same problem with the conditional operator "?" which a ton of resources name as the ternary operator. edit: tertiary -> ternary
- eesmith 5y agoI know it as "the ternary operator" (used that way in K&R at https://archive.org/details/TheCProgrammingLanguageFirstEdition/page/n53/mode/2up?q=ternary https://archive.org/details/TheCProgrammingLanguageFirstEdit...), and until about 2 minutes ago had never heard it as "the conditional operator" - even though that's how the spec describes it!
- deleted 5y ago[deleted]
- ollien 5y agoYep. 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 5y agoThat 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)
- yaur 5y agoWhat's the case where the C % operator behaves in an unexpected way? I've been wiring software for about 20 years and can count zero hands the number of times someone I've worked with has had to worry about how the modulo operator behaves with negative numbers.
- housecarpenter 5y agoAn example would be if you want to find the month corresponding to a timestamp. The obvious thing to do is to scale the timestamp so that it gives you the number of months after the epoch, take that number % 12, and map 0 to January, 1 to February, etc. (assuming the epoch is in January). But if you try to do that with a timestamp from before the epoch, you'll end up with 0 for January, -11 for February, -10 for March, etc.
- yaur 5y agoNo. If your software has to deal with dates from before 1970 "seconds since the epoch" is not a reasonable choice for a time unit.
- kazinator 5y agoC only pinned this down in C99. In C90, the sign of the remainder was implementation-defined in those cases in question.
- LAC-Tech 5y agoSo only 22 years ago :) Are C programmers still using C89 and C90?
- _3u10 5y agoYes, Linux uses gnu89
- kazinator 5y ago.. and that allows plenty of silently accepted extensions, including variable-length arrays, which were in GNU C long before C99. It seems that only GCC 4.3 added the -Wvla option to unbundle the diagnosis of the presence of VLA's from -pedantic. Now you can write in gnu89, while banishing VLA's from your code base, if you're so inclined.
- opencl 5y agoThere are a lot of C compilers out there, and many of them have not implemented all of C99. Microsoft started to add C99 features in MSVC2013 and still doesn't support the whole spec. The C compilers supplied by microcontroller vendors in particular are often, to put it charitably, not great at conforming with the latest standards.
- jlarocco 5y agoIIRC, Microsoft has publicly stated that they only plan to implement the parts of C99 required by the C++ standards. EDIT: Fact checking myself, I found [1], so apparently they've decided to start adding C11 and C17. C99 support isn't entirely clear, though. [1] https://devblogs.microsoft.com/cppblog/c11-and-c17-standard-support-arriving-in-msvc/ https://devblogs.microsoft.com/cppblog/c11-and-c17-standard-...
- thaumasiotes 5y ago> Modulo and remainder are not the same operation, so both python and C are correct That just makes C look worse. Remainders are always nonnegative, as specified in the Division Algorithm [note that the Division Algorithm is the name of a theorem, not an algorithm]. https://en.wikipedia.org/wiki/Euclidean_division https://en.wikipedia.org/wiki/Euclidean_division Also, I'm not aware of a definition of "modulo" other than "remainder". Where are you getting the idea that they're different? For example, https://en.wikipedia.org/wiki/Modulo_operation https://en.wikipedia.org/wiki/Modulo_operation explicitly defines "modulo" as "remainder".