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

Function polygammaCore

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

Source from the content-addressed store, hash-verified

955 result = result.add(BigDecimal.ONE.div(w));
956 result = result.add(BigDecimal.ONE.div(w.mul(w).mul(2)));
957 let w2kp1 = w.mul(w)._mulToPrecision(w, p); // w^3
958 const w2 = w._mulToPrecision(w, p);
959 const tol = new BigDecimal(10).pow(-(p + guard));
960 const nTerms = Math.min(maxTerms, bernoulli.length);
961 for (let k = 0; k < nTerms; k++) {
962 const [bNum, bDen] = bernoulli[k];
963 const term = new BigDecimal(bNum.toString()).div(
964 new BigDecimal(bDen.toString()).mul(w2kp1)
965 );
966 if (k > 0 && term.abs().lt(tol)) break;
967 result = result.add(term);
968 w2kp1 = w2kp1._mulToPrecision(w2, p);
969 }
970
971 return result;
972}
973
974/**
975 * Bignum Polygamma function ψₙ(z) = dⁿ/dzⁿ ψ(z)
976 * Delegates to bigDigamma/bigTrigamma for n=0,1.
977 * For n ≥ 2, uses recurrence + asymptotic expansion.
978 */
979export function bigPolygamma(ce: ComputeEngine, n: BigNum, z: BigNum): BigNum {
980 const nNum = n.toNumber();
981 if (!Number.isInteger(nNum) || nNum < 0) return BigDecimal.NAN;
982 if (nNum === 0) return bigDigamma(ce, z); // already guarded
983 if (nNum === 1) return bigTrigamma(ce, z); // already guarded
984 if (!z.isFinite() || z.isZero()) return BigDecimal.NAN;
985 return withGuardDigits(SPECIAL_FN_GUARD, () => polygammaCore(ce, nNum, z));
986}
987
988function polygammaCore(ce: ComputeEngine, nNum: number, z: BigNum): BigNum {
989 // Bignum factorial helper (small n, simple loop)
990 const bigFactorial = (m: number): BigNum => {
991 let r: BigNum = BigDecimal.ONE;
992 for (let i = 2; i <= m; i++) r = r.mul(i);
993 return r;
994 };
995
996 const p = BigDecimal.precision;
997 const guard = 10;
998 // Shift to w ≈ p so the asymptotic series converges in ≈0.4·p terms rather
999 // than running its full ≈π·w (see `gammalnCore`).
1000 const shift = Math.max(7, Math.ceil(p));
1001
1002 // Poles at z = 0, −1, −2, …
1003 let w = z;
1004 let result = new BigDecimal(0);
1005 if (w.isNegative() && w.isInteger()) return BigDecimal.NAN;
1006
1007 // Recurrence (from ψ(z+1) = ψ(z) + 1/z differentiated n times, DLMF 5.15.5):
1008 // ψ⁽ⁿ⁾(z) = ψ⁽ⁿ⁾(z+1) + (−1)^{n+1} n!/z^{n+1}
1009 // The single shift loop also lifts negative non-integer z past the poles.
1010 const sign = nNum % 2 === 0 ? -1 : 1; // (−1)^{n+1}
1011 const bigFactN = bigFactorial(nNum);
1012 while (w.lt(shift)) {
1013 result = result.add(
1014 new BigDecimal(sign).mul(bigFactN).div(w.pow(nNum + 1))

Callers 1

bigPolygammaFunction · 0.85

Calls 15

addMethod · 0.95
bigFactorialFunction · 0.85
getBernoulliRationalsFunction · 0.85
toPrecisionMethod · 0.80
mulToPrecisionMethod · 0.80
divMethod · 0.65
mulMethod · 0.65
powMethod · 0.65
addMethod · 0.65
toStringMethod · 0.65
absMethod · 0.65
ceilMethod · 0.45

Tested by

no test coverage detected