(ce: ComputeEngine, s: BigNum)
| 1254 | if (x.isNegative() || x.gt(BigDecimal.ONE)) return BigDecimal.NAN; |
| 1255 | if (x.isZero()) return BigDecimal.ZERO; |
| 1256 | if (x.eq(BigDecimal.ONE)) return BigDecimal.ONE; |
| 1257 | return withGuardDigits(SPECIAL_FN_GUARD, () => { |
| 1258 | const bt = gammalnCore(ce, a.add(b)) |
| 1259 | .sub(gammalnCore(ce, a)) |
| 1260 | .sub(gammalnCore(ce, b)) |
| 1261 | .add(a.mul(x.ln())) |
| 1262 | .add(b.mul(BigDecimal.ONE.sub(x).ln())) |
| 1263 | .exp(); |
| 1264 | const boundary = a.add(BigDecimal.ONE).div(a.add(b).add(BigDecimal.TWO)); |
| 1265 | if (x.lt(boundary)) |
| 1266 | return bt.mul(bigBetaContinuedFraction(ce, a, b, x)).div(a); |
| 1267 | return BigDecimal.ONE.sub( |
| 1268 | bt.mul(bigBetaContinuedFraction(ce, b, a, BigDecimal.ONE.sub(x))).div(b) |
| 1269 | ); |
| 1270 | }); |
| 1271 | } |
| 1272 | |
| 1273 | /** |
| 1274 | * Bignum Riemann zeta function ζ(s). |
| 1275 | * |
| 1276 | * The general case uses the Cohen–Villegas–Zagier acceleration of the |
| 1277 | * alternating Dirichlet eta series (error ~(3+√8)^{−n}, so ~1.3 digits of |
| 1278 | * accuracy per term); the kernel runs with working-precision guard digits so |
| 1279 | * the result is accurate to the full requested precision. |
| 1280 | */ |
| 1281 | export function bigZeta(ce: ComputeEngine, s: BigNum): BigNum { |
| 1282 | if (!s.isFinite()) return BigDecimal.NAN; |
| 1283 | if (s.eq(1)) return new BigDecimal(Infinity); // pole |
| 1284 | return withGuardDigits(SPECIAL_FN_GUARD, () => zetaCore(ce, s)); |
| 1285 | } |
| 1286 | |
| 1287 | function zetaCore(ce: ComputeEngine, s: BigNum): BigNum { |
| 1288 | const pi = BigDecimal.PI; |
| 1289 | |
| 1290 | // Special value: ζ(0) = -1/2 |
| 1291 | if (s.isZero()) return BigDecimal.HALF.neg(); |
| 1292 | |
| 1293 | // Special values for positive even integers: ζ(2k) = (-1)^{k+1} B_{2k} (2π)^{2k} / (2(2k)!) |
| 1294 | // Capped at MAX_EXACT_ZETA_EVEN_N: the Bernoulli-number computation is |
| 1295 | // O(k²)-ish in the Bernoulli index k = s/2, so this closed form is only |
| 1296 | // worth it for modest s — beyond the cap the general series below (which |
| 1297 | // is precision-scaled and magnitude-independent) computes the same value. |
| 1298 | if (s.isInteger() && s.isPositive()) { |
| 1299 | const sn = s.toNumber(); |
| 1300 | if (sn % 2 === 0 && sn >= 2 && sn <= MAX_EXACT_ZETA_EVEN_N) { |
| 1301 | const k = sn / 2; |
| 1302 | const bernoulli = getBernoulliRationals(ce, k); |
| 1303 | const [bNum, bDen] = bernoulli[k - 1]; |
| 1304 | const bernAbs = new BigDecimal(absBigint(bNum).toString()).div( |
| 1305 | new BigDecimal(bDen.toString()) |
| 1306 | ); |
| 1307 | const twoPi = pi.mul(2); |
| 1308 | let factVal: BigNum = BigDecimal.ONE; |
| 1309 | let steps = 0; |
| 1310 | for (let i = 2; i <= sn; i++) { |
| 1311 | if ((++steps & 0xfff) === 0) checkDeadline(ce._deadlineFrame); |
| 1312 | factVal = factVal.mul(i); |
| 1313 | } |
no test coverage detected