Excel 16.0 build 20228
Windows, 64-bit, CPU not recorded
5,367 captured inputs are indexed for this environment. Capture dates: 2026-08-09 to 2026-08-09. This is a reading count, not a comparison with another build.
Financial functions
Refuses 45 of 5,533 recorded calls; the rest match
Of 5,533 recorded answers (5,528 in the answer bank and 5 workbook cells), 45 do not match: 45 are refused. How we measure this · See the Rust code
| Language | Name in Excel |
|---|---|
| Arabic | RRI |
| Bulgarian | RRI |
| Czech | RRI |
| Danish | RRI |
| German | RRI |
| Greek | RRI |
| English (Australia) | RRI |
| English (United Kingdom) | RRI |
| English (United States) | RRI |
| Spanish | RRI |
| Estonian | RRI |
| Finnish | TOT.ROI |
| French | TAUX.INT.EQUIV |
| Hebrew | RRI |
| Croatian | RRI |
| Hungarian | MR |
| Indonesian | RRI |
| Italian | RRI |
| Japanese | RRI |
| Korean | RRI |
| Lithuanian | RRI |
| Latvian | RRI |
| Norwegian | REALISERT.AVKASTNING |
| Dutch | RRI |
| Polish | RÓWNOW.STOPA.PROC |
| Portuguese (Brazil) | RRI |
| Portuguese (Portugal) | DEVOLVERTAXAJUROS |
| Romanian | RRI |
| Russian | ЭКВ.СТАВКА |
| Slovak | RRI |
| Slovenian | RRI |
| Serbian (Latin) | RRI |
| Swedish | AVKPÅINVEST |
| Thai | RRI |
| Turkish | GERÇEKLEŞENYATIRIMGETİRİSİ |
| Ukrainian | RRI |
| Vietnamese | RRI |
| Chinese (Simplified) | RRI |
| Chinese (Hong Kong) | RRI |
| Chinese (Traditional) | RRI |
Names from Microsoft's support site.
RRI(nper, pv, fv)
RRI(nper,pv,fv) returns the equivalent compound rate per period between a starting and final amount, without intermediate cash flows. Mathematically it is (fv/pv)^(1/nper)-1.
=RRI(2,64,100) returns about 0.25: the growth factor is 1.5625, whose square root is 1.25. Two periods compound that rate from 64 to 100.
The recorded current kernel rejects nonpositive or subnormal period counts before its equality shortcut. It normalises subnormal value inputs to zero, checks equal values before sign guards, and admits two negative amounts with a positive ratio. A zero present value or opposite nonzero signs gives #NUM! under those rules.
Use stored x87 division for base=fv/pv and for reciprocal=1/nper. A normalised zero base returns minus one. For exactly one period, retain the quotient directly as the powered value; otherwise use the raw measured LN/product/EXP power chain, not the worksheet POWER square-root shortcut. Store the final subtraction of one. The current helper also applies finite-result guards. This preserves cancellation-sensitive stores near equal amounts; native pow followed by subtraction can differ substantially on small rates.
Quoted from the public repository DnaCalc/DnaCalc, crates calc-func and calc-fml, at commit 9e1884369a67. Comments are the source's own. A kernel shared with other functions appears once, on its module page.
RRI · 3 lines · calc-func/src/catalogue/financial.rs on GitHub13 rri_fn "RRI" (3, 3) [V "nper", V "pv", V "fv"] |s, a, sv| {
tv_out(s, tv::rri(num(s, a, 0)?, num(s, a, 1)?, num(s, a, 2)?))
}
financial_daz · 8 lines · calc-func/src/ported/financial_time_value_family.rs on GitHub#[inline]
fn financial_daz(value: f64) -> f64 {
if value.abs() < f64::MIN_POSITIVE {
0.0_f64.copysign(value)
} else {
value
}
}
rri · 62 lines · calc-func/src/ported/financial_time_value_family.rs on GitHubpub fn rri(periods: f64, present_value: f64, future_value: f64) -> Result<f64, FinancialError> {
validate_finite(&[periods, present_value, future_value])?;
// W109's live edge-domain batteries pin the guard order as tightly as the
// positive-domain power graph. Positive subnormal periods are rejected
// before the equality shortcut, while MIN_POSITIVE is admitted.
if periods < f64::MIN_POSITIVE {
return Err(FinancialError::Num);
}
// This legacy financial body observes DAZ-normalized value inputs.
// Equality precedes the sign guards, so equal zeros/subnormals (and even
// equal negative normal values) publish +0.
let present_value = financial_daz(present_value);
let future_value = financial_daz(future_value);
if present_value == future_value {
return Ok(0.0);
}
// A present value of 0 and values of opposite signs are #NUM!; two negative values have a
// positive ratio and are computed like positive ones (dc-ifc, Excel 16.0.20430 on 2026-10-27:
// RRI(1,-1,-3) is 2, RRI(2,-4,-9) 0.5, RRI(2,-5,0) and RRI(2,5,0) -1, RRI(2,0,5),
// RRI(2,-5,5) and RRI(2,5,-5) #NUM!).
let opposite = (present_value < 0.0) != (future_value < 0.0) && future_value != 0.0;
if present_value == 0.0 || opposite {
return Err(FinancialError::Num);
}
// W109 G6-13 / BUG-FUNC-044: RRI is a legacy x87 spill body. Its wrapper
// division, reciprocal, and final subtraction are each RN53(RN64(op)); the
// power itself is the raw x87 chain
// `exp(RN53(RN64((1/n) * ln(base))))`. Native `powf` misses the near-one
// cancellation ladder by 2^27 output ULP, and `ln(base)/n` misses 97 of the
// fresh 4,900 rows. This is NOT the worksheet POWER wrapper: RRI(2,1,2)
// takes the raw chain and bypasses POWER's exponent-0.5 sqrt shortcut.
// The published quotient is DAZ-normalized too. Its zero lane is exactly
// -1 and must bypass the raw LN/EXP helper, whose contract requires a
// finite positive base.
let base = financial_daz(excel_x87_div(future_value, present_value));
if base == 0.0 {
return Ok(-1.0);
}
if !base.is_finite() {
return Err(FinancialError::Num);
}
let reciprocal = excel_x87_recip(periods);
if !reciprocal.is_finite() {
return Err(FinancialError::Num);
}
// periods==1 is an exact identity route, not merely an exponent that
// happens to equal one. Adjacent binary64 period values take the raw chain.
let powered = if periods == 1.0 {
base
} else {
excel_pow_chain(base, reciprocal)
};
let result = excel_x87_sub(powered, 1.0);
if result.is_finite() {
Ok(result)
} else {
Err(FinancialError::Num)
}
}
tv_out catalogue/financialbinary_with ported/excel_numericexcel_pow_chain ported/excel_numericexcel_x87_sub ported/excel_numericexcel_x87_mul ported/excel_numericexcel_x87_div ported/excel_numericexcel_x87_recip ported/excel_numericmul ported/excel_numeric/x87sub ported/excel_numeric/x87div ported/excel_numeric/x87recip ported/excel_numeric/x87pow2_positive ported/excel_numeric/x87_chainspow2 ported/excel_numeric/x87_chainsexp_ext ported/excel_numeric/x87_chainsexp_with ported/excel_numeric/x87_chainsexcel_exp ported/excel_numeric/x87_chainslog_with ported/excel_numeric/x87_chainsexcel_log ported/excel_numeric/x87_chainsvalidate_finite ported/financial_time_value_familyNo implementation has been published with a Handbook test suite for this function.
The recorded environments below distinguish a reading from a same-input comparison. Counts describe captured inputs in each environment; overlapping captures and comparisons are not totals of unique worksheet calls.
| Excel 16.0 build | Platform and CPU | Captured inputs |
|---|---|---|
| 20228 | Windows, 64-bit, CPU not recorded | 5,367 |
The record contains no same-input comparison between these environments. Reading different inputs on different builds does not establish either a version change or cross-build agreement.
Recorded environments and comparison details.
Windows, 64-bit, CPU not recorded
5,367 captured inputs are indexed for this environment. Capture dates: 2026-08-09 to 2026-08-09. This is a reading count, not a comparison with another build.
PDURATION solves periods; RATE includes constant payments; XIRR includes dated cash flows.
No named variants are recorded yet.
Suggest a correction or contribute an implementation · For agents