MCPcopy Create free account
hub / github.com/cortex-js/compute-engine / digammaCore

Function digammaCore

src/compute-engine/numerics/special-functions.ts:829–880  ·  view source on GitHub ↗
(ce: ComputeEngine, z: BigNum)

Source from the content-addressed store, hash-verified

827 const table = computeBernoulliEven(buildTerms, ce._deadline);
828 bernoulliCache.set(ce, table);
829
830 // Return the full cached table (length ≥ minTerms), NOT a `minTerms` slice.
831 // Every caller already clamps its own consumption — the four asymptotic
832 // series (gammaln/digamma/trigamma/polygamma) iterate to
833 // `Math.min(maxTerms, table.length)` and break at the tolerance well before
834 // that, and `zetaCore` indexes a single fixed element `table[k-1]` — so no
835 // caller ever over-sums past its requested `minTerms`. The asymptotic-series
836 // divergence trap (extra terms make the sum worse) is therefore handled at
837 // the caller's clamp, and the per-call `slice` copy is pure overhead. (The
838 // clamp, not the table length, is what enforces the asymptotic cutoff.)
839 return table;
840}
841
842/**
843 * Bignum Digamma function ψ(z) = d/dz ln(Γ(z))
844 * Same algorithm as machine `digamma`: reflection for negative z,
845 * recurrence to shift z > 7, then asymptotic expansion with Bernoulli numbers.
846 */
847export function bigDigamma(ce: ComputeEngine, z: BigNum): BigNum {
848 if (!z.isFinite()) return BigDecimal.NAN;
849 return withGuardDigits(SPECIAL_FN_GUARD, () => digammaCore(ce, z));
850}
851
852function digammaCore(ce: ComputeEngine, z: BigNum): BigNum {
853 // Reflection formula for negative values: ψ(1-z) = ψ(z) + π·cot(πz)
854 if (z.isNegative()) {
855 if (z.isInteger()) return BigDecimal.NAN; // poles at non-positive integers
856 const pi = BigDecimal.PI;
857 const piZ = pi.mul(z);
858 const cotPiZ = piZ.cos().div(piZ.sin());
859 return digammaCore(ce, BigDecimal.ONE.sub(z)).sub(pi.mul(cotPiZ));
860 }
861
862 if (z.isZero()) return BigDecimal.NAN; // pole
863
864 const p = BigDecimal.precision;
865 const guard = 10;
866 // Shift to w ≈ p (not the old 0.37·p, which left the asymptotic series' floor
867 // at the target tolerance, forcing it to run its full ≈π·w terms). The larger
868 // shift converges the series in ≈0.4·p terms; see the note in `gammalnCore`.
869 const shift = Math.max(7, Math.ceil(p));
870
871 // Recurrence: ψ(z+1) = ψ(z) + 1/z — shift z up until z > shift
872 let result = new BigDecimal(0);
873 let w = z;
874 while (w.lt(shift)) {
875 result = result.sub(BigDecimal.ONE.div(w));
876 w = w.add(BigDecimal.ONE);
877 }
878
879 const maxTerms = Math.max(20, Math.ceil(0.6 * p) + 20);
880 const bernoulli = getBernoulliRationals(ce, maxTerms);
881
882 // Asymptotic expansion: ψ(w) ~ ln(w) - 1/(2w) - Σ B_{2k}/(2k·w^{2k}).
883 // Round the running power w^{2k} each step: `mul` keeps the full product, so an

Callers 1

bigDigammaFunction · 0.85

Calls 15

subMethod · 0.95
addMethod · 0.95
getBernoulliRationalsFunction · 0.85
cosMethod · 0.80
sinMethod · 0.80
mulToPrecisionMethod · 0.80
mulMethod · 0.65
divMethod · 0.65
subMethod · 0.65
isZeroMethod · 0.65
addMethod · 0.65
lnMethod · 0.65

Tested by

no test coverage detected