At near-zero `periodicRate`, the direct subtraction
`power(1 + r, n) - 1` suffers catastrophic cancellation: `(1+r)^n`
rounds to a value very close to 1 and the subtraction discards most
of Number's 19-digit large-mantissa precision. The resulting
amortization factor is inaccurate enough that
`loanPrincipalFromPeriodicPayment` returns a principal greater than
`periodicPayment * paymentsRemaining`, which propagates into
`computeTheoreticalLoanState` as a negative `interestDue` and fires
the `interest due delta not greater than outstanding` assertion in
`computePaymentComponents` (testBugInterestDueDeltaCrash).
The same numerical defect causes systematic underpayment of
interest in release builds at the bug regime. On a $1B loan with
the test parameters, closed-form charges only $0.0588 of interest
versus the mathematically correct $0.3805 (verified independently
via 50-digit Decimal arithmetic). Linear scaling: ~$321 underpaid
per $1T of principal.
Replace `raisedRate - 1` with a hybrid evaluator:
- When `r * paymentsRemaining >= 1e-9`, use the closed-form
`power(1+r, n) - 1`. At Number's 19-digit mantissa this still
retains ~10 sig digits post-subtraction and is ~30-500x faster
than the binomial expansion.
- Below the threshold, expand `(1+r)^n - 1 = sum C(n,k) r^k` with
early termination once terms fall below Number precision.
The hybrid takes the closed-form path at every rate covered by
existing fixtures, so output is bit-identical to pre-fix code at
moderate rates (no fixture drift).
Also drops the now-unused `computeRaisedRate` from the lending
helpers (its only caller was `computePaymentFactor`).
Test coverage:
- testComputePowerMinusOne / testComputePowerMinusOneHybrid:
direct unit tests for both new helpers, including property
checks against `(1+r)^2 = 1 + 2r + r^2` and `(1+r)^3 = 1 + 3r +
3r^2 + r^3`, threshold-boundary verification at exactly
r*n = 1e-9, and large-n early-termination.
- testLoanPrincipalFromPeriodicPaymentNearZeroRate: regression
guard, asserts `principal <= payment * n` at near-zero rate.
- testComputeTheoreticalLoanStateNearZeroRate: regression guard,
asserts `interestDue >= 0` and `principalOutstanding <=
valueOutstanding`.
- testBugInterestDueDeltaCrash: end-to-end reproduction of the
original assertion abort, now passes cleanly.
- testFullLifecycleVaultPnLNearZeroRate: integration test running
a $1B loan to completion, verifies the vault collects the
economically-correct interest matching the 50-digit Decimal
reference within sub-microcent tolerance, plus self-consistency
(vault gain == TVO - principal at LoanSet) and conservation
(borrower outflow == vault gain + broker gain).
This change:
* Removes a set of unnecessary brackets in the initialization of an `std::uint32_t`.
* Fixes a couple of incorrect flags (same value, just wrong variables - so no amendment needed).
This change replaces all instances of `<variable> != tesSUCCESS` with `!isTesSuccess(<variable>)` and `<variable> == tesSUCCESS` with `isTesSuccess(<variable>)`.
This change:
* Makes `addSLE` in `DIDSet` a static function, instead of a free function.
* Renames `Attestation` to `Data` everywhere (an artifact of a previous name for the field).
* Actually runs a set of tests that were not included in the `run` function of `DID_test`.