Skip to content

Fix the accuracy of ERF and ERFC near zero and for large arguments - #1795

Open
marcin-kordas-hoc wants to merge 3 commits into
developfrom
fix/erf-accuracy-near-zero
Open

marcin-kordas-hoc wants to merge 3 commits into
developfrom
fix/erf-accuracy-near-zero

Conversation

@marcin-kordas-hoc

@marcin-kordas-hoc marcin-kordas-hoc commented Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

ERF and ERFC lost precision for arguments close to zero and for large arguments. Excel is accurate there, so the results differed from Excel's:

Formula Before Excel / exact Now
ERF(1e-10) 1.128379612e-10 (relative error 3.9e-7) 1.12837916709551e-10 agrees
ERF(1e-300) (raw function) about 1.1e-16 1.12837916709551e-300 agrees
ERFC(5) 1.5374368445e-12 (relative error 1.5e-5) 1.53745979442803e-12 agrees

The cause was erf returning 1 - exp(...) (every digit below about 1e-16 is lost) and erfc being 1 - erf. erf is now computed from its series below 2 (all terms positive, no cancellation) and from the continued fraction of erfc above; erfc uses the continued fraction from 1 upwards. Relative error against Python's math.erf and math.erfc over 46 arguments from 1e-300 to 27 (negative ones included) is at most 7e-16 for erf and 3e-15 for erfc (a prototype of the same formulas, measured before they went into the repository).

The change is in the vendored jstat.ts, so the normal and log-normal distributions that call erf and erfc (NORM.DIST, NORM.INV through erfcinv, LOGNORM.DIST, LOGNORM.INV) are more accurate as well. The existing tests for them still pass unchanged.

Behaviour check against Excel

71 ERF and ERFC formulas were evaluated in Excel Online (MS Graph live session) and in HyperFormula, from 1e-300 to 27, with negative arguments and the two-argument form of ERF: all agree within a relative 4e-11, which is the 11 significant digits HyperFormula returns by default against Excel's 15. Two of them need a note:

  • ERF(1e-300) and ERFC(27) return NaN from the engine, not from erf: with the default smartRounding, any result below about 1e-290 becomes NaN, and so does a plain =1e-300*1. The raw functions return the right values (1.1283791670955126e-300 and 5.23705e-319). That is a separate defect of the number rounding and is not changed here, so the tests start at 1e-100.
  • The uppercase exponent form 1E-10 does not parse on develop (it is fixed in the GESTEP pull request), so the cases use 1e-10.

Tests

Paired tests branch: fix/erf-accuracy-near-zero in the tests repository: 29 Excel-measured cases added to the ERF and ERFC specs, 12 or more of which fail on the previous implementation. Full local run: 502 suites, 6262 passed, 3 skipped.

🤖 Generated with Claude Code


Note

Medium Risk
Changes numeric outputs for ERF/ERFC and dependent statistical functions across many formulas; behavior is intentional and Excel-aligned but may shift edge-case results in existing sheets.

Overview
Improves numeric accuracy of ERF and ERFC so tiny and large arguments match Excel instead of losing precision from 1 - exp(...) and erfc = 1 - erf.

The vendored jstat.ts implementation is replaced with piecewise algorithms: a positive-term series for small |x|, a continued-fraction erfc for larger values, and explicit handling for NaN, sign, and underflow (e.g. erfc → 0 for very large x). Normal and log-normal distribution helpers that call these primitives inherit the same accuracy. The unreleased changelog documents the fix (#1795).

Reviewed by Cursor Bugbot for commit 6fc292b. Bugbot is set up for automated code reviews on this repo. Configure here.

marcin-kordas-hoc and others added 2 commits October 6, 2026 08:59
erf is computed from its series below 2 and from the continued fraction of erfc above, instead of
1 - exp(...), which lost every digit below about 1e-16. erfc uses the continued fraction from 1 upwards.
Relative error against Python's math.erf and math.erfc is at most 7e-16 for erf and 2e-16 for erfc.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
hyperformula-docs 6fc292b Commit Preview URL

Branch Preview URL
Oct 07 2026, 06:25 AM

@github-actions

github-actions Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Performance comparison of head (6fc292b) vs base (5abbbd9)

                                     testName |    base |    head | change
--------------------------------------------------------------------------
                                      Sheet A |  489.51 |  491.03 | +0.31%
                                      Sheet B |  158.88 |  162.37 | +2.20%
                                      Sheet T |   137.4 |  141.58 | +3.04%
                                Column ranges |  466.64 |  471.93 | +1.13%
                                Sorted lookup | 14145.4 | 14196.5 | +0.36%
Sheet A:  change value, add/remove row/column |   16.07 |   16.59 | +3.24%
 Sheet B: change value, add/remove row/column |  129.31 |  134.06 | +3.67%
                   Column ranges - add column |   148.3 |  152.59 | +2.89%
                Column ranges - without batch |  469.39 |  482.88 | +2.87%
                        Column ranges - batch |  113.49 |  118.42 | +4.34%

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Oct 7, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.32%. Comparing base (5abbbd9) to head (6fc292b).

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff            @@
##           develop    #1795   +/-   ##
========================================
  Coverage    97.32%   97.32%           
========================================
  Files          195      195           
  Lines        15739    15753   +14     
  Branches      3461     3499   +38     
========================================
+ Hits         15318    15332   +14     
  Misses         413      413           
  Partials         8        8           
Files with missing lines Coverage Δ
src/interpreter/plugin/3rdparty/jstat/jstat.ts 88.48% <100.00%> (+0.30%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

This branch has not been deployed

No deployments
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.

1 participant