Skip to content

An equation in a remainder is solved to its whole family - #1630

Merged
Rafael-SOWNet merged 1 commit into
masterfrom
a-remainder-equation-is-solved
Sep 30, 2026
Merged

Rafael-SOWNet merged 1 commit into
masterfrom
a-remainder-equation-is-solved

Conversation

@Rafael-SOWNet

@Rafael-SOWNet Rafael-SOWNet commented Sep 30, 2026 •

Copy link
Copy Markdown
Member

(x mod 4) + 1 = 3 holds for every x = 2 + 4n. On 2.5.0 it was { }, which claims there is no solution. Where the numeric fallback reached one of these equations, it listed the solutions it found in its window: (2x + 1) mod 4 = 3 was { -5, -3, -1, 1, 3, 5 }, and 7 is a solution too.

The remainder is now inverted the way the trigonometric functions are, with a whole parameter. mod is the floored remainder and takes the sign of the divisor: -1 mod 4 = 3, 5 mod (-4) = -3, 5/2 mod 2 = 1/2. So modulo a positive a it takes each value in [0, a) once per period, and modulo a negative a each value in (a, 0]. f mod a = r is therefore f = r + |a| n when r lies in that range, and has no solution when it does not. A divisor containing x, or a divisor or value that is not a number, is left unsolved.

Solve("x") of 2.5.0 now
(x mod 4) + 1 = 3 { } { 2 + 4 * n_1 }
(2x + 1) mod 4 = 3 { -5, -3, -1, 1, 3, 5 } { (3 + 4 * n_1 - 1) / 2 }
x mod (-4) = -1 { } { -1 + 4 * n_1 }
x mod 4 = 5 { } { }
x mod a = 1 { } { x : x mod a = 1 }

RemainderEquationTest checks four things:

  • every member of each family satisfies its equation, for n from -2 to 2;
  • the family contains every solution;
  • a value the remainder never takes has no solution;
  • an equation it cannot read stays unsolved.

Two tests pinned the old answer so that this change would be seen. ModulusTest.SolvingIsNotClaimed is now SolvingGivesEverySolution. The x mod 3 = 1 row of AnUnwrittenInverseIsNotTheEmptySetTest moved to RemainderEquationTest and is checked at values of n, because a membership test cannot range over a parameter.

Suite on net10.0, at 78c07506 on master 371b38e1: 14164 passed and 1 failed, the pinned ModulusTest.SolvingIsNotClaimed above. The head, 8963256a, differs from 78c07506 only in that test. At the head the 428 solver, remainder, modulus and residue tests pass, the rewritten one among them. Every target framework builds.
Gate: allocation matches the baseline on all 19 gated benchmarks.

BREAKING-CHANGES.md gains a new entry. The earlier entry for equations the solver cannot invert now lists mod only for a divisor that is not a number, and its x mod 3 = 1 row is now x mod a = 1.

Closes #1629.

Part of #180.

🤖 Generated with Claude Code

https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura

f mod a = r has one solution per period. It is now inverted the way the
trigonometric functions are, with a whole parameter: f = r + |a| n where r is
a value the floored remainder takes -- [0, a) for a positive a, (a, 0] for a
negative one -- and no solution where it is not. (x mod 4) + 1 = 3 is
{ 2 + 4 n_1 }, where 2.5.0 answered { }; (2x + 1) mod 4 = 3 is every odd
number, where 2.5.0 listed six of them. A divisor or value that is not a
number is left unsolved.

Closes #1629.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura
@Rafael-SOWNet Rafael-SOWNet added this to the 2.6.0 milestone Sep 30, 2026
@Rafael-SOWNet
Rafael-SOWNet merged commit 3cfecdd into master Sep 30, 2026
31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

An equation in a remainder, (x mod 4) + 1 = 3, is solved as the congruence it is

1 participant