Skip to content

SolveNt does not find all roots of equation #115

Description

@MomoDeve
Entity e = "arcsin(x) - x*pi/3";
Console.WriteLine(e.SolveEquation("x"));

Yes, this equation does not have analytical solution, but SolveNt() can (and should!) find all roots, as their number is finite
Output: {0}
Desired output: {-1/2, 0, 1/2}

Activity

  1. added this to the Future milestone on May 13, 2021
  2. Rafael-SOWNet commented on Aug 4, 2026

    @Rafael-SOWNet
    Member

    Still open — your case is not fixed. arcsin(x) - x*pi/3 still answers { 0 } and not { -1/2, 0, 1/2 }. Leaving this open deliberately, but recording what the investigation found, since two other defects were behind the same symptom and both are now fixed.

    Fixed, #695. The Newton grid collapsed to a single point. The shares that lay out the starting grid were computed with EDecimal's bare /, which carries no precision context and returns NaN for any quotient that does not terminate in base ten. Only step counts of the form 2^a·5^b divide exactly, so for 3, 6, 7, 9, 12, 21 and most other values every share but the first came out NaN, and with it every starting point — the grid quietly shrank to the corner where x and y are both zero. The default of 10 divides exactly, which is why it went unseen, and why asking for a finer search made the answer worse. x^3 - 2x gave all three roots at 10 steps and one at 21.

    Fixed, #696. Compiled arcsin returned the conjugate of the arcsine off the real axis — a five-year-old defect. Newton's method felt it as divergence away from a root it had been started on, which matters here because your equation is an arcsine.

    Not fixed, and the reason yours still fails. The default grid is 10 steps over a region that does not tighten around the interval where the roots live. All three of your roots lie in (-1, 1), which the grid steps over; raising StepCount finds them, and now genuinely does since #695:

    MathS.Settings.NewtonSolver.As(
        new MathS.Settings.NewtonSetting { From = (-1, -1), To = (1, 1), StepCount = (20, 20) },
        () => "arcsin(x) - x*pi/3".ToEntity().SolveEquation("x"));
    // { -1/2, 0, 1/2 }

    Making that the default is a cost decision — every solve pays for it — so it is the maintainers' call rather than mine. Three options as I see them: raise the default step count; choose the region from the expression rather than fixing it; or leave it and document the setting. Happy to implement whichever.

  3. Rafael-SOWNet commented on Aug 5, 2026

    @Rafael-SOWNet
    Member

    Now fixed, in #729, merged to master as 552e825. This supersedes the comment above.

    before after
    "arcsin(x) - x*pi/3".SolveEquation("x") { 0 } { -1/2, 0, 1/2 }
    the same via SolveNt 1 root 3 roots

    Which is the desired output in the report, exactly.

    The comment above had the diagnosis right — "the default grid is 10 steps over a region that does not tighten around the interval where the roots live" — but read it as something only a finer grid could fix. It is worth saying why that was too pessimistic.

    The grid is two-dimensional: a step count of N costs N² Newton runs but lays real starting points only (To - From) / N apart. At the default that is 2, and the three roots span one unit in total, so they shared a single starting point. Buying real-axis resolution by raising N costs N², which is what made this look expensive.

    But a sign change is a far cheaper witness of a root than a Newton run is — one evaluation against the sixty an iteration to precision 30 costs. So the real axis is now scanned at StepCount.Re * StepCount.Im points, as many as the grid has starting points, and Newton runs only from the brackets it finds. The spacing that matters for a real root becomes (To - From) / N² rather than (To - From) / N — 0.2 at the default rather than 2 — for about 2% of what the grid already spends. No setting has to change.

    One thing the comment above got wrong and worth correcting: it treated close roots as generally unreachable. They are not. x*(x - 1/2)*(x + 1/2) has roots the same 0.5 apart and gave all three even before this, because a polynomial's basins interleave across the whole plane. arcsin is the hard case because outside [-1, 1] every starting point hands it a complex value and the iteration wanders off — so the failure was specific to an expression that is real only on a small interval, not to close roots as such.

    The fix is additive and the grid is untouched. A sign change witnesses a root of odd multiplicity on an interval where the expression is real, so repeated roots (x^2 + 2x + 1) and roots off the real axis (x^2 + 1) stay the grid's to find; tests pin both. Regression tests in SolverRegressionTest.cs and NewtonGridTest.cs. Full suite green, 117-problem corpus unchanged.

  4. added theissue type on Sep 22, 2026
  5. modified the milestones: Future, 2.6.0 on Sep 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions