Repository navigation
Add a modulus node (#402, #618) - #703
Conversation
There was no remainder in the library at all: `%` was a parse error and there was nothing to call. Adds `Modf`, with the parser, `MathS.Mod`, the `%` operator on `Entity`, evaluation, simplification, differentiation, limits, both compilers, LaTeX, SymPy export and the F# `%`, which needs no wrapper code of its own since F# resolves it through `op_Modulus`. The remainder takes the sign of the dividend, which is the truncated convention: the one C# has, and the one the arbitrary-precision arithmetic underneath already implements. (-7) % 3 is -1, not 2. `%` binds as tightly as `*` and `/` and associates to the left, again as in C#. Three places where less is claimed than could be: The derivative is the dividend's own where the divisor does not depend on the variable, and is left alone where it does. a % b is a - b*floor(a/b), and there is no floor node here, so writing the general case would mean writing something wrong at the jumps. A limit is answered where the remainder is continuous and left unevaluated at the jumps, where the dividend reaches a non-zero multiple of the divisor. The value at a jump is one of the two one-sided limits and neither the other nor the two-sided one. Zero is not a jump: the remainder takes the dividend's sign, so x % 3 is x on either side of it. Inverting is not implemented, so solving answers with no roots rather than with wrong ones -- x % a = v has one solution per period and wants an integer parameter, as the trigonometric inversions have. The stack machine carries every value as a complex number and answers NaN where either part is not real, which is the same refusal the interpreter makes by leaving a complex remainder unevaluated. There is no one remainder of a complex number by another. The parser files under Core/Antlr are regenerated by the project's own antlr_rerun script; the churn is one new token shifting every index after it. 42 new C# tests, 3 new F# tests; suite 4503 + 130 passed, 0 failed; corpus unchanged at 111/117 with 0 wrong.
|
Is preserving negative dividend mathematically correct as opposed to the Euclidean remainer? Also - the parser should accept |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #703 +/- ##
==========================================
+ Coverage 80.99% 81.62% +0.62%
==========================================
Files 155 160 +5
Lines 13687 13882 +195
Branches 1957 2344 +387
==========================================
+ Hits 11086 11331 +245
+ Misses 1990 1892 -98
- Partials 611 659 +48 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Two corrections from review, both of which the AGENTS.md rule decides against what was here: mathematical convention outranks the programming one. The remainder now takes the sign of the divisor -- the floored a - b*floor(a/b) -- so (-7) mod 3 is 2 and 7 mod (-3) is -2. This is the convention under which the residues modulo n are the numbers from 0 to n - 1, which is the point of the operation in number theory, and it is what the other systems answer: SymPy, Mathematica and Maxima all give 2. Checked against SymPy 1.14 on all four sign pairs rather than asserted. The truncated convention that was here is C's, and C's % is an operation on machine integers. Both compilers follow. The stack machine converts by adding one divisor where the signs disagree; the Linq compiler emits ((a % b) + b) % b, which is the shortest expression that turns the runtime's truncation into the floored answer for every pair of signs. The parser now spells it `mod`, and `%` is left alone so that it stays free to mean percent, which is what it means in mathematical writing. The stringizer follows, so the round trip holds. The C# and F# `%` operator on Entity stays -- it is the language's operator over a different type, and #402 asks for it -- and says in its documentation that it is not int's. Suite 4504 passed, 0 failed.
|
Both points taken, and the first one you are right about — I had reached for the programmer's convention, not the mathematician's. Pushed as The conventionI checked rather than argued. SymPy 1.14, all four sign pairs:
So it is now the floored remainder, Both compilers follow: the stack machine adds one divisor where the signs disagree, and the Linq compiler emits The spelling
I kept the Two things I found while doing this, neither of them mine to fix hereThe numeric
Three types, three behaviours, one There is no syntax reference in the repository. The grammar is the only statement of what the language accepts, and it is ANTLR source. That is part of why Suite |
|
@Happypig375 both of your points are implemented and verified, so I am merging this — but the second half of my reply was an offer rather than a rhetorical question, and it still stands. Done: the remainder is floored and takes the sign of the divisor, checked against SymPy 1.14 on all four sign pairs; the parser spells it Still open, and yours to decide: I kept the One consequence now that #709 has landed: the three numeric |
There was no remainder in the library at all —
%was a parse error and there was nothing to call. #402 asks forMathS.Modulusand for%in the F# wrapper; #618 asks how to get a remainder and is told there is no operator for it.Adds
Modfand takes it through everything in the project's ownAddingNode.cschecklist: parser,MathS.Mod, the%operator onEntity, evaluation, simplification, differentiation, limits, both compilers, stringize, LaTeX, SymPy export, sort hash, codomain, substitution and inversion.Conventions, both pinned by tests
The remainder takes the sign of the dividend — the truncated convention, which is what C# does and what the arbitrary-precision arithmetic underneath already implements.
(-7) % 3is -1, not 2. The Euclidean convention is the other common choice and the two disagree on every negative dividend, so the tests state it rather than leave it to be discovered.MathS.Moddocuments how to get the non-negative form.%binds as tightly as*and/and associates left, again as in C#. There is a test per case:2 * 7 % 3,7 % 3 * 2,12 / 4 % 2,1 + 7 % 3,2 ^ 3 % 3,-7 % 3, each asserted against the value C# itself computes for the same source.Three places where it deliberately claims less than it could
a % bisa - b*floor(a/b); there is no floor node here, so the general case could only be written as something that is wrong at the jumps.x % 3isxon either side of 0 and passes through continuously.x % a = vhas one solution per period and wants an integer parameter, as the trigonometric inversions have. There is a test pinning the empty answer so that whoever writes it sees the change.Complex arguments
There is no one remainder of a complex number by another — which multiple of the divisor to subtract is a choice, and rounding the quotient to the nearest Gaussian integer and truncating it disagree. The interpreter declines and leaves
a % bunevaluated. The stack machine carries every value as aSystem.Numerics.Complexand has no way to return an unevaluated node, so it answers NaN, which says the same thing. Tested both ways.The Linq compiler uses
Expression.Moduloand is not widened to double the way division is: the remainder of two integers is an integer and widening would only lose that. Both compilers are tested against the interpreter on the same inputs.Simplification
a % a→ 0,0 % a→ 0 (both carrying the node's own "divisor is not zero" condition),(a % b) % b→a % b, and numeric evaluation.x % 1is deliberately not reduced — that is 0 only for wholex, and2.5 % 1is 0.5, so it stays unless the dividend is known to be an integer.Measurements
Failed: 0, Passed: 4503, Skipped: 14, Total: 4517andFailed: 0, Passed: 130for F#.AngouriMath.FSharpandAngouriMath.Terminal.Libboth build.A note on the diff size
Sources/AngouriMath/Core/Antlr/*is regenerated by the project's ownSources/Utils/antlr_rerun.bat(ANTLR 4.13.1, then the post-processor that makes the generated classes internal). One new token shifts every token index after it, which is where the ~1500 changed lines come from. The hand-written change is the single'%'alternative inmult_expressioninAngouriMath.g.