function binarySplit(a: bigint, b: bigint): { P: bigint, Q: bigint, R: bigint } {
if (b === a + 1n) {
const aBig = a;
const Pab = -(6n * aBig - 5n) * (2n * aBig - 1n) * (6n * aBig - 1n);
const Qab = 10939058860032000n * aBig ** 3n;
const Rab = Pab * (545140134n * aBig + 13591409n);
return { P: Pab, Q: Qab, R: Rab };
} else {
const m = BigInt(a + b) / 2n;
const left = binarySplit(a, m);
const right = binarySplit(m, b);
const Pab = left.P * right.P;
const Qab = left.Q * right.Q;
const Rab = right.Q * left.R + left.P * right.R;
return { P: Pab, Q: Qab, R: Rab };
}
}
// Approximate sqrt using Newton's method
function bigIntSqrt(n: bigint, precision = 100n) {
const one = 10n ** precision;
let x = one;
let prev = 0n;
while (x !== prev) {
prev = x;
x = (x + (n * one * one) / x) / 2n;
}
return x;
}
function chudnovsky(n: number) {
const N = BigInt(n);
const { Q, R } = binarySplit(1n, N);
const C = 10005n;
const sqrtC = bigIntSqrt(C, 50n); // sqrt(C) * 10^50
const top = 426880n * sqrtC * Q;
const bottom = 13591409n * Q + R;
// Result is top / bottom with 50 digits of precision
const pi = top * 10n ** 50n / bottom;
return pi;
}
// Print result with decimal point
function formatBigIntDecimal(bigInt: bigint, precision = 50) {
const str = bigInt.toString().padStart(precision + 1, '0');
return str.slice(0, -precision) + '.' + str.slice(-precision);
}
// Output
for (let n = 2; n < 10; n++) {
const piBigInt = chudnovsky(n);
console.log(`${n} = ${formatBigIntDecimal(piBigInt, 100)}`);
}