Repository navigation
Conversation
Math.js 9.5.0 -> 15.2.0 (fraction.js 5 with bigint, typed-function 4); 15.2.0 fixes the parser vulnerabilities of 13.1-15.1 (CVE-2026-40897, CVE-2026-41139, GHSA-jvff-x2qm-6286). Engine adaptations to keep the 0.1.17 contract: add/subtract/multiply/ divide round results with a denominator above 2^53 - 1 to the closest fraction with a smaller one (long sums such as the probabilistic sensitivity analysis mean stayed bounded with fraction.js 4; with bigint they grew to thousands of digits and toFloat returned NaN); toFloat handles Fractions beyond the double range; eval with asNumber rejects Unit results as before. Tests: the contract of built artifacts of a release is selected explicitly (SD_EXPRESSION_ENGINE_BASELINE=0.1.17, npm run test:baseline for the committed dist/), version-dependent expectations assert both Math.js versions. The bundles parse as ES2020 (Math.js 13+ requires ES2020 and BigInt); the package sources still compile to ES5.
The denominator bound of the arithmetic helpers was absolute: results below about 1e-16 became 0 (divide(1, 1e20), multiply(divide(1, 1e20), 1e20)), and toFloat lost Fractions beyond the double range (Infinity for (10^310 + 1) / 1009, 0 for (2^1200 + 1) / (2^2200 + 1)). Results stay exact while numerator and denominator have at most 64 bits and are otherwise replaced by the first continued-fraction convergent within a relative error of 2^-64; toFloat divides with bigint to 64 significant bits and scales by a power of two. Tests against exact rational arithmetic: the reported cases, random operands from 1e-30 to 1e30, a sum of terms between 1e-25 and 1e25, random large Fractions in toFloat.
…Math.js changes Revert the rounding of add/subtract/multiply/divide: it changed values (x + 0 != x for x = 2^80 / 3) and decisions on ties; the arithmetic is exact again as Math.js 15 computes it. Bounding the long sums of the probabilistic sensitivity analysis belongs to the aggregation in sd-computations. toFloat of a Fraction returns the double nearest to it, ties to even, including subnormal results and overflow to Infinity (bigint division with a sticky bit). Reference cases (midpoints, ties, subnormals, overflow, random large Fractions) generated with Python's fractions.Fraction. Version-difference tests for the reproduced Math.js 10-15 changes of user expressions (percent and mod precedence, implicit multiplication, comparison tolerances, isInteger, mod round-off, matrix functions, print indices, ...); docs/MATHJS_UPGRADE.md lists their sources and proposes the handling of old diagrams for decision.
sd-computations (fix/job-resume-semantics) records the expression semantics in every job execution and continues a stopped job only under the semantics it was started with; the proposal for old diagrams refers to it instead of an unimplemented marker.
sd-computations (fix/job-resume-semantics, 52a7ab5) now records a profile of the Math.js version and configuration instead of the Math.js major; expressions that change the shared configuration are listed as a decision.
fix/job-resume-semantics is not ready to be merged on its own: it refuses analyses of diagrams that call config(...) also with 0.1.17, and its profile does not cover createUnit / import.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Draft: depends on consumer changes and on decisions of the owner (below).
Base:
modernizeafter the squashes of A (2e70d48) and B (d00e0e9). Own commits (rebased, same tree asbefore):
1f24b29,e1171b6,0c0bd47(replaces the rounding of the first two; the net change is what isdescribed here),
b70e2eb,d1e3558,f6d361b(docs). Squash on merge.Version: Math.js 15.2.0
Latest stable release; the only version after 9.x without known parser vulnerabilities:
GHSA-jvff-x2qm-6286, GHSA-29qv-4j9f-fjw5 (CVE-2026-40897), GHSA-5v89-rwgr-qj6g (CVE-2026-41139), all High,
affect 13.1.0 - 15.1.x, fixed in 15.2.0 (9.5.0 not affected).
Changes
mathjs9.5.0→15.2.0(exact). Runtime tree: fraction.js 5.3.4 (bigint), typed-function 4.2.2,complex.js 2.4.3, decimal.js 10.6.0, @babel/runtime 7.29.10; sd-utils, sd-random, lodash, loglevel unchanged.
src/expression-engine.js), public API unchanged:add,subtract,multiply,divide) is exact, as Math.js 15 computes it. Theearlier rounding policies of this PR are removed: an absolute bound made small values 0, a relative one
changed
x + 0(x = 2^80/3:compare(x, add(x, 0))1,subtract-1/3). Regression tests for both.toFloatof a Fraction returns the double nearest to it, ties to even, including subnormals and overflow(fraction.js 5
valueOf()=Number(n) / Number(d)rounds twice and gives Infinity/NaN for large parts).Contract: correct rounding. Reference: 188 cases (both sides of midpoints, ties, subnormals, the overflow
boundary, random Fractions up to 1200 bits) generated with Python
fractions.Fraction(
test/contract/fixtures/tofloat_cases.py).toNumberrejects aUnit(as 0.1.17; Math.js 14+ converts the value of a unit).after 100 runs, the browser blocks at 1000). Bounded where they are formed, in sd-computations
(
fix/psa-exact-mean), not in the engine.SD_EXPRESSION_ENGINE_BASELINE=0.1.17/npm run test:baselinefor the committed 0.1.17 dist,test/contract/mathjs-version.test.jsasserts both versions for every difference: exactness against bigintrational arithmetic (1000 random operand pairs of 1e-30 - 1e30), small values,
toFloatcases, and thetable of reproduced Math.js 10-15 changes of user expressions.
docs/MATHJS_UPGRADE.md: sources of the differences and a proposal for old diagrams (for decision, notimplemented).
Silent changes of user expressions (reproduced, Math.js HISTORY.md 10.0 - 15.2)
100 + 3% + 1,100 * 3% + 1,x% + 1(x = 2) (15.0)10 / 4 mod 3(14.0, mod precedence)-1 / 2 x,+1 / 2 x(x = 2),-1 / 2 pi(11.0)x > 0(x = 1e-15),abs(0.1 + 0.2 - 0.3) < 1e-15,isZero(1e-15)(13.0 tolerances)isInteger(2.00000000000001) ? 100 : 0,isInteger(0.1 * 3 * 10)(15.1)0.3 mod 0.1(11.11.1)print("$1 $2", [10, 20])(11.11.1),typeOf(f)(11.0),combinations(60, 30)(10.2)20 $2,Function, …42010 20,function, …460sqrt([4, 9]),x ? : 1,size(),m[1, :], US gallonsabsTol: Number.EPSILONin the Math.js configuration restores all comparison cases of 13.0 (notisInteger,mod,floor/ceil) - an option, not applied. The expressions of the 16 saved diagrams of thetest data give the same values in both versions.
Consumer changes (separate branches)
build/minifier-bigint: merged (faddc5f). uglify-js 3.4.9 → 3.19.3 (lockfile, dev): thestandalone build failed on
0n.fix/psa-exact-mean: merged (296c764). Expected values of theprobabilistic analysis from the rows: exact fixed-point sum of the doubles (no BigInt) and one rounding of sum /
runs. Independent of C; ready for review.
fix/job-resume-semantics(172e22e,52a7ab5): an expression semantics profile (profileversion, full Math.js version, whole Math.js configuration) in every job execution; a stopped job is continued
only under the same profile, otherwise archived and restarted; a worker with another profile refuses, and the
refused execution is ended (FAILED, endTime) and can be run again. Draft: not to be merged before the
decision on expressions that change the shared Math.js state (decision 6); its refusal of diagrams with
config(...)applies with 0.1.17 too.fix/babel-bigint(95114ae, patch; the fork cannot be pushed from here): Math.js andfraction.js excluded from the global babelify transform, which turned
**on bigint intoMath.pow.Results (final set: C
d0a97e3, code unchanged inf6d361b, + the four consumer branches; PSA at1e0526b,79066f3changes only the sign of zero and comments)npm run test:build, Node 24.22.2 / npm 11.19.1 and Node 22.22.0 / npm 10.9.4: all checks passed; contracttests standalone(.min) 72 / 3 skipped, module(.min) 74 / 1, source 71 / 4, consumer bundle 71 / 4, installed
dist 72 / 74; Jasmine 11/11 (engine code unchanged since; not rerun for the documentation commits).
npm run test:baseline(committed 0.1.17 dist): standalone 70 / 5 skipped, module 72 / 3.41a87b8, PSA1e0526b, resume52a7ab5) with C: gulp build incl. standalone,Karma 222/222 (196 + 11 exact sum / mean + 15 semantics profile, incl. real Web Workers).
Math.js configuration is refused from the sensitivity analysis dialog (alert, loading ended, stored FAILED with
endTime), the analysis completes after a reload with the normal worker. Earlier browser scenarios (worker):
identical to B except two values where 0.1.17 rounded (expected-value-minimization of
differentrulesandflip_pass.jsonexact instead of 0.5816063329128321; PSA51.71343227838675→…676).probabilistic analysis stopped after 1110 rows is not continued under Math.js 15: a new instance computes all
600 runs (expected values within 0.26 ulp of the exact row mean), the old one stays STOPPED with its rows under
…|archived|<id>. Control: the new sd-computations with 0.1.17 continues the same instance.43.8 s (31-40 s in earlier runs); old sd-computations + C blocks.
Decisions needed
docs/MATHJS_UPGRADE.md), and whether the0.1.17 comparison tolerances are kept (
absTol: Number.EPSILON).n/din the job repository (records of 0.1.17 are read).computed (marking them in the UI, cleaning up archived instances: open).
config(...),import,createUnit): with the semanticsprofile, a diagram whose code calls
config(...)cannot run restartable analyses in the SilverDecisions worker(page and worker profiles differ). Allow (refused as now), reject, or isolate per diagram;
import/createUnitare not covered by the profile.Squash merge
[deps] upgrade Math.js to 15.2.0 and preserve expression contracts