Excel 16.0 build 19929
Windows, bitness not recorded, CPU not recorded
26 captured inputs are indexed for this environment. Capture dates are not recorded. This is a reading count, not a comparison with another build.
Math and trigonometry functions
Matches all 269,999 recorded answers
Recorded: 269,996 in the answer bank and 3 workbook cells. How we measure this · See the Rust code
| Language | Name in Excel |
|---|---|
| Arabic | ACOTH |
| Bulgarian | ACOTH |
| Czech | ACOTH |
| Danish | ARCCOTH |
| German | ACOTH |
| Greek | ACOTH |
| English (Australia) | ACOTH |
| English (United Kingdom) | ACOTH |
| English (United States) | ACOTH |
| Spanish | ACOTH |
| Estonian | ACOTH |
| Finnish | ACOTH |
| French | ACOTH |
| Hebrew | ACOTH |
| Croatian | ACOTH |
| Hungarian | ARCCOTH |
| Indonesian | ACOTH |
| Italian | ACOTH |
| Japanese | ACOTH |
| Korean | ACOTH |
| Lithuanian | ACOTH |
| Latvian | ACOTH |
| Norwegian | ACOTH |
| Dutch | ACOTH |
| Polish | ACOTH |
| Portuguese (Brazil) | ACOTH |
| Portuguese (Portugal) | ACOTH |
| Romanian | ACOTH |
| Russian | ACOTH |
| Slovak | ACOTH |
| Slovenian | ACOTH |
| Serbian (Latin) | ACOTH |
| Swedish | ARCCOTH |
| Thai | ACOTH |
| Turkish | ACOTH |
| Ukrainian | ACOTH |
| Vietnamese | ACOTH |
| Chinese (Simplified) | ACOTH |
| Chinese (Hong Kong) | ACOTH |
| Chinese (Traditional) | ACOTH |
Names from Microsoft's support site.
ACOTH(number)
ACOTH(number) is the inverse hyperbolic cotangent.
acoth x = (1/2) * ln( (x + 1) / (x - 1) ) = atanh(1/x), |x| > 1
|x| > 1, that is (-infinity, -1) ∪ (1, +infinity). The closed interval
[-1, 1] is excluded: coth maps R \ {0} onto exactly |y| > 1, so no real argument in the
unit interval has a real inverse hyperbolic cotangent. This is the complement of ATANH's
domain, and the two functions partition the real line between them but for the two endpoints.(-infinity, 0) ∪ (0, +infinity) — every nonzero real, with zero itself unattained.
acoth never returns zero, because coth never equals zero.acoth(-x) = -acoth(x). This is exact mathematics and, as the identification
work in this family has shown for its sibling, not something an implementation gets for free.x = 1+ (where acoth -> +infinity) and x = -1-
(where acoth -> -infinity). Approach from inside the interval is not possible; there is
nothing there.acoth(x) = 1/x + 1/(3x^3) + 1/(5x^5) + ... for |x| > 1. As
|x| -> infinity the function decays like 1/x and reaches into the subnormals. This is the
half of the domain where all the numerical difficulty lives.x = 1 + t, acoth(1 + t) = (1/2) * ln(2/t) + O(t). The growth is
logarithmic, so even an argument one ulp above 1 produces only a modest number — around 18.
The function is far better behaved at its poles than its poles suggest.d/dx acoth x = 1/(1 - x^2), which is negative on the whole domain (so acoth
is decreasing on each branch) and finite everywhere except at the excluded endpoints.[-1, 1] — exactly the excluded
real domain. ATANH's cuts are the two outer rays. The two functions have complementary cuts,
which is the precise statement of the complementary-domain observation above.Abramowitz & Stegun give the closed form in chapter 4 section 4.6; Kahan's branch-cut paper is the standard treatment of why the cut sits where it does.
| Argument | Meaning | Default |
|---|---|---|
number | The hyperbolic cotangent of the value you want. Required. | — |
That description is Microsoft's, from the Learn reference: "the hyperbolic cotangent of the angle that you want".
Returns Number.
x = 1 and x = -1 are not in the domain and are rejected. The interval is open; these
are the poles.(-1, 1), including zero and every subnormal, is a domain failure.
Readers arriving from ATANH — whose domain is exactly this interval — get this wrong in both
directions.±1 the answer is finite and modest. There is no overflow near the poles,
because the growth is logarithmic: the largest magnitude reachable from a double argument is
around 18.4, attained one ulp outside 1.1/x, and the result reaches into the subnormal
range at the top of the double domain. This is the region where relative accuracy is hard to
keep, and where the two candidate evaluation forms visibly differ.ACOTH has one serious hazard, and it is at the far end of the domain rather than at the poles —
the opposite of what the function's shape suggests.
The large-argument cancellation. Evaluate (1/2) ln((x+1)/(x-1)) for large x. The ratio
(x+1)/(x-1) tends to 1, and ln of a value near 1 is the canonical accuracy disaster: the
information about the answer lives entirely in the digits of the ratio that the division has just
rounded away. Concretely, once x exceeds about 2^53, the doubles x+1 and x-1 are the same
number, the ratio is exactly 1, and the naive form returns exactly zero — where the true answer
is approximately 1/x, a perfectly representable positive number. The failure begins long before
that: relative accuracy degrades steadily from around x = 10.
The remedies, both standard:
acoth(x) = atanh(1/x), and 1/x is small, so an accurate small-argument
atanh delivers full relative accuracy right down to the subnormals. This is the single most
effective change and it costs one division.log1p on the difference form. atanh(u) = (1/2)(log1p(u) - log1p(-u)) with
u = 1/x, which never forms a quantity near 1 and never takes a logarithm of one. Higham's
treatment of log(1+x) is the standard reference for why the log1p primitive exists at all.Near the poles, by contrast, the naive form is fine: (x+1)/(x-1) is large there, ln of a large
number is well conditioned, and the only subtlety is that x - 1 must be computed from a double
argument that is already close to 1 — which Sterbenz's lemma makes exact.
So the correct branch structure is the reverse of the intuitive one: use the direct ratio-log
near the poles, where the ratio is far from one, and the reciprocal atanh form far from
them, where the ratio is close to one. An implementation that uses one form everywhere is wrong at
one end or the other.
Why the switch point matters more here than usual. Because the two forms disagree in the last bits over a whole band, any implementation that places its switch differently from Excel's will differ from Excel on every argument in the gap between the two placements — even though both forms are individually excellent. This is the characteristic signature of a piecewise elementary function, and it is why identification work on this family concentrates on locating switches rather than on improving accuracy.
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.
ACOTH · 1 lines · calc-func/src/catalogue/math.rs on GitHub4 acoth "ACOTH" (1, 1) [V "number"] |s, a, sv| { unary(s, a, k::acoth::acoth_kernel) }
acoth_series_magnitude · 26 lines · calc-func/src/ported/acoth.rs on GitHubfn acoth_series_magnitude(a: f64) -> f64 {
let reciprocal = crate::ported::excel_numeric::excel_x87_div(1.0, a);
// Excel flushes the reciprocal-to-series handoff when it is subnormal. In
// particular, both signs of a sufficiently large finite input publish +0.
if reciprocal < f64::MIN_POSITIVE {
return 0.0;
}
let square = crate::ported::excel_numeric::excel_x87_mul(a, a);
let mut power = a;
let mut sum = reciprocal;
for k in 1..ACOTH_SERIES_TERM_CAP {
power = crate::ported::excel_numeric::excel_x87_mul(power, square);
let denominator = crate::ported::excel_numeric::excel_x87_mul((2 * k + 1) as f64, power);
let term = crate::ported::excel_numeric::excel_x87_div(1.0, denominator);
let next = crate::ported::excel_numeric::excel_x87_add(sum, term);
if next == sum {
break;
}
sum = next;
}
sum
}
acoth_kernel · 26 lines · calc-func/src/ported/acoth.rs on GitHubpub fn acoth_kernel(n: f64) -> Result<f64, WorksheetErrorCode> {
let a = n.abs();
if a <= 1.0 {
return Err(WorksheetErrorCode::Num);
}
// W109 build-20228/CV2 identification: ACOTH computes on |x| and restores
// the sign after one of two distinct calculation graphs:
// * below the pinned switch, native binary64 +/-1 staging, an x87-PC64
// stored division, then FYL2X and half-scale;
// * at and above it, the direct inverse odd-power series with every
// reciprocal, multiply, divide, and accumulator add stored through
// x87 PC64.
// The frozen graph scored 202,217/202,217 discovery inputs and
// 66,552/66,552 disjoint held-out inputs exactly.
let mag = if a < ACOTH_SERIES_FLOOR {
let ratio = crate::ported::excel_numeric::excel_x87_div(a + 1.0, a - 1.0);
// Storing the FYL2X result before multiplying by the exact power-of-two
// scale is bit-equivalent here to keeping the half-scale in x87.
0.5 * crate::ported::excel_numeric::excel_log(ratio)
} else {
acoth_series_magnitude(a)
};
// Excel publishes positive zero for both signs after the reciprocal flush.
Ok(if mag == 0.0 { 0.0 } else { mag.copysign(n) })
}
unary catalogue/mathbinary_with ported/excel_numericexcel_x87_add ported/excel_numericexcel_x87_mul ported/excel_numericexcel_x87_div ported/excel_numericmul ported/excel_numeric/x87add ported/excel_numeric/x87div ported/excel_numeric/x87No 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 |
|---|---|---|
| 19929 | Windows, bitness not recorded, CPU not recorded | 26 |
| 20131 | Windows, bitness not recorded, AMD Ryzen 7 4800H with Radeon Graphics | 56 |
| 20228 | Windows, 64-bit, CPU not recorded | 239,774 |
| 20430 | Windows, 64-bit, CPU not recorded | 1,224 |
Agreement on these compared inputs does not establish agreement on unmeasured inputs.
Recorded environments and comparison details.
Windows, bitness not recorded, CPU not recorded
26 captured inputs are indexed for this environment. Capture dates are not recorded. This is a reading count, not a comparison with another build.
Windows, bitness not recorded, AMD Ryzen 7 4800H with Radeon Graphics
56 captured inputs are indexed for this environment. Capture dates: 2026-07-12 to 2026-07-12. This is a reading count, not a comparison with another build.
Windows, 64-bit, CPU not recorded
239,774 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.
Windows, 64-bit, CPU not recorded
1,224 captured inputs are indexed for this environment. Capture dates: 2026-09-29 to 2026-09-29. This is a reading count, not a comparison with another build.
ATANH — the reciprocal partner and the complementary domain: acoth(x) = atanh(1/x)
wherever both are defined, ATANH on (-1, 1) and ACOTH on |x| > 1. Upstream identification
work treats the two together for exactly this reason, and both carry evidence records here.COTH — the forward function. COTH(ACOTH(x)) = x to rounding on the domain;
ACOTH(COTH(t)) = t for every nonzero t.ACOSH — shares the exclusion of the unit interval, but only on one side: ACOSH takes
[1, infinity), ACOTH takes |x| > 1. They differ at exactly x = 1, where ACOSH is
defined and zero and ACOTH is not defined at all.ACOT — the circular namesake, and unlike ACOTH it has no domain restriction whatsoever.
The pair is a good illustration that a hyperbolic namesake is not a variant: it is a different
function with a different domain and a different shape.LN — the substrate of the closed form, and the source of the large-argument hazard.1/COTH(x), and with ATANH, whose domain is the exact complement.No named variants are recorded yet.
Suggest a correction or contribute an implementation · For agents