Skip to content

fix: restore BigNumber precision state when decimal.js trig throws precision-limit errors#3682

Open
mvanhorn wants to merge 1 commit into
josdejong:developfrom
mvanhorn:fix/3676-bignumber-trig-precision-state
Open

fix: restore BigNumber precision state when decimal.js trig throws precision-limit errors#3682
mvanhorn wants to merge 1 commit into
josdejong:developfrom
mvanhorn:fix/3676-bignumber-trig-precision-state

Conversation

@mvanhorn

Copy link
Copy Markdown

Summary

Fix at the single choke point where mathjs creates its BigNumber class: src/type/bignumber/BigNumber.js (the factory that does Decimal.clone({precision: config.precision})). After cloning, wrap the trig-family prototype methods that use decimal.js's PI-based argument reduction (sin/cos/tan/asin/acos/atan and their cosecant/secant/cotangent/hyperbolic aliases as exposed by decimal.js: sine, cosine, tangent, etc.) in a thin guard that snapshots BigNumber.precision and BigNumber.rounding before delegating and restores them in a finally block, so a thrown DecimalError can no longer leave the class in a corrupted state. In the catch path, rethrow the DecimalError wrapped with an actionable message (e.g.

Why this matters

With math.config({number: 'BigNumber', precision: 509, ...}), evaluating tan(pi/2) (or any trig call on a high-precision argument) throws [DecimalError] Precision limit exceeded from decimal.js. The root cause is that decimal.js trig methods internally raise working precision to roughly precision + sd(x) guard digits for argument reduction against its PI constant, which is only stored to 1025 digits; 509 + ~509 exceeds that limit. Worse (per the reporter's follow-up comment), decimal.js mutates Ctor.precision/Ctor.rounding before computing and only restores them on success, so once the error is thrown the mathjs BigNumber class is left with a corrupted precision (~1025), and every subsequent BigNumber evaluation fails with the same error until the page is reloaded. The hard 1025-digit PI limit lives in decimal.js and cannot be lifted from mathjs, but the sticky global-state corruption and the cryptic error are mathjs-side bugs that can be fixed.

See #3676.

Testing

  • Happy path: with default precision (64), tan(pi/2), sin(0.5), cos(bignumber(1)) still return correct BigNumber results and existing trig unit tests pass unchanged. - Sticky-state regression (core fix): configure a fresh math instance with {number: 'BigNumber', precision: 509}; assert evaluate('tan(pi/2)') throws, then assert a subsequent unrelated BigNumber evaluation (e.g. evaluate('1.1 + 2.2') or sin(bignumber(0.5))) succeeds and BigNumber.precision still equals 509. - Error path: the thrown error message mentions the precision limit of decimal.js trigonometric functions (not just the bare [DecimalError] Precision limit exceeded), and is an Error instance.

Fixes #3676

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.

are trigonometric function broken ?

1 participant