Skip to content

Convergence and iteration limits

@ac-kit/math-analysisPortable

import { ConvergenceOptions, ConvergenceResult, ConvergenceError } from "@ac-kit/math-analysis";

ConvergenceOptions is the same shape on every iterative routine in the package — tolerance, maxIterations and an AbortSignal. Every field is optional and every routine documents its own defaults.

What tolerance is measured against is deliberately not fixed here, because it genuinely differs: for bisect it is the width of the remaining bracket, for continuedFractionEval it is the relative size of the last update. Each function states it on its own parameter, where you will be reading it.

A routine that runs out of iterations still has a best-so-far answer. What it does with that answer depends on whether you would be able to tell:

  • It returns a ConvergenceResult. The value comes back alongside converged: false and the iteration count. Check the flag — an unconverged value looks exactly like a converged one.
  • It returns a bare number, and throws ConvergenceError. There is nowhere to put the flag, so silence would be indistinguishable from success. The error names the routine and how many iterations it spent.
Running out of iterations

Every iterative routine here takes a maxIterations budget, and the ones that can report their own progress return a ConvergenceResult rather than throwing. Each point is one budget: the height is how far the answer still is from φ, and the red section is where the routine gave up before meeting its tolerance. The value it returned there is a real best-effort estimate — it is just not the answer.

math-analysis/convergence-budget.example.ts
const budgets = Array.from(range(1, budget + 1));
const errors = budgets.map((maxIterations) => {
const result = continuedFractionEval(GOLDEN_RATIO, { maxIterations });
// `converged` is what distinguishes "this is the answer" from "this is
// where I had to stop". Returning the value bare would hide the difference.
return result.converged
? Number.NaN
: Math.max(Math.abs(result.value - PHI), Number.MIN_VALUE);
});

Catching a ConvergenceError is rarely the right response. It almost always means the input was outside the regime the routine covers, or that maxIterations was set too low for the accuracy asked of it — raise one, or loosen the other.

Passing a signal aborts the iteration. It is checked once per iteration rather than inside the work an iteration does, so the cost of supporting it is bounded by maxIterations and not by the integrand.

Further reading