Skip to content

Add PERCENTILE and QUARTILE function families#1650

Open
marcin-kordas-hoc wants to merge 10 commits intodevelopfrom
feature/percentile-quartile
Open

Add PERCENTILE and QUARTILE function families#1650
marcin-kordas-hoc wants to merge 10 commits intodevelopfrom
feature/percentile-quartile

Conversation

@marcin-kordas-hoc
Copy link
Copy Markdown
Collaborator

@marcin-kordas-hoc marcin-kordas-hoc commented Apr 7, 2026

Summary

  • Implement 6 new functions: PERCENTILE, PERCENTILE.INC, PERCENTILE.EXC, QUARTILE, QUARTILE.INC, QUARTILE.EXC
  • New PercentilePlugin with inclusive/exclusive interpolation helpers
  • i18n translations for all 17 languages (verified against Excel function translator)
  • CHANGELOG entry and built-in-functions.md updated

Changes

  • src/interpreter/plugin/PercentilePlugin.ts — new plugin
  • src/interpreter/plugin/index.ts — export registration
  • src/i18n/languages/*.ts — all 17 languages
  • docs/guide/built-in-functions.md — 6 new entries (alphabetical)
  • CHANGELOG.md — added entry

Test plan

  • 57 unit tests in hyperformula-tests (function-percentile.spec.ts)
  • Excel validation workbook (107 cases) — open in Excel 365 desktop, verify all PASS
  • npm run lint passes
  • npm run compile passes
  • CI green

Note

Medium Risk
Adds new statistical function implementations in the interpreter, which can affect formula evaluation and error behavior for these functions. Scope is otherwise localized (docs/i18n/changelog), but correctness depends on interpolation and edge-case handling.

Overview
Introduces a new PercentilePlugin implementing PERCENTILE.INC/PERCENTILE.EXC and QUARTILE.INC/QUARTILE.EXC, with PERCENTILE and QUARTILE as aliases to the inclusive variants.

The implementation extracts numeric values from ranges, sorts them, computes inclusive/exclusive linear interpolation, and returns appropriate #NUM! errors for out-of-range parameters or empty numeric inputs.

Updates the built-in functions guide, adds an Unreleased changelog entry, and extends all language packs with translations for the new function names.

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

marcin-kordas-hoc and others added 3 commits March 20, 2026 17:35
…C, QUARTILE.EXC functions

- New PercentilePlugin with inclusive and exclusive interpolation
- Translations for all 17 supported languages (verified via excel-translator.de)
- Documentation in built-in-functions.md
- CHANGELOG entry

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…lidation

- Extract getSortedValues() to eliminate 4x duplicated range-extraction + sort
- Remove dead-code guards from percentileInclusive/percentileExclusive helpers
- Fix quartile validation: truncate BEFORE range check (Excel truncates 3.9→3)
- Remove minValue/maxValue from QUARTILE params — validate post-truncation
- Use correct ValueSmall/ValueLarge error messages for under/over bounds

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- ruRU: ПРОЦЕНТИЛЬ.ВКЛ/ИСКЛ → ПЕРСЕНТИЛЬ.ВКЛ/ИСКЛ (match base name)
- csCZ: QUARTIL → KVARTIL (proper Czech Excel name)
- trTR: .DHL → .DAH for INC variants (Dahil, not typo)
- index.ts: fix alphabetical export order (ModuloPlugin before PercentilePlugin)
- PercentilePlugin: use ast.procedureName instead of hardcoded metadata key

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Wrong error message when percentile rank exceeds dataset size
    • Split the combined rank < 1 || rank > n check into two separate conditions so rank > n now correctly returns ErrorMessage.ValueLarge instead of ErrorMessage.ValueSmall.
  • ✅ Fixed: Russian PERCENTILE.INC/EXC translations use wrong root word
    • Changed the Russian translations for PERCENTILE.INC and PERCENTILE.EXC from ПЕРСЕНТИЛЬ.ВКЛ/ПЕРСЕНТИЛЬ.ИСКЛ to ПРОЦЕНТИЛЬ.ВКЛ/ПРОЦЕНТИЛЬ.ИСКЛ to match official Microsoft Excel Russian locale names.

Create PR

Or push these changes by commenting:

@cursor push 8d62452b48
Preview (8d62452b48)
diff --git a/src/i18n/languages/ruRU.ts b/src/i18n/languages/ruRU.ts
--- a/src/i18n/languages/ruRU.ts
+++ b/src/i18n/languages/ruRU.ts
@@ -369,8 +369,8 @@
     LARGE: 'НАИБОЛЬШИЙ',
     SMALL: 'НАИМЕНЬШИЙ',
     PERCENTILE: 'ПЕРСЕНТИЛЬ',
-    'PERCENTILE.INC': 'ПЕРСЕНТИЛЬ.ВКЛ',
-    'PERCENTILE.EXC': 'ПЕРСЕНТИЛЬ.ИСКЛ',
+    'PERCENTILE.INC': 'ПРОЦЕНТИЛЬ.ВКЛ',
+    'PERCENTILE.EXC': 'ПРОЦЕНТИЛЬ.ИСКЛ',
     QUARTILE: 'КВАРТИЛЬ',
     'QUARTILE.INC': 'КВАРТИЛЬ.ВКЛ',
     'QUARTILE.EXC': 'КВАРТИЛЬ.ИСКЛ',

diff --git a/src/interpreter/plugin/PercentilePlugin.ts b/src/interpreter/plugin/PercentilePlugin.ts
--- a/src/interpreter/plugin/PercentilePlugin.ts
+++ b/src/interpreter/plugin/PercentilePlugin.ts
@@ -34,9 +34,12 @@
 function percentileExclusive(sortedVals: number[], k: number): number | CellError {
   const n = sortedVals.length
   const rank = k * (n + 1)
-  if (rank < 1 || rank > n) {
+  if (rank < 1) {
     return new CellError(ErrorType.NUM, ErrorMessage.ValueSmall)
   }
+  if (rank > n) {
+    return new CellError(ErrorType.NUM, ErrorMessage.ValueLarge)
+  }
   const intPart = Math.floor(rank)
   const fraction = rank - intPart
   if (intPart < n) {

This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.

…name)

Microsoft uses different roots: legacy ПЕРСЕНТИЛЬ vs newer ПРОЦЕНТИЛЬ.ВКЛ/ИСКЛ.
Confirmed via official ru-ru support.microsoft.com docs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

There are 3 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 224d845. Configure here.

marcin-kordas-hoc and others added 3 commits April 7, 2026 02:10
…docs)

- csCZ: KVARTIL → QUARTIL (Czech Excel uses QUARTIL, not KVARTIL)
- trTR: .DAH → .DHL (Turkish Excel uses .DHL, confirmed on support.microsoft.com/tr-tr)

Our earlier code review incorrectly changed these. Official MS docs confirm
the original translations were correct.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add @param/@returns tags to all public methods and module-level helpers
- Rename intPart → lowerIndex for clarity in interpolation functions
- Add inline comments explaining quart / 4 conversion
- Improve class-level JSDoc to explain inclusive/exclusive distinction

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@marcin-kordas-hoc marcin-kordas-hoc requested a review from sequba April 7, 2026 10:54
@sequba
Copy link
Copy Markdown
Contributor

sequba commented Apr 7, 2026

@marcin-kordas-hoc resolve the merge conflicts

| NORMSINV | Returns value of inverse normal distribution. | NORMSINV(P) |
| PEARSON | Returns the correlation coefficient between two data sets. | PEARSON(Data1, Data2) |
| PHI | Returns probability densitity of normal distribution. | PHI(X) |
| PERCENTILE | Returns the k-th percentile of values in a range. | PERCENTILE(Data, K) |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this works the same as PERCENTILE.INC, it should have the same description

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 17a65e5. PERCENTILE now has the same description as PERCENTILE.INC: "inclusive of 0 and 1".

| POISSON | Returns density of Poisson distribution. | POISSON(X, Mean, Mode) |
| POISSON.DIST | Returns density of Poisson distribution. | POISSON.DIST(X, Mean, Mode) |
| POISSONDIST | Returns density of Poisson distribution. | POISSONDIST(X, Mean, Mode) |
| QUARTILE | Returns the quartile of a data set. | QUARTILE(Data, Quart) |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this works the same as QUARTILE.INC, it should have the same description

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 17a65e5. QUARTILE now has the same description as QUARTILE.INC: "based on inclusive percentile values".

Comment on lines +67 to +80
'PERCENTILE': {
method: 'percentile',
parameters: [
{argumentType: FunctionArgumentType.RANGE},
{argumentType: FunctionArgumentType.NUMBER, minValue: 0, maxValue: 1},
],
},
'PERCENTILE.INC': {
method: 'percentile',
parameters: [
{argumentType: FunctionArgumentType.RANGE},
{argumentType: FunctionArgumentType.NUMBER, minValue: 0, maxValue: 1},
],
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If these 2 function work the same use FunctionPlugin.aliases

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 17a65e5. PERCENTILE is now an alias for PERCENTILE.INC, and QUARTILE is an alias for QUARTILE.INC, using FunctionPlugin.aliases.

marcin-kordas-hoc and others added 2 commits April 7, 2026 12:02
…review)

- PERCENTILE is now an alias for PERCENTILE.INC
- QUARTILE is now an alias for QUARTILE.INC
- Docs: PERCENTILE and QUARTILE descriptions match their .INC variants

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ability

Use ValueLarge for rank > n (upper bound) and ValueSmall for rank < 1
(lower bound) instead of generic ValueSmall for both. ErrorType stays
NUM in both cases (Excel-compatible). Improves detailedError API for
developers and AI agents per 2026 explainability priority.
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.

2 participants