Commit 4042b04
authored
Fix IRR error when income > sum of payments (#1627)
### Context
The IRR function returns `#NUM!` error when the initial investment
significantly exceeds the sum of returns (e.g., `=IRR({-150000, 12000,
15000, 18000})`). Excel correctly returns ~-41% for this case.
**Root cause:** The `irrCore` Newton-Raphson solver overshoots past the
lower bound of -1 on the first iteration when the solution is a strongly
negative rate. The code then unconditionally returns `#NUM!`.
**Fix:** Replace the unconditional error with a bisection-based clamp.
When Newton-Raphson overshoots past -1, bisect between the current rate
and -1: `newRate = (rate - 1) / 2`. This is guaranteed to stay in the
valid domain (`> -1`) and converges linearly until close enough for
quadratic Newton convergence to take over.
### How did you test your changes?
Added 5 unit tests in the private tests repo covering:
- Bug reproduction: `[-150000, 12000, 15000, 18000]` with default guess
- Reversed cash flow signs: `[150000, -12000, -15000, -18000]`
- Highly negative IRR (near total loss): `[-10000, 100, 100, 100]`
- Negative IRR with explicit guess
- Large investment with many small returns
All 42 IRR tests pass (37 existing + 5 new), no regressions.
### Types of changes
- [x] Bug fix (a non-breaking change that fixes an issue)
### Related issues:
1. Fixes #1628
### Checklist:
- [x] I have reviewed the guidelines about [Contributing to
HyperFormula](https://hyperformula.handsontable.com/guide/contributing.html)
and I confirm that my code follows the code style of this project.
- [ ] I have signed the [Contributor License
Agreement](https://goo.gl/forms/yuutGuN0RjsikVpM2).
- [x] My change is compliant with the
[OpenDocument](https://docs.oasis-open.org/office/OpenDocument/v1.3/os/part4-formula/OpenDocument-v1.3-os-part4-formula.html)
standard.
- [x] My change is compatible with Microsoft Excel.
- [x] My change is compatible with Google Sheets.
- [ ] I described my changes in the
[CHANGELOG.md](https://github.com/handsontable/hyperformula/blob/master/CHANGELOG.md)
file.
- [ ] My changes require a documentation update.
- [ ] My changes require a migration guide.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Small, localized numerical-solver change plus non-runtime
test/benchmark script updates; primary risk is altered IRR convergence
behavior on edge-case inputs.
>
> **Overview**
> Fixes `IRR` returning `#NUM!` for strongly negative solutions by
clamping Newton-Raphson iterations in `irrCore` when the next step
overshoots past `-1` (bisects back into the valid domain instead of
immediately erroring).
>
> Updates tooling/docs around the private test suite: renames the setup
script to `test:setup-private`, adjusts `fetch-tests.sh` to create a
missing branch from `develop` (and pull appropriately), and repoints
benchmark scripts to `test/hyperformula-tests/performance`. Also records
the IRR fix in `CHANGELOG.md`.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
34b1265. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->1 parent c96a600 commit 4042b04
5 files changed
Lines changed: 27 additions & 18 deletions
File tree
- src/interpreter/plugin
- test
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
10 | 14 | | |
11 | 15 | | |
12 | 16 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
76 | 76 | | |
77 | 77 | | |
78 | 78 | | |
79 | | - | |
| 79 | + | |
80 | 80 | | |
81 | 81 | | |
82 | | - | |
| 82 | + | |
83 | 83 | | |
84 | 84 | | |
85 | 85 | | |
| |||
88 | 88 | | |
89 | 89 | | |
90 | 90 | | |
91 | | - | |
92 | | - | |
93 | | - | |
94 | | - | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
95 | 95 | | |
96 | 96 | | |
97 | 97 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
876 | 876 | | |
877 | 877 | | |
878 | 878 | | |
879 | | - | |
| 879 | + | |
| 880 | + | |
| 881 | + | |
| 882 | + | |
| 883 | + | |
| 884 | + | |
| 885 | + | |
| 886 | + | |
| 887 | + | |
| 888 | + | |
880 | 889 | | |
881 | 890 | | |
882 | 891 | | |
883 | 892 | | |
884 | 893 | | |
885 | 894 | | |
886 | 895 | | |
887 | | - | |
888 | | - | |
889 | | - | |
890 | | - | |
891 | | - | |
892 | 896 | | |
893 | 897 | | |
894 | 898 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
15 | | - | |
| 15 | + | |
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
| |||
45 | 45 | | |
46 | 46 | | |
47 | 47 | | |
48 | | - | |
| 48 | + | |
49 | 49 | | |
50 | 50 | | |
51 | 51 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
31 | | - | |
| 31 | + | |
32 | 32 | | |
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
| 38 | + | |
38 | 39 | | |
| 40 | + | |
39 | 41 | | |
| 42 | + | |
| 43 | + | |
40 | 44 | | |
41 | | - | |
42 | | - | |
43 | | - | |
| |||
0 commit comments