About the port
@johnhenry/math began as a faithful port of the original Mallory
ActionScript 3 library, but it fixed bugs rather than carrying them over,
and it took advantage of modern JavaScript/TypeScript: ES classes, generics,
iterators, Array subclassing, tagged unions, and .ts-native execution.
Every module was translated test-first — a test was written against the
original’s documented/intended behavior before its TypeScript equivalent
existed, which is how the bugs below were caught rather than silently
reproduced.
A sampling of the ~40 bugs found and fixed
Section titled “A sampling of the ~40 bugs found and fixed”RealMath.subtractreturneda * b. (Yes, really.)- Order statistics were broken:
sortused the default lexicographic sort, sominimum/maximum/medianwere wrong for numbers. ComplexMath.dividecomparedalpha.ivalue(lowercasev, alwaysundefined), so all eight directed-infinity results were dead code.ComplexMath.normalDistributionreciprocated the whole expression, putting the exponential in the denominator (wrong sign) — the normal PDF was inverted.solveNwasn’t Newton’s method — it assumed a derivative of 1 and diverged; now a real numeric Newton–Raphson.integrateNsampled at2·x + interval;differentiateNwas a forward difference despite claiming to be symmetric.invertMatrixhad no pivoting (divide-by-zero on a zero pivot); now uses partial pivoting (and a zero-pivot row swap inStructure, for finite fields).crossProductread index 3 for the z-component and used truthiness tests that dropped zero components;powerMatrixnever actually multiplied.Vector.setElementinfinitely recursed on a falsy slot.ComplexNumberstring parsing crashed on non-matches and couldn’t round-trip negative imaginary parts; it also swallowed every*, so"4*2"parsed as42.StringEvaluatorwas uniformly right-associative (10-2-3 → 11); now left-associative for+ - * / %and right-associative for^.Polynomial.multiplyreferenced a non-existentdimension.value;Polynomial.antiderivativedropped its highest-degree term.IntegerMath.modulusrecursed one step at a time (stack overflow);primeFactorsinfinite-looped on0and negatives.Structure’s matrix section was non-functional (static/instance confusion, undefined references) and is reconstructed as working generic linear algebra.IntUtilsspelled “forty” and “ninety” as “fourty” and “ninty”.
Where the original had no verifiable intended behavior
Section titled “Where the original had no verifiable intended behavior”One area — the Flash 3D ribbon geometry in Graph3DUtils — had no
recoverable specification: no test, no comment, no reference implementation
to check against, just a block of matrix math whose intended output couldn’t
be independently verified. Rather than “fix” it by guesswork, the math is
ported verbatim, with an explicit note in the source marking it as such.
The Flash rendering utilities (GraphUtils/Graph3DUtils) more broadly now
return renderer-agnostic geometry — 2D paths, 3D meshes, as plain data —
instead of Flash display objects, since there’s no Flash runtime to hand
those to anymore.
That distinction matters for how to read the rest of this history: everywhere else, a fix means the original’s documented or inferable intent was identifiably violated by its own code, and the test written against that intent is what proves the fix is correct — not a preference for “better” math.
This is a snapshot of the port as it happened, not a description of
@johnhenry/math’s current API — the library has grown substantially since
(CellGraph, Rotor4, exact-fraction and interval arithmetic, and more; see
the main page for what’s actually in it today).