mirror of
https://github.com/storytold/gridcraft.git
synced 2026-10-31 15:48:41 +00:00
commit
59fd17ae56
3 files changed
+23
-5
No files matched your search
@@ -336,6 +336,10 @@ pub(super) fn percentrank_impl(a: &[Arg], exc: bool) -> R<Value> {
|
||||
if sig < 1.0 || s.is_empty() {
|
||||
return Err(CellError::Num);
|
||||
}
|
||||
// Excel: 10^significance overflows from 309 up.
|
||||
if sig >= 309.0 {
|
||||
return Err(CellError::Div0);
|
||||
}
|
||||
let (first, last) = (s.first().copied().unwrap_or(0.0), s.last().copied().unwrap_or(0.0));
|
||||
if x < first || x > last {
|
||||
return Err(CellError::NA);
|
||||
@@ -359,6 +363,10 @@ pub(super) fn percentrank_impl(a: &[Arg], exc: bool) -> R<Value> {
|
||||
let (rl, rh) = (rank_of(lo), rank_of(hi));
|
||||
rl + (x - lo) / (hi - lo) * (rh - rl)
|
||||
};
|
||||
// From significance 15 up Excel returns 15 significant digits, rounded.
|
||||
if sig >= 15.0 {
|
||||
return num_val(format!("{r:.14e}").parse().unwrap_or(r));
|
||||
}
|
||||
num_val(trunc_digits(r, sig))
|
||||
}
|
||||
|
||||
|
||||
@@ -227,10 +227,19 @@ fn percentiles() {
|
||||
close(ev("PERCENTRANK.EXC", vec![e9.clone(), n(5.43)]), 0.381);
|
||||
close(ev("PERCENTRANK.EXC", vec![e9, n(5.43), n(1.0)]), 0.3);
|
||||
let t = c(&[1.0, 2.0, 3.0]);
|
||||
close(ev("PERCENTRANK", vec![t.clone(), n(2.0), n(400.0)]), 0.5);
|
||||
close(ev("PERCENTRANK.INC", vec![t.clone(), n(2.0), n(400.0)]), 0.5);
|
||||
close(ev("PERCENTRANK.INC", vec![t.clone(), n(1.0), n(400.0)]), 0.0);
|
||||
close(ev("PERCENTRANK.EXC", vec![t, n(2.0), n(400.0)]), 0.5);
|
||||
// Excel 16: significance 309 and up is #DIV/0!, 308 still works.
|
||||
for name in ["PERCENTRANK", "PERCENTRANK.INC", "PERCENTRANK.EXC"] {
|
||||
is_err(ev(name, vec![t.clone(), n(2.0), n(309.0)]), CellError::Div0);
|
||||
is_err(ev(name, vec![t.clone(), n(1.0), n(400.0)]), CellError::Div0);
|
||||
close(ev(name, vec![t.clone(), n(2.0), n(308.0)]), 0.5);
|
||||
}
|
||||
// From significance 15 up the result has 15 significant digits.
|
||||
let k = c(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]);
|
||||
for sig in [15.0, 16.0, 308.0] {
|
||||
close_tol(ev("PERCENTRANK.INC", vec![k.clone(), n(2.123_456_789), n(sig)]), 0.187_242_798_166_667, 1e-16);
|
||||
}
|
||||
close_tol(ev("PERCENTRANK.INC", vec![k.clone(), n(2.123_456_789), n(14.0)]), 0.187_242_798_166_66, 1e-15);
|
||||
close(ev("PERCENTRANK.EXC", vec![k, n(2.123_456_789), n(16.0)]), 0.265_432_098_625);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Function parity: worksheet functions and formulas
|
||||
|
||||
> **Last reviewed:** 2026-10-31 · **Last updated:** 2026-10-31 · **Change:** minor (edge cases matched to Excel: base conversions, BITLSHIFT/BITRSHIFT, UNICHAR noncharacters, UPPER/LOWER/PROPER casing, FIXED/DOLLAR output, F/T/GAMMA/WEIBULL/BETA distributions, BINOM trial cap, HARMEAN; earlier: function edge-case parity row; earlier: function edge-case parity row; earlier: ECMA.CEILING listed with USDOLLAR as not on Microsoft's list; earlier: IMSQRT reproduces the stray real part Excel gives for negative reals) · **Target:** Microsoft Excel (Microsoft 365), Excel for Mac 16.113.4
|
||||
> **Last reviewed:** 2026-10-31 · **Last updated:** 2026-10-31 · **Change:** minor (edge cases matched to Excel: base conversions, BITLSHIFT/BITRSHIFT, UNICHAR noncharacters, UPPER/LOWER/PROPER casing, FIXED/DOLLAR output, F/T/GAMMA/WEIBULL/BETA distributions, BINOM trial cap, HARMEAN; earlier: function edge-case parity row; earlier: function edge-case parity row; earlier: function edge-case parity row; earlier: ECMA.CEILING listed with USDOLLAR as not on Microsoft's list; earlier: IMSQRT reproduces the stray real part Excel gives for negative reals) · **Target:** Microsoft Excel (Microsoft 365), Excel for Mac 16.113.4
|
||||
|
||||
Excel's worksheet functions, category by category, against GridCraft's function library. Part of
|
||||
[target-app-parity.md](target-app-parity.md); gaps feed [gaps.md](gaps.md).
|
||||
@@ -93,6 +93,7 @@ This improves series preparation; it does not change the model-fitting or season
|
||||
| 15-significant-digit comparison semantics | done (#57): `=0.1+0.2=0.3` is TRUE, and MATCH and COUNTIF compare the same way. Arithmetic keeps full precision, as Excel does — `=(0.1+0.2)-0.3` is 5.55E-17 |
|
||||
| IMSQRT and the other IM* functions against Excel's text | IMSQRT follows Excel's polar route, so a negative real gives Excel's stray real part: `IMSQRT("-4")` is `1.22514845490862E-16+2i` (checked in Excel 16.0 on 79 inputs). Differences kept: IMSQRT of a number with a part above about 1E154 or below about 1E-155 gives the exact root (Excel gives `#NUM!` or 0); IMPOWER, IMEXP, IMSIN, IMCOS, IMSINH and IMCOSH keep exact results where Excel shows the same kind of noise (`IMPOWER("-4",2)` is `16-3.92047505570758E-15i`) or different trailing digits near multiples of pi/2; IMCSC and IMCSCH differ by one unit in the 15th digit; IMARGUMENT returns 16–17 digits where Excel returns 15; the text of IM* and COMPLEX results differs for some magnitudes (Excel writes `COMPLEX(1E-10,1)` as `0.0000000001+i` but `COMPLEX(0.000000123456789012345,1)` as `1.23456789012345E-07+i`, and an integer past 15 digits rounded and zero-padded) |
|
||||
| MOD quotient limit | done: Excel 16.0 returns `#NUM!` when `ABS(number/divisor) >= 1.1259E12`; lower quotients retain the remainder |
|
||||
| PERCENTRANK significance and precision | done: Excel 16.0 returns `#DIV/0!` from significance 309, and rounds to 15 significant digits for significance 15–308 |
|
||||
| External workbook references (`[Book.xlsx]Sheet1!A1`) | parsed; links dropped on open, no update |
|
||||
| Localized function names and `;` separators | **missing** (#45); en-US only |
|
||||
| Long flat operator chains (`=A1+A2+…`, `-`, `*`, `/`, `^`, `&`, comparisons) | done: no operand limit below Excel's 8,192-character formula limit (Excel, observed: `=1+1+…` with 4,096 operands is exactly 8,192 characters with the `=` and calculates; one more character is refused). Evaluated (#484), printed (#628), stored, copied, adjusted, saved and reopened without recursing once per operand, on a 1 MiB stack (#916); written to XLSX as plain formulas, not dynamic arrays; Spanish entry accepts them |
|
||||
|
||||
Reference in new issue
Block a user