UNPKG

@cortex-js/compute-engine

Version:

Symbolic computing and numeric evaluations for JavaScript and Node.js

1,498 lines (1,491 loc) 243 kB
/** Compute Engine 0.58.0 */ // src/compute-engine/numeric-value/types.ts var NumericValue = class { /** bignum version of .re, if available */ get bignumRe() { return void 0; } /** The imaginary part of this numeric value. * * Can be negative, zero or positive. */ im; get bignumIm() { return void 0; } isZeroWithTolerance(_tolerance) { return this.isZero; } // // JavaScript Object methods // /** Object.valueOf(): returns a primitive value, preferably a JavaScript * number over a string, even if at the expense of precision */ valueOf() { if (this.im === 0) return this.bignumRe ? this.bignumRe.toNumber() : this.re; return this.toString(); } /** Object.toPrimitive() */ [Symbol.toPrimitive](hint) { return hint === "string" ? this.toString() : this.valueOf(); } /** Object.toJSON */ toJSON() { if (this.im === 0) { const r = this.re; if (Number.isFinite(r)) return r; } return this.N().toString(); } print() { const log = console["log"]; log?.(this.toString()); } }; // src/big-decimal/utils.ts var _pow10Cache = /* @__PURE__ */ new Map(); function pow10(n) { if (n <= 100) { let v = _pow10Cache.get(n); if (v === void 0) { v = 10n ** BigInt(n); _pow10Cache.set(n, v); } return v; } return 10n ** BigInt(n); } function fpmul(a, b, scale) { return a * b / scale; } function fpdiv(a, b, scale) { return a * scale / b; } function fpsqrt(a, scale) { if (a === 0n) return 0n; if (a < 0n) throw new RangeError("fpsqrt: negative input"); let x; const aNum = Number(a); const scaleNum = Number(scale); if (Number.isFinite(aNum) && Number.isFinite(scaleNum) && aNum > 0 && scaleNum > 0) { const approx = Math.sqrt(aNum / scaleNum) * scaleNum; if (Number.isFinite(approx) && approx > 0) { x = BigInt(Math.floor(approx)); if (x === 0n) x = 1n; } else { x = digitBasedSeed(a, scale); } } else { x = digitBasedSeed(a, scale); } const as = a * scale; let prev; do { prev = x; x = (x + as / x) / 2n; } while (bigintAbs(x - prev) > 1n); const next = (x + as / x) / 2n; const diffX = bigintAbs(x * x - as); const diffNext = bigintAbs(next * next - as); return diffNext < diffX ? next : x; } function digitBasedSeed(a, scale) { const LEAD = 15; const digA = bigintDigits(a); const shiftA = Math.max(0, digA - LEAD); const leadA = Number(shiftA > 0 ? a / pow10(shiftA) : a); const digS = bigintDigits(scale); const shiftS = Math.max(0, digS - LEAD); const leadS = Number(shiftS > 0 ? scale / pow10(shiftS) : scale); const totalShift = shiftA + shiftS; const halfShift = Math.floor(totalShift / 2); let floatSeed = Math.sqrt(leadA * leadS); if (totalShift % 2 !== 0) floatSeed *= 3.1622776601683795; const seed = BigInt(Math.round(floatSeed)) * pow10(halfShift); return seed > 0n ? seed : 1n; } function bigintAbs(n) { return n < 0n ? -n : n; } function bigintDigits(n) { if (n === 0n) return 1; if (n < 0n) n = -n; if (n < 0x20000000000000n) return Math.floor(Math.log10(Number(n))) + 1; let bits = 0; let tmp = n; let high = 1; while (tmp >> BigInt(high) > 0n) high *= 2; for (let shift = high >> 1; shift >= 1; shift >>= 1) { if (tmp >> BigInt(shift) > 0n) { bits += shift; tmp >>= BigInt(shift); } } bits += 1; const approx = Math.ceil(bits * 0.30102999566398); if (n < pow10(approx - 1)) return approx - 1; if (n >= pow10(approx)) return approx + 1; return approx; } function fpexp(x, scale) { if (x === 0n) return scale; let k = 0; let r = x; const half = scale / 2n; while (bigintAbs(r) > half) { r = r / 2n; k++; } let sum = scale; let term = r; sum += term; for (let n = 2; ; n++) { term = term * r / (BigInt(n) * scale); if (bigintAbs(term) === 0n) break; sum += term; } for (let i = 0; i < k; i++) { sum = sum * sum / scale; } return sum; } function fpln(x, scale) { if (x === scale) return 0n; const xNum = Number(x); const scaleNum = Number(scale); let y; let target = x; let k = 0; if (Number.isFinite(xNum) && Number.isFinite(scaleNum) && xNum > 0 && scaleNum > 0) { const ratio = xNum / scaleNum; if (Number.isFinite(ratio) && ratio > 0) { const approx = Math.log(ratio); if (Number.isFinite(approx)) { y = BigInt(Math.round(approx * scaleNum)); } else { y = estimateLnSeed(x, scale); } } else { y = estimateLnSeed(x, scale); } } else { target = x; const twoScale = 2n * scale; const halfScale = scale / 2n; while (target > twoScale || target < halfScale) { target = fpsqrt(target, scale); k++; } y = estimateLnSeed(target, scale); } let prevAbsDelta = 0n; for (let i = 0; i < 100; i++) { const ey = fpexp(y, scale); if (ey === 0n) { y = y / 2n; continue; } const yn = y + target * scale / ey - scale; const absDelta = bigintAbs(yn - y); if (absDelta <= 1n) break; if (absDelta < 100000n && prevAbsDelta > 0n && prevAbsDelta < 100000n && absDelta * 4n >= prevAbsDelta) break; prevAbsDelta = absDelta; y = yn; } for (let i = 0; i < k; i++) { y = 2n * y; } return y; } function estimateLnSeed(x, scale) { const xDigits = bigintDigits(x); const scaleDigits = bigintDigits(scale); const digitDiff = BigInt(xDigits - scaleDigits); return digitDiff * 2302585n * scale / 1000000n; } var PI_DIGITS = "314159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912983367336244065664308602139494639522473719070217986094370277053921717629317675238467481846766940513200056812714526356082778577134275778960917363717872146844090122495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859502445945534690830264252230825334468503526193118817101000313783875288658753320838142061717766914730359825349042875546873115956286388235378759375195778185778053217122680661300192787661119590921642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151557485724245415069595082953311686172785588907509838175463746493931925506040092770167113900984882401285836160356370766010471018194295559619894676783744944825537977472684710404753464620804668425906949129331367702898915210475216205696602405803815019351125338243003558764024749647326391419927260426992279678235478163600934172164121992458631503028618297455570674983850549458858692699569092721079750930295532116534498720275596023648066549911988183479775356636980742654252786255181841757467289097777279380008164706001614524919217321721477235014144197356854816136115735255213347574184946843852332390739414333454776241686251898356948556209921922218427255025425688767179049460165346680498862723279178608578438382796797668145410095388378636095068006422512520511739298489608412848862694560424196528502221066118630674427862203919494504712371378696095636437191728746776465757396241389086583264599581339047802759009946576407895126946839835259570982582262052248940772671947826848260147699090264013639443745530506820349625245174939965143142980919065925093722169646151570985838741059788595977297549893016175392846813826868386894277415599185592524595395943104997252468084598727364469584865383673622262609912460805124388439045124413654976278079771569143599770012961608944169486855584840635"; var _fppiCache = null; function fppi(scale) { if (_fppiCache !== null && _fppiCache.scale === scale) return _fppiCache.value; const p = bigintDigits(scale) - 1; const neededDigits = p + 10; const digits = PI_DIGITS.slice(0, neededDigits + 1); const piInt = BigInt(digits); const fracDigits = digits.length - 1; const value = piInt * scale / pow10(fracDigits); _fppiCache = { scale, value }; return value; } function fpsincos(x, scale) { if (x === 0n) return [0n, scale]; const pi = fppi(scale); const twoPi = 2n * pi; const halfPi = pi / 2n; let r; const absX = bigintAbs(x); if (absX > scale * (1n << 30n)) { const extraDigits = bigintDigits(absX) - bigintDigits(scale) + 20; const extScale = scale * pow10(extraDigits); const extX = x * pow10(extraDigits); const extPi = fppi(extScale); const extTwoPi = 2n * extPi; let extR = extX % extTwoPi; if (extR < 0n) extR += extTwoPi; r = extR / pow10(extraDigits); } else { r = x % twoPi; } if (r < 0n) r += twoPi; let sinSign = 1n; let cosSign = 1n; if (r > 3n * halfPi) { r = twoPi - r; sinSign = -1n; } else if (r > pi) { r = r - pi; sinSign = -1n; cosSign = -1n; } else if (r > halfPi) { r = pi - r; cosSign = -1n; } const p = bigintDigits(scale) - 1; const targetK = Math.min(18, Math.max(2, Math.ceil(0.87 * Math.sqrt(p)))); let k = 0; const threshold = scale >> BigInt(targetK); while (r > threshold) { r = r / 2n; k++; } let sinVal = r; let cosVal = scale; let sinTerm = r; let cosTerm = scale; const r2 = r * r; const scale2 = scale * scale; for (let n = 2; ; n += 2) { cosTerm = cosTerm * r2 / (BigInt(n) * BigInt(n - 1) * scale2); if (cosTerm === 0n) { sinTerm = sinTerm * r2 / (BigInt(n + 1) * BigInt(n) * scale2); if (sinTerm !== 0n) { if (n % 4 === 2) { cosVal -= cosTerm; sinVal -= sinTerm; } else { cosVal += cosTerm; sinVal += sinTerm; } } break; } sinTerm = sinTerm * r2 / (BigInt(n + 1) * BigInt(n) * scale2); if (n % 4 === 2) { cosVal -= cosTerm; sinVal -= sinTerm; } else { cosVal += cosTerm; sinVal += sinTerm; } if (sinTerm === 0n) break; } for (let i = 0; i < k; i++) { const newSin = 2n * sinVal * cosVal / scale; const newCos = 2n * cosVal * cosVal / scale - scale; sinVal = newSin; cosVal = newCos; } return [sinSign * sinVal, cosSign * cosVal]; } function fpatan(x, scale) { if (x === 0n) return 0n; if (x < 0n) return -fpatan(-x, scale); const pi = fppi(scale); const halfPi = pi / 2n; if (x > scale) { const reciprocal = scale * scale / x; return halfPi - fpatan(reciprocal, scale); } const threshold = 4n * scale / 10n; let halvings = 0; let r = x; while (r > threshold) { const r22 = r * r; const val = (scale * scale + r22) / scale; const sqrtVal = fpsqrt(val, scale); r = r * scale / (scale + sqrtVal); halvings++; } let sum = r; let term = r; const r2 = r * r; const scale2 = scale * scale; for (let n = 3; ; n += 2) { term = term * r2 / scale2; if (term === 0n) break; if (n % 4 === 3) { sum -= term / BigInt(n); } else { sum += term / BigInt(n); } } for (let i = 0; i < halvings; i++) { sum = 2n * sum; } return sum; } // src/big-decimal/big-decimal.ts var NAN_CMP = NaN; var BigDecimal = class _BigDecimal { /** Working precision (significant digits) for inexact operations like division. */ static precision = 50; // ---------- Static constants ---------- static ZERO = Object.freeze( Object.assign(Object.create(_BigDecimal.prototype), { significand: 0n, exponent: 0 }) ); static ONE = Object.freeze( Object.assign(Object.create(_BigDecimal.prototype), { significand: 1n, exponent: 0 }) ); static TWO = Object.freeze( Object.assign(Object.create(_BigDecimal.prototype), { significand: 2n, exponent: 0 }) ); static NEGATIVE_ONE = Object.freeze( Object.assign(Object.create(_BigDecimal.prototype), { significand: -1n, exponent: 0 }) ); static HALF = Object.freeze( Object.assign(Object.create(_BigDecimal.prototype), { significand: 5n, exponent: -1 }) ); static NAN = Object.freeze( Object.assign(Object.create(_BigDecimal.prototype), { significand: 0n, exponent: NaN }) ); static POSITIVE_INFINITY = Object.freeze( Object.assign(Object.create(_BigDecimal.prototype), { significand: 1n, exponent: Infinity }) ); static NEGATIVE_INFINITY = Object.freeze( Object.assign(Object.create(_BigDecimal.prototype), { significand: -1n, exponent: Infinity }) ); /** Full-precision PI (1100+ digits) */ static _piFullPrecision = null; /** PI rounded to working precision */ static _piCache = null; static _piCachePrecision = 0; /** PI to current working precision. */ static get PI() { if (_BigDecimal._piFullPrecision === null) { _BigDecimal._piFullPrecision = new _BigDecimal( PI_DIGITS[0] + "." + PI_DIGITS.slice(1) ); } const prec = _BigDecimal.precision; if (_BigDecimal._piCache === null || _BigDecimal._piCachePrecision !== prec) { _BigDecimal._piCache = _BigDecimal._piFullPrecision.toPrecision(prec + 4); _BigDecimal._piCachePrecision = prec; } return _BigDecimal._piCache; } significand; exponent; constructor(value) { if (value instanceof _BigDecimal) { this.significand = value.significand; this.exponent = value.exponent; return; } if (typeof value === "bigint") { [this.significand, this.exponent] = normalize(value, 0); return; } if (typeof value === "number") { [this.significand, this.exponent] = fromNumber(value); return; } [this.significand, this.exponent] = fromString(value); } // ---------- State checks ---------- /** True when this value represents NaN. */ isNaN() { return Number.isNaN(this.exponent); } /** True when significand is 0 and the value is not NaN. */ isZero() { return this.exponent === 0 && this.significand === 0n; } /** True when the exponent is finite (not NaN, not +/-Infinity). */ isFinite() { return Number.isFinite(this.exponent); } /** True when the value represents a mathematical integer (exponent >= 0) and is finite. */ isInteger() { return this.isFinite() && this.exponent >= 0; } /** True when significand > 0 (including positive infinity). */ isPositive() { return this.significand > 0n; } /** True when significand < 0 (including negative infinity). */ isNegative() { return this.significand < 0n; } // ---------- Comparison methods ---------- /** * Compare this value with another. * Returns -1 if this < other, 0 if equal, 1 if this > other, NaN if either is NaN. */ cmp(other) { if (typeof other === "number") { if (Number.isNaN(other)) return NAN_CMP; const thisExp2 = this.exponent; if (Number.isNaN(thisExp2)) return NAN_CMP; if (other === 0) { if (this.significand === 0n) return 0; return this.significand > 0n ? 1 : -1; } if (!Number.isFinite(thisExp2)) { if (other === Infinity) return this.significand > 0n ? 0 : -1; if (other === -Infinity) return this.significand < 0n ? 0 : 1; return this.significand > 0n ? 1 : -1; } if (this.significand === 0n) return other > 0 ? -1 : 1; if (other === Infinity) return -1; if (other === -Infinity) return 1; if (this.significand > 0n !== other > 0) return this.significand > 0n ? 1 : -1; if (Number.isInteger(other) && thisExp2 >= 0 && thisExp2 <= 15) { const thisVal = this.significand * pow10(thisExp2); const otherVal = BigInt(other); if (thisVal < otherVal) return -1; if (thisVal > otherVal) return 1; return 0; } other = new _BigDecimal(other); } const thisExp = this.exponent; const otherExp = other.exponent; const thisSig = this.significand; const otherSig = other.significand; if (thisExp !== thisExp || otherExp !== otherExp) return NAN_CMP; if (!Number.isFinite(thisExp) || !Number.isFinite(otherExp)) { if (!Number.isFinite(thisExp) && !Number.isFinite(otherExp)) { if (thisSig === otherSig) return 0; return thisSig > otherSig ? 1 : -1; } if (!Number.isFinite(thisExp)) return thisSig > 0n ? 1 : -1; return otherSig > 0n ? -1 : 1; } if (thisSig === 0n) { if (otherSig === 0n) return 0; return otherSig > 0n ? -1 : 1; } if (otherSig === 0n) return thisSig > 0n ? 1 : -1; if (thisSig > 0n && otherSig < 0n) return 1; if (thisSig < 0n && otherSig > 0n) return -1; if (thisExp === otherExp) { if (thisSig < otherSig) return -1; if (thisSig > otherSig) return 1; return 0; } const thisDigits = bigintDigits(thisSig); const otherDigits = bigintDigits(otherSig); const thisMag = thisDigits + thisExp; const otherMag = otherDigits + otherExp; if (thisMag !== otherMag) { const sign = thisSig > 0n ? 1 : -1; return thisMag > otherMag ? sign : -sign; } let aSig = thisSig; let bSig = otherSig; const diff = Math.abs(thisExp - otherExp); if (diff > 1e3) { const aDigits = thisDigits; const bDigits = otherDigits; const target = Math.max(aDigits, bDigits) + 1; if (aDigits < target) aSig = aSig * pow10(target - aDigits); if (bDigits < target) bSig = bSig * pow10(target - bDigits); } else if (thisExp < otherExp) { bSig = bSig * pow10(diff); } else { aSig = aSig * pow10(diff); } if (aSig < bSig) return -1; if (aSig > bSig) return 1; return 0; } /** * Returns true if this value equals other. * NaN === NaN → false (standard NaN semantics). */ eq(other) { if (typeof other === "number") { if (other === 0) return this.significand === 0n && this.exponent === 0; if (other === 1) return this.significand === 1n && this.exponent === 0; if (other === -1) return this.significand === -1n && this.exponent === 0; if (Number.isInteger(other) && Number.isFinite(this.exponent) && this.exponent >= 0 && this.exponent <= 15) { return this.significand * pow10(this.exponent) === BigInt(other); } return this.cmp(other) === 0; } return this.significand === other.significand && this.exponent === other.exponent; } /** Returns true if this value is strictly less than other. */ lt(other) { return this.cmp(other) === -1; } /** Returns true if this value is less than or equal to other. */ lte(other) { const c = this.cmp(other); return c === -1 || c === 0; } /** Returns true if this value is strictly greater than other. */ gt(other) { return this.cmp(other) === 1; } /** Returns true if this value is greater than or equal to other. */ gte(other) { const c = this.cmp(other); return c === 1 || c === 0; } // ---------- Arithmetic methods ---------- /** * Add this value to another. * Aligns exponents, adds significands. The result is exact. */ add(other) { if (typeof other === "number") other = new _BigDecimal(other); const thisExp = this.exponent; const otherExp = other.exponent; if (Number.isFinite(thisExp) && Number.isFinite(otherExp)) { if (thisExp === otherExp) return fromRaw(this.significand + other.significand, thisExp); const diff = thisExp - otherExp; if (diff > 0) return fromRaw( this.significand * pow10(diff) + other.significand, otherExp ); return fromRaw( this.significand + other.significand * pow10(-diff), thisExp ); } if (thisExp !== thisExp || otherExp !== otherExp) return _BigDecimal.NAN; const thisInf = !Number.isFinite(thisExp); const otherInf = !Number.isFinite(otherExp); if (thisInf && otherInf) { if (this.significand !== other.significand) return _BigDecimal.NAN; return this.significand > 0n ? _BigDecimal.POSITIVE_INFINITY : _BigDecimal.NEGATIVE_INFINITY; } if (thisInf) return this.significand > 0n ? _BigDecimal.POSITIVE_INFINITY : _BigDecimal.NEGATIVE_INFINITY; return other.significand > 0n ? _BigDecimal.POSITIVE_INFINITY : _BigDecimal.NEGATIVE_INFINITY; } /** * Subtract other from this. * Aligns exponents, subtracts significands. The result is exact. */ sub(other) { if (typeof other === "number") other = new _BigDecimal(other); const thisExp = this.exponent; const otherExp = other.exponent; if (Number.isFinite(thisExp) && Number.isFinite(otherExp)) { if (thisExp === otherExp) return fromRaw(this.significand - other.significand, thisExp); const diff = thisExp - otherExp; if (diff > 0) return fromRaw( this.significand * pow10(diff) - other.significand, otherExp ); return fromRaw( this.significand - other.significand * pow10(-diff), thisExp ); } if (thisExp !== thisExp || otherExp !== otherExp) return _BigDecimal.NAN; const thisInf = !Number.isFinite(thisExp); const otherInf = !Number.isFinite(otherExp); if (thisInf && otherInf) { if (this.significand === other.significand) return _BigDecimal.NAN; return this.significand > 0n ? _BigDecimal.POSITIVE_INFINITY : _BigDecimal.NEGATIVE_INFINITY; } if (thisInf) return this.significand > 0n ? _BigDecimal.POSITIVE_INFINITY : _BigDecimal.NEGATIVE_INFINITY; return other.significand > 0n ? _BigDecimal.NEGATIVE_INFINITY : _BigDecimal.POSITIVE_INFINITY; } /** * Multiply this value by another. * Multiplies significands, adds exponents. The result is exact. */ mul(other) { if (typeof other === "number") other = new _BigDecimal(other); const thisExp = this.exponent; const otherExp = other.exponent; if (Number.isFinite(thisExp) && Number.isFinite(otherExp)) return fromRaw(this.significand * other.significand, thisExp + otherExp); if (thisExp !== thisExp || otherExp !== otherExp) return _BigDecimal.NAN; if (this.significand === 0n || other.significand === 0n) return _BigDecimal.NAN; const signA = this.significand > 0n ? 1n : -1n; const signB = other.significand > 0n ? 1n : -1n; return signA * signB > 0n ? _BigDecimal.POSITIVE_INFINITY : _BigDecimal.NEGATIVE_INFINITY; } /** * Negate this value. Zero.neg() → Zero. */ neg() { const sig = this.significand; if (sig === 0n) return this; if (Number.isFinite(this.exponent)) return fromRaw(-sig, this.exponent); return sig > 0n ? _BigDecimal.NEGATIVE_INFINITY : _BigDecimal.POSITIVE_INFINITY; } /** * Absolute value. If already non-negative, returns this. */ abs() { if (this.significand >= 0n) return this; if (!Number.isFinite(this.exponent)) return _BigDecimal.POSITIVE_INFINITY; return fromRaw(-this.significand, this.exponent); } /** * Round toward -Infinity. * `3.7` → `3`, `-3.7` → `-4`. * For integers returns this. NaN/Infinity → return this. */ floor() { const exp = this.exponent; if (exp >= 0) return this; if (Number.isFinite(exp)) { const t = this.trunc(); if (this.significand < 0n) return t.sub(fromRaw(1n, 0)); return t; } return this; } /** * Round toward +Infinity. * `3.2` → `4`, `-3.2` → `-3`. * For integers returns this. NaN/Infinity → return this. */ ceil() { const exp = this.exponent; if (exp >= 0) return this; if (Number.isFinite(exp)) { const t = this.trunc(); if (this.significand > 0n) return t.add(fromRaw(1n, 0)); return t; } return this; } /** * Round half away from zero (standard math rounding). * `3.5` → `4`, `-3.5` → `-4`, `3.4` → `3`, `3.6` → `4`. * For integers returns this. NaN/Infinity → return this. */ round() { const exp = this.exponent; if (exp >= 0) return this; if (Number.isFinite(exp)) { const half = fromRaw(5n, -1); if (this.significand > 0n) return this.add(half).trunc(); return this.sub(half).trunc(); } return this; } /** * Truncate toward zero, removing the fractional part. * For integers (exponent >= 0) returns this. * NaN → NaN, +/-Infinity → +/-Infinity. */ trunc() { const exp = this.exponent; if (exp >= 0) return this; if (Number.isFinite(exp)) { const truncSig = this.significand / pow10(-exp); if (truncSig === 0n) return fromRaw(0n, 0); return fromRaw(truncSig, 0); } return this; } /** * Divide this value by another. * Uses `BigDecimal.precision` to determine significant digits for inexact results. * * Special cases: * - NaN / x → NaN, x / NaN → NaN * - nonzero / 0 → +/-Infinity (matching Decimal.js behavior) * - 0 / 0 → NaN * - Inf / finite → Inf (correct sign) * - finite / Inf → 0 * - Inf / Inf → NaN */ div(other) { if (typeof other === "number") other = new _BigDecimal(other); const thisExp = this.exponent; const otherExp = other.exponent; const thisSig = this.significand; const otherSig = other.significand; if (Number.isFinite(thisExp) && Number.isFinite(otherExp)) { if (otherSig === 0n) { if (thisSig === 0n) return _BigDecimal.NAN; return thisSig > 0n ? _BigDecimal.POSITIVE_INFINITY : _BigDecimal.NEGATIVE_INFINITY; } if (thisSig === 0n) return fromRaw(0n, 0); const prec = _BigDecimal.precision; const guard = 10; const absDividend = thisSig < 0n ? -thisSig : thisSig; const absDivisor = otherSig < 0n ? -otherSig : otherSig; const dividendDigits = bigintDigits(absDividend); const divisorDigits = bigintDigits(absDivisor); const totalScale = prec + guard + Math.max(0, divisorDigits - dividendDigits); const scale = pow10(totalScale); const quotient = thisSig * scale / otherSig; const resultExp = thisExp - otherExp - totalScale; return fromRaw(quotient, resultExp).toPrecision(prec); } if (thisExp !== thisExp || otherExp !== otherExp) return _BigDecimal.NAN; const thisInf = !Number.isFinite(thisExp); const otherInf = !Number.isFinite(otherExp); if (thisInf && otherInf) return _BigDecimal.NAN; if (thisInf) { const signA = thisSig > 0n ? 1n : -1n; const signB = otherSig > 0n ? 1n : otherSig < 0n ? -1n : 1n; return signA * signB > 0n ? _BigDecimal.POSITIVE_INFINITY : _BigDecimal.NEGATIVE_INFINITY; } return fromRaw(0n, 0); } /** * Multiplicative inverse: 1 / this. * Uses `BigDecimal.precision` for the division. */ inv() { return fromRaw(1n, 0).div(this); } /** * Modulo (remainder after truncating division). * Defined as: this - trunc(this / other) * other * * The sign of the result matches the sign of the dividend (this), * consistent with JavaScript's % operator and Decimal.js. */ mod(other) { if (typeof other === "number") other = new _BigDecimal(other); const thisExp = this.exponent; const otherExp = other.exponent; if (Number.isFinite(thisExp) && Number.isFinite(otherExp)) { if (other.significand === 0n) return _BigDecimal.NAN; if (this.significand === 0n) return fromRaw(0n, 0); return this.sub(this.div(other).trunc().mul(other)).toPrecision( _BigDecimal.precision ); } if (thisExp !== thisExp || otherExp !== otherExp) return _BigDecimal.NAN; if (!Number.isFinite(thisExp)) return _BigDecimal.NAN; return new _BigDecimal(this); } /** * Raise to a power. * * - Integer exponent: exact result via repeated squaring * - Zero exponent: 1 (for any non-NaN base) * - Negative integer exponent: pow(abs(n)).inv() (uses precision) * - Non-integer exponent on positive base: exp(n * ln(this)) * - Non-integer exponent on negative base: NaN (real-valued result doesn't exist) * * Special cases: * - NaN base or exponent → NaN * - Infinite exponent → NaN * - 0^0 → 1 (mathematical convention) * - 0^positive → 0 * - 0^negative → Infinity */ pow(n) { if (typeof n === "number") n = new _BigDecimal(n); if (this.isNaN() || n.isNaN()) return _BigDecimal.NAN; if (!n.isFinite()) return _BigDecimal.NAN; if (n.isInteger()) { const expValue = n.toBigInt(); if (expValue === 0n) return fromRaw(1n, 0); if (!this.isFinite()) { if (expValue > 0n) { if (this.significand < 0n && expValue % 2n !== 0n) return _BigDecimal.NEGATIVE_INFINITY; return _BigDecimal.POSITIVE_INFINITY; } return fromRaw(0n, 0); } if (this.isZero()) { if (expValue > 0n) return fromRaw(0n, 0); return _BigDecimal.POSITIVE_INFINITY; } if (expValue < 0n) { return this.pow(n.neg()).inv(); } const absSig = this.significand < 0n ? -this.significand : this.significand; const thisLog10 = bigintDigits(absSig) + this.exponent; const resultLog10 = Number(expValue) * thisLog10; if (resultLog10 > 9e15) { return this.significand < 0n && expValue % 2n !== 0n ? _BigDecimal.NEGATIVE_INFINITY : _BigDecimal.POSITIVE_INFINITY; } if (resultLog10 < -9e15) { return fromRaw(0n, 0); } const prec = _BigDecimal.precision; let result = fromRaw(1n, 0); let base = this; let exp = expValue; while (exp > 0n) { if (exp & 1n) { result = result.mul(base).toPrecision(prec); } exp >>= 1n; if (exp > 0n) { base = base.mul(base).toPrecision(prec); } } return result; } if (!this.isFinite()) { if (this.significand < 0n) return _BigDecimal.NAN; if (n.significand > 0n) return _BigDecimal.POSITIVE_INFINITY; return _BigDecimal.ZERO; } if (this.isZero()) { if (n.significand > 0n) return _BigDecimal.ZERO; return _BigDecimal.POSITIVE_INFINITY; } if (this.significand < 0n) return _BigDecimal.NAN; return n.mul(this.ln()).exp(); } // ---------- Conversion methods ---------- /** Convert to a JavaScript number. May lose precision for large values. */ toNumber() { if (!Number.isFinite(this.exponent)) { if (this.exponent !== this.exponent) return NaN; return this.significand > 0n ? Infinity : -Infinity; } if (this.significand === 0n) return 0; if (this.exponent === 0) return Number(this.significand); return Number(this.toString()); } /** * Reconstruct a decimal string from significand and exponent. * * For normal-range exponents, produces a clean decimal string. * For very large (> 20) or very small (< -6) adjusted exponents, * uses scientific notation like `'1.5e+25'`. */ toString() { if (!Number.isFinite(this.exponent)) { if (this.exponent !== this.exponent) return "NaN"; return this.significand > 0n ? "Infinity" : "-Infinity"; } if (this.significand === 0n) return "0"; const negative = this.significand < 0n; const absStr = (negative ? -this.significand : this.significand).toString(); const numDigits = absStr.length; const adjustedExp = numDigits + this.exponent - 1; const sign = negative ? "-" : ""; if (adjustedExp > 20 || adjustedExp < -6) { const sciStr = numDigits === 1 ? absStr : absStr[0] + "." + absStr.slice(1); const expSign = adjustedExp >= 0 ? "+" : ""; return `${sign}${sciStr}e${expSign}${adjustedExp}`; } if (this.exponent >= 0) { return sign + absStr + "0".repeat(this.exponent); } const decimalDigits = -this.exponent; if (decimalDigits < numDigits) { const intPart = absStr.slice(0, numDigits - decimalDigits); const fracPart = absStr.slice(numDigits - decimalDigits); return `${sign}${intPart}.${fracPart}`; } const leadingZeros = decimalDigits - numDigits; return `${sign}0.${"0".repeat(leadingZeros)}${absStr}`; } /** * Format with a fixed number of decimal places. * * Rounds to the specified number of digits after the decimal point * using round-half-to-even (banker's rounding) for the tie-breaking case. * If `digits` is undefined, behaves like toFixed(0). */ toFixed(digits) { const d = digits ?? 0; if (!Number.isFinite(this.exponent)) { if (this.exponent !== this.exponent) return "NaN"; return this.significand > 0n ? "Infinity" : "-Infinity"; } const negative = this.significand < 0n; const absSig = negative ? -this.significand : this.significand; const shift = this.exponent + d; let rounded; if (shift >= 0) { rounded = absSig * pow10(shift); } else { const divisor = pow10(-shift); const quotient = absSig / divisor; const remainder = absSig % divisor; const half = divisor / 2n; if (remainder > half) { rounded = quotient + 1n; } else if (remainder < half) { rounded = quotient; } else { if (divisor % 2n !== 0n) { rounded = quotient; } else if (quotient % 2n === 0n) { rounded = quotient; } else { rounded = quotient + 1n; } } } const sign = negative && rounded !== 0n ? "-" : ""; const roundedStr = rounded.toString(); if (d === 0) { return `${sign}${roundedStr}`; } if (roundedStr.length <= d) { const padded = roundedStr.padStart(d, "0"); return `${sign}0.${padded}`; } const intPart = roundedStr.slice(0, roundedStr.length - d); const fracPart = roundedStr.slice(roundedStr.length - d); return `${sign}${intPart}.${fracPart}`; } /** * Round to n significant digits, returning a new BigDecimal. * Uses round-half-to-even for tie-breaking. * If the value already has n or fewer significant digits, returns this. */ toPrecision(n) { if (this.significand === 0n || !Number.isFinite(this.exponent)) return this; const absSig = this.significand < 0n ? -this.significand : this.significand; const digits = bigintDigits(absSig); if (digits <= n) return this; const shift = digits - n; const divisor = pow10(shift); let rounded = absSig / divisor; const remainder = absSig % divisor; const half = divisor / 2n; if (remainder > half || remainder === half && rounded % 2n !== 0n) { rounded += 1n; } const sig = this.significand < 0n ? -rounded : rounded; return fromRaw(sig, this.exponent + shift); } /** * Truncate fractional part and return a bigint. * Throws if the value is NaN or Infinity. */ toBigInt() { if (!Number.isFinite(this.exponent)) { if (this.exponent !== this.exponent) throw new RangeError("Cannot convert NaN to BigInt"); throw new RangeError("Cannot convert Infinity to BigInt"); } if (this.exponent >= 0) { return this.significand * pow10(this.exponent); } const divisor = pow10(-this.exponent); return this.significand / divisor; } }; function fromRaw(sig, exp) { const [normSig, normExp] = normalize(sig, exp); const bd = Object.create(BigDecimal.prototype); bd.significand = normSig; bd.exponent = normExp; return bd; } var _1e9 = 1000000000n; var _1e3 = 1000n; function normalize(sig, exp) { if (sig === 0n) return [0n, 0]; while (sig % _1e9 === 0n) { sig /= _1e9; exp += 9; } while (sig % _1e3 === 0n) { sig /= _1e3; exp += 3; } while (sig % 10n === 0n) { sig /= 10n; exp += 1; } return [sig, exp]; } function fromNumber(value) { if (Number.isNaN(value)) return [0n, NaN]; if (value === Infinity) return [1n, Infinity]; if (value === -Infinity) return [-1n, Infinity]; if (Number.isInteger(value)) return normalize(BigInt(value), 0); return fromString(value.toString()); } function fromString(s) { s = s.trim(); if (s === "" || s === "NaN") return [0n, NaN]; if (s === "Infinity" || s === "+Infinity") return [1n, Infinity]; if (s === "-Infinity") return [-1n, Infinity]; let mantissa; let explicitExp = 0; const eIdx = s.search(/[eE]/); if (eIdx !== -1) { mantissa = s.slice(0, eIdx); explicitExp = Number(s.slice(eIdx + 1)); if (!Number.isFinite(explicitExp)) return [0n, NaN]; } else { mantissa = s; } let negative = false; if (mantissa.startsWith("-")) { negative = true; mantissa = mantissa.slice(1); } else if (mantissa.startsWith("+")) { mantissa = mantissa.slice(1); } const dotIdx = mantissa.indexOf("."); let intPart; let fracPart; if (dotIdx === -1) { intPart = mantissa; fracPart = ""; } else { intPart = mantissa.slice(0, dotIdx); fracPart = mantissa.slice(dotIdx + 1); } intPart = intPart.replace(/^0+/, "") || "0"; const digits = intPart + fracPart; if (digits.length === 0 || !/^\d+$/.test(digits)) return [0n, NaN]; let sig = BigInt(digits); if (negative) sig = -sig; const implicitExp = -fracPart.length; return normalize(sig, implicitExp + explicitExp); } // src/big-decimal/transcendentals.ts function toFixedPoint(x, precision) { const scale = pow10(precision); const exp = x.exponent + precision; if (exp >= 0) { return [x.significand * pow10(exp), scale]; } return [x.significand / pow10(-exp), scale]; } function fromFixedPoint(fp, scale, targetPrecision) { if (fp === 0n) return BigDecimal.ZERO; const negative = fp < 0n; let absFp = negative ? -fp : fp; const fpDigits = bigintDigits(absFp); if (fpDigits > targetPrecision) { const drop = fpDigits - targetPrecision; const divisor = pow10(drop); const half = divisor / 2n; const remainder = absFp % divisor; absFp = absFp / divisor; if (remainder >= half) absFp += 1n; const scaleExp2 = bigintDigits(scale) - 1; const resultExp2 = drop - scaleExp2; const sig2 = negative ? -absFp : absFp; return fromRaw(sig2, resultExp2); } const scaleExp = bigintDigits(scale) - 1; const resultExp = -scaleExp; const sig = negative ? -absFp : absFp; return fromRaw(sig, resultExp); } BigDecimal.prototype.sqrt = function() { if (this.isNaN()) return BigDecimal.NAN; if (this.isZero()) return BigDecimal.ZERO; if (!this.isFinite()) { if (this.significand > 0n) return BigDecimal.POSITIVE_INFINITY; return BigDecimal.NAN; } if (this.significand < 0n) return BigDecimal.NAN; const targetPrec = BigDecimal.precision; const workingPrec = targetPrec + 10; const [fp, scale] = toFixedPoint(this, workingPrec); const sqrtFp = fpsqrt(fp, scale); return fromFixedPoint(sqrtFp, scale, targetPrec); }; BigDecimal.prototype.cbrt = function() { if (this.isNaN()) return BigDecimal.NAN; if (this.isZero()) return BigDecimal.ZERO; if (!this.isFinite()) { if (this.significand > 0n) return BigDecimal.POSITIVE_INFINITY; return BigDecimal.NEGATIVE_INFINITY; } if (this.significand < 0n) { return this.neg().cbrt().neg(); } const targetPrec = BigDecimal.precision; const workingPrec = targetPrec + 10; const [fp, scale] = toFixedPoint(this, workingPrec); const C = fp * scale * scale; let x; const numVal = this.toNumber(); const scaleNum = Number(scale); if (Number.isFinite(numVal) && numVal > 0 && Number.isFinite(scaleNum)) { const approx = Math.cbrt(numVal); if (Number.isFinite(approx) && approx > 0) { x = BigInt(Math.floor(approx * scaleNum)); if (x === 0n) x = 1n; } else { x = cbrtSeed(fp, scale); } } else { x = cbrtSeed(fp, scale); } let prev; do { prev = x; const x2 = x * x; if (x2 === 0n) { x = 1n; break; } x = (2n * x + C / x2) / 3n; } while (bigintAbs(x - prev) > 1n); { const next = (2n * x + C / (x * x)) / 3n; const diffX = bigintAbs(x * x * x - C); const diffNext = bigintAbs(next * next * next - C); if (diffNext < diffX) x = next; } return fromFixedPoint(x, scale, targetPrec); }; BigDecimal.sqrt = function(x) { return x.sqrt(); }; BigDecimal.cbrt = function(x) { return x.cbrt(); }; BigDecimal.prototype.exp = function() { if (this.isNaN()) return BigDecimal.NAN; if (!this.isFinite()) { if (this.significand > 0n) return BigDecimal.POSITIVE_INFINITY; return BigDecimal.ZERO; } if (this.isZero()) return BigDecimal.ONE; const targetPrec = BigDecimal.precision; const workingPrec = targetPrec + 15; const [fp, scale] = toFixedPoint(this, workingPrec); const expFp = fpexp(fp, scale); return fromFixedPoint(expFp, scale, targetPrec); }; BigDecimal.prototype.ln = function() { if (this.isNaN()) return BigDecimal.NAN; if (!this.isFinite()) { if (this.significand > 0n) return BigDecimal.POSITIVE_INFINITY; return BigDecimal.NAN; } if (this.isZero()) return BigDecimal.NEGATIVE_INFINITY; if (this.significand < 0n) return BigDecimal.NAN; if (this.eq(1)) return BigDecimal.ZERO; const targetPrec = BigDecimal.precision; const workingPrec = targetPrec + 15; const [fp, scale] = toFixedPoint(this, workingPrec); const lnFp = fpln(fp, scale); return fromFixedPoint(lnFp, scale, targetPrec); }; BigDecimal.prototype.log = function(base) { const b = base instanceof BigDecimal ? base : new BigDecimal(base); return this.ln().div(b.ln()); }; BigDecimal.exp = function(x) { return x.exp(); }; BigDecimal.ln = function(x) { return x.ln(); }; BigDecimal.log10 = function(x) { return x.log(10); }; BigDecimal.prototype.sin = function() { if (this.isNaN()) return BigDecimal.NAN; if (!this.isFinite()) return BigDecimal.NAN; if (this.isZero()) return BigDecimal.ZERO; const targetPrec = BigDecimal.precision; const workingPrec = targetPrec + 15; const [fp, scale] = toFixedPoint(this, workingPrec); const [sinFp] = fpsincos(fp, scale); return fromFixedPoint(sinFp, scale, targetPrec); }; BigDecimal.prototype.cos = function() { if (this.isNaN()) return BigDecimal.NAN; if (!this.isFinite()) return BigDecimal.NAN; if (this.isZero()) return BigDecimal.ONE; const targetPrec = BigDecimal.precision; const workingPrec = targetPrec + 15; const [fp, scale] = toFixedPoint(this, workingPrec); const [, cosFp] = fpsincos(fp, scale); return fromFixedPoint(cosFp, scale, targetPrec); }; BigDecimal.prototype.tan = function() { if (this.isNaN()) return BigDecimal.NAN; if (!this.isFinite()) return BigDecimal.NAN; if (this.isZero()) return BigDecimal.ZERO; const targetPrec = BigDecimal.precision; const workingPrec = targetPrec + 15; const [fp, scale] = toFixedPoint(this, workingPrec); const [sinFp, cosFp] = fpsincos(fp, scale); if (cosFp === 0n) { return sinFp > 0n ? BigDecimal.POSITIVE_INFINITY : BigDecimal.NEGATIVE_INFINITY; } const tanFp = sinFp * scale / cosFp; return fromFixedPoint(tanFp, scale, targetPrec); }; BigDecimal.prototype.atan = function() { if (this.isNaN()) return BigDecimal.NAN; if (this.isZero()) return BigDecimal.ZERO; if (!this.isFinite()) { const piHalf = BigDecimal.PI.div(BigDecimal.TWO); if (this.significand > 0n) return piHalf; return piHalf.neg(); } const targetPrec = BigDecimal.precision; const workingPrec = targetPrec + 15; const [fp, scale] = toFixedPoint(this, workingPrec); const atanFp = fpatan(fp, scale); return fromFixedPoint(atanFp, scale, targetPrec); }; BigDecimal.prototype.asin = function() { if (this.isNaN()) return BigDecimal.NAN; if (!this.isFinite()) return BigDecimal.NAN; if (this.isZero()) return BigDecimal.ZERO; const absThis = this.abs(); const one = BigDecimal.ONE; if (absThis.gt(one)) return BigDecimal.NAN; if (absThis.eq(one)) { const piHalf = BigDecimal.PI.div(BigDecimal.TWO); return this.significand > 0n ? piHalf : piHalf.neg(); } const targetPrec = BigDecimal.precision; const workingPrec = targetPrec + 20; const [xFp, scale] = toFixedPoint(this, workingPrec); const x2 = fpmul(xFp, xFp, scale); const oneMinusX2 = scale - x2; const sqrtVal = fpsqrt(oneMinusX2, scale); const ratio = fpdiv(xFp, sqrtVal, scale); const result = fpatan(ratio, scale); return fromFixedPoint(result, scale, targetPrec); }; BigDecimal.prototype.acos = function() { if (this.isNaN()) return BigDecimal.NAN; if (!this.isFinite()) return BigDecimal.NAN; const absThis = this.abs(); if (absThis.gt(BigDecimal.ONE)) return BigDecimal.NAN; if (this.eq(1)) return BigDecimal.ZERO; if (this.eq(-1)) return BigDecimal.PI; const piHalf = BigDecimal.PI.div(BigDecimal.TWO); return piHalf.sub(this.asin()); }; BigDecimal.sin = function(x) { return x.sin(); }; BigDecimal.cos = function(x) { return x.cos(); }; BigDecimal.tan = function(x) { return x.tan(); }; BigDecimal.asin = function(x) { return x.asin(); }; BigDecimal.acos = function(x) { return x.acos(); }; BigDecimal.atan = function(x) { return x.atan(); }; BigDecimal.atan2 = function(y, x) { const yBd = y instanceof BigDecimal ? y : new BigDecimal(y); if (yBd.isNaN() || x.isNaN()) return BigDecimal.NAN; const pi = BigDecimal.PI; const piHalf = pi.div(BigDecimal.TWO); if (x.isZero()) { if (yBd.isZero()) return BigDecimal.ZERO; if (yBd.significand > 0n) return piHalf; return piHalf.neg(); } const ratio = yBd.div(x); if (x.significand > 0n) { return ratio.atan(); } if (yBd.significand >= 0n) { return ratio.atan().add(pi); } return ratio.atan().sub(pi); }; BigDecimal.prototype.sinh = function() { if (this.isNaN()) return BigDecimal.NAN; if (this.isZero()) return BigDecimal.ZERO; if (!this.isFinite()) { if (this.significand > 0n) return BigDecimal.POSITIVE_INFINITY; return BigDecimal.NEGATIVE_INFINITY; } const expX = this.exp(); const expNegX = expX.inv(); return expX.sub(expNegX).div(BigDecimal.TWO); }; BigDecimal.prototype.cosh = function() { if (this.isNaN()) return BigDecimal.NAN; if (this.isZero()) return BigDecimal.ONE; if (!this.isFinite()) { return BigDecimal.POSITIVE_INFINITY; } const expX = this.exp(); const expNegX = expX.inv(); return expX.add(expNegX).div(BigDecimal.TWO); }; BigDecimal.prototype.tanh = function() { if (this.isNaN()) return BigDecimal.NAN; if (this.isZero()) return BigDecimal.ZERO; if (!this.isFinite()) { if (this.significand > 0n) return BigDecimal.ONE; return BigDecimal.NEGATIVE_ONE; } const exp2x = this.mul(BigDecimal.TWO).exp(); return exp2x.sub(BigDecimal.ONE).div(exp2x.add(BigDecimal.ONE)); }; BigDecimal.sinh = function(x) { return x.sinh(); }; BigDecimal.cosh = function(x) { return x.cosh(); }; BigDecimal.tanh = function(x) { return x.tanh(); }; function cbrtSeed(fp, scale) { const LEAD = 15; const digFp = bigintDigits(fp); const shiftFp = Math.max(0, digFp - LEAD); const leadFp = Number(shiftFp > 0 ? fp / pow10(shiftFp) : fp); const digS = bigintDigits(scale); const shiftS = Math.max(0, digS - LEAD); const leadS = Number(shiftS > 0 ? scale / pow10(shiftS) : scale); const totalShift = shiftFp + 2 * shiftS; const thirdShift = Math.floor(totalShift / 3); const remainder = totalShift % 3; let floatSeed = Math.cbrt(leadFp * leadS * leadS); if (remainder === 1) floatSeed *= 2.154434690031882; if (remainder === 2) floatSeed *= 4.641588833612779; const seed = BigInt(Math.round(floatSeed)) * pow10(thirdShift); return seed > 0n ? seed : 1n; } // src/compute-engine/numerics/richardson.ts function extrapolate(f, x0, options = {}) { const { contract = 0.125, step = 1, power = 2, atol = 1e-16, rtol = atol > 0 ? 0 : Math.sqrt(Number.EPSILON), maxeval = 1e6, // Number.MAX_SAFE_INTEGER breaktol = 2 } = options; if (!isFinite(x0)) { return extrapolate((u) => f(1 / u), 1 / x0, { rtol, atol, maxeval, contract: Math.abs(contract) > 1 ? 1 / contract : contract, step: 1 / step, power }); } let h = step; const invcontract = Math.pow(1 / contract, power); let f0 = f(x0 + h); const neville = [f0]; let err = Infinity; let numeval = 1; while (numeval < maxeval) { numeval += 1; h *= contract; neville.push(f(x0 + h)); let c = invcontract; let minerr = Infinity; for (let i = neville.length - 2; i >= 0; i--) { const old = neville[i]; neville[i] = neville[i + 1] + (neville[i + 1] - neville[i]) / (c - 1); const err_ = Math.abs(neville[i] - old); minerr = Math.min(minerr, err_); if (err_ < err) { f0 = neville[i]; err = err_; } c *= invcontract; } if (minerr > breaktol * err || !isFinite(minerr)) break; if (err <= Math.max(rtol * Math.abs(f0), atol)) break; } return [f0, err]; } // src/compute-engine/numerics/bigint.ts function bigint(a) { if (typeof a === "bigint") return a; if (typeof a === "number") { if (!Number.isInteger(a)) return null; if (a >= Number.MAX_SAFE_INTEGER && a <= Number.MAX_SAFE_INTEGER) return BigInt(a); return bigint(a.toString()); } if (a instanceof BigDecimal) { if (!a.isInteger()) return null; return BigInt(a.toFixed(0)); } let s = a.toLowerCase(); const m = s.match(/^([+-]?[0-9]+)e([+-]?[0-9]+)$/); if (m) { const exp = parseInt(m[2]); if (exp < 0) return null; s = m[1] + "0".repeat(exp); } const i = s.indexOf("."); if (i >= 0) return null; if (!/^[+-]?[0-9]+$/.test(s)) return null; try { return BigInt(s); } catch (e) { console.error(e.message); return null; } } // src/compute-engine/numerics/primes.ts var LARGE_PRIME = 1125899906842597; var SMALL_PRIMES = /* @__PURE__ */ new Set([ 2, 3, 5, 7, 11, 13, 17,