@cortex-js/compute-engine
Version:
Symbolic computing and numeric evaluations for JavaScript and Node.js
1,685 lines (1,682 loc) • 2.23 MB
JavaScript
/** Compute Engine 0.58.0 */
// node_modules/complex-esm/dist/src/complex.js
var cosh = Math.cosh || function(x) {
return Math.abs(x) < 1e-9 ? 1 - x : (Math.exp(x) + Math.exp(-x)) * 0.5;
};
var sinh = Math.sinh || function(x) {
return Math.abs(x) < 1e-9 ? x : (Math.exp(x) - Math.exp(-x)) * 0.5;
};
var cosm1 = function(x) {
var b = Math.PI / 4;
if (-b > x || x > b) {
return Math.cos(x) - 1;
}
var xx = x * x;
return xx * (xx * (xx * (xx * (xx * (xx * (xx * (xx / 20922789888e3 - 1 / 87178291200) + 1 / 479001600) - 1 / 3628800) + 1 / 40320) - 1 / 720) + 1 / 24) - 1 / 2);
};
var hypot = function(x, y) {
var a = Math.abs(x);
var b = Math.abs(y);
if (a < 3e3 && b < 3e3) {
return Math.sqrt(a * a + b * b);
}
if (a < b) {
a = b;
b = x / y;
} else {
b = y / x;
}
return a * Math.sqrt(1 + b * b);
};
var parser_exit = function() {
throw SyntaxError("Invalid Param");
};
function logHypot(a, b) {
var _a = Math.abs(a);
var _b = Math.abs(b);
if (a === 0) {
return Math.log(_b);
}
if (b === 0) {
return Math.log(_a);
}
if (_a < 3e3 && _b < 3e3) {
return Math.log(a * a + b * b) * 0.5;
}
a = a / 2;
b = b / 2;
return 0.5 * Math.log(a * a + b * b) + Math.LN2;
}
var parse = function(a, b) {
var z = { "re": 0, "im": 0 };
if (a === void 0 || a === null) {
z["re"] = z["im"] = 0;
} else if (b !== void 0) {
z["re"] = a;
z["im"] = b;
} else
switch (typeof a) {
case "object":
if ("im" in a && "re" in a) {
z["re"] = a["re"];
z["im"] = a["im"];
} else if ("abs" in a && "arg" in a) {
if (!Number.isFinite(a["abs"]) && Number.isFinite(a["arg"])) {
return Complex["INFINITY"];
}
z["re"] = a["abs"] * Math.cos(a["arg"]);
z["im"] = a["abs"] * Math.sin(a["arg"]);
} else if ("r" in a && "phi" in a) {
if (!Number.isFinite(a["r"]) && Number.isFinite(a["phi"])) {
return Complex["INFINITY"];
}
z["re"] = a["r"] * Math.cos(a["phi"]);
z["im"] = a["r"] * Math.sin(a["phi"]);
} else if (a.length === 2) {
z["re"] = a[0];
z["im"] = a[1];
} else {
parser_exit();
}
break;
case "string":
z["im"] = /* void */
z["re"] = 0;
var tokens = a.match(/\d+\.?\d*e[+-]?\d+|\d+\.?\d*|\.\d+|./g);
var plus = 1;
var minus = 0;
if (tokens === null) {
parser_exit();
}
for (var i = 0; i < tokens.length; i++) {
var c = tokens[i];
if (c === " " || c === " " || c === "\n") {
} else if (c === "+") {
plus++;
} else if (c === "-") {
minus++;
} else if (c === "i" || c === "I") {
if (plus + minus === 0) {
parser_exit();
}
if (tokens[i + 1] !== " " && !isNaN(Number(tokens[i + 1]))) {
z["im"] += parseFloat((minus % 2 ? "-" : "") + tokens[i + 1]);
i++;
} else {
z["im"] += parseFloat((minus % 2 ? "-" : "") + "1");
}
plus = minus = 0;
} else {
if (plus + minus === 0 || isNaN(Number(c))) {
parser_exit();
}
if (tokens[i + 1] === "i" || tokens[i + 1] === "I") {
z["im"] += parseFloat((minus % 2 ? "-" : "") + c);
i++;
} else {
z["re"] += parseFloat((minus % 2 ? "-" : "") + c);
}
plus = minus = 0;
}
}
if (plus + minus > 0) {
parser_exit();
}
break;
case "number":
z["im"] = 0;
z["re"] = a;
break;
default:
parser_exit();
}
if (isNaN(z["re"]) || isNaN(z["im"])) {
}
return z;
};
var Complex = class _Complex {
constructor(a, b) {
this.re = 0;
this.im = 0;
var z = parse(a, b);
this["re"] = z["re"];
this["im"] = z["im"];
}
/**
* Calculates the sign of a complex number, which is a normalized complex
*
* @returns {Complex}
*/
sign() {
var abs2 = this["abs"]();
return new _Complex(this["re"] / abs2, this["im"] / abs2);
}
/**
* Adds two complex numbers
*
* @returns {Complex}
*/
add(a, b) {
var z = new _Complex(a, b);
if (this["isInfinite"]() && z["isInfinite"]()) {
return _Complex["NAN"];
}
if (this["isInfinite"]() || z["isInfinite"]()) {
return _Complex["INFINITY"];
}
return new _Complex(this["re"] + z["re"], this["im"] + z["im"]);
}
/**
* Subtracts two complex numbers
*
* @returns {Complex}
*/
sub(a, b) {
var z = new _Complex(a, b);
if (this["isInfinite"]() && z["isInfinite"]()) {
return _Complex["NAN"];
}
if (this["isInfinite"]() || z["isInfinite"]()) {
return _Complex["INFINITY"];
}
return new _Complex(this["re"] - z["re"], this["im"] - z["im"]);
}
/**
* Multiplies two complex numbers
*
* @returns {Complex}
*/
mul(a, b) {
var z = new _Complex(a, b);
if (this["isInfinite"]() && z["isZero"]() || this["isZero"]() && z["isInfinite"]()) {
return _Complex["NAN"];
}
if (this["isInfinite"]() || z["isInfinite"]()) {
return _Complex["INFINITY"];
}
if (z["im"] === 0 && this["im"] === 0) {
return new _Complex(this["re"] * z["re"], 0);
}
return new _Complex(this["re"] * z["re"] - this["im"] * z["im"], this["re"] * z["im"] + this["im"] * z["re"]);
}
/**
* Divides two complex numbers
*
* @returns {Complex}
*/
div(a, b) {
var z = new _Complex(a, b);
if (this["isZero"]() && z["isZero"]() || this["isInfinite"]() && z["isInfinite"]()) {
return _Complex["NAN"];
}
if (this["isInfinite"]() || z["isZero"]()) {
return _Complex["INFINITY"];
}
if (this["isZero"]() || z["isInfinite"]()) {
return _Complex["ZERO"];
}
a = this["re"];
b = this["im"];
var c = z["re"];
var d = z["im"];
var t, x;
if (0 === d) {
return new _Complex(a / c, b / c);
}
if (Math.abs(c) < Math.abs(d)) {
x = c / d;
t = c * x + d;
return new _Complex((a * x + b) / t, (b * x - a) / t);
} else {
x = d / c;
t = d * x + c;
return new _Complex((a + b * x) / t, (b - a * x) / t);
}
}
/**
* Calculate the power of two complex numbers
*
* @returns {Complex}
*/
pow(a, b) {
var z = new _Complex(a, b);
a = this["re"];
b = this["im"];
if (z["isZero"]()) {
return _Complex["ONE"];
}
if (z["im"] === 0) {
if (b === 0 && a > 0) {
return new _Complex(Math.pow(a, z["re"]), 0);
} else if (a === 0) {
switch ((z["re"] % 4 + 4) % 4) {
case 0:
return new _Complex(Math.pow(b, z["re"]), 0);
case 1:
return new _Complex(0, Math.pow(b, z["re"]));
case 2:
return new _Complex(-Math.pow(b, z["re"]), 0);
case 3:
return new _Complex(0, -Math.pow(b, z["re"]));
}
}
}
if (a === 0 && b === 0 && z["re"] > 0 && z["im"] >= 0) {
return _Complex["ZERO"];
}
var arg = Math.atan2(b, a);
var loh = logHypot(a, b);
a = Math.exp(z["re"] * loh - z["im"] * arg);
b = z["im"] * loh + z["re"] * arg;
return new _Complex(a * Math.cos(b), a * Math.sin(b));
}
/**
* Calculate the complex square root
*
* @returns {Complex}
*/
sqrt() {
var a = this["re"];
var b = this["im"];
var r = this["abs"]();
var re, im;
if (a >= 0) {
if (b === 0) {
return new _Complex(Math.sqrt(a), 0);
}
re = 0.5 * Math.sqrt(2 * (r + a));
} else {
re = Math.abs(b) / Math.sqrt(2 * (r - a));
}
if (a <= 0) {
im = 0.5 * Math.sqrt(2 * (r - a));
} else {
im = Math.abs(b) / Math.sqrt(2 * (r + a));
}
return new _Complex(re, b < 0 ? -im : im);
}
/**
* Calculate the complex exponent
*
* @returns {Complex}
*/
exp() {
var tmp = Math.exp(this["re"]);
if (this["im"] === 0) {
}
return new _Complex(tmp * Math.cos(this["im"]), tmp * Math.sin(this["im"]));
}
/**
* Calculate the complex exponent and subtracts one.
*
* This may be more accurate than `Complex(x).exp().sub(1)` if
* `x` is small.
*
* @returns {Complex}
*/
expm1() {
var a = this["re"];
var b = this["im"];
return new _Complex(Math.expm1(a) * Math.cos(b) + cosm1(b), Math.exp(a) * Math.sin(b));
}
/**
* Calculate the natural log
*
* @returns {Complex}
*/
log() {
var a = this["re"];
var b = this["im"];
if (b === 0 && a > 0) {
}
return new _Complex(logHypot(a, b), Math.atan2(b, a));
}
/**
* Calculate the magnitude of the complex number
*
* @returns {number}
*/
abs() {
return hypot(this["re"], this["im"]);
}
/**
* Calculate the angle of the complex number
*
* @returns {number}
*/
arg() {
return Math.atan2(this["im"], this["re"]);
}
/**
* Calculate the sine of the complex number
*
* @returns {Complex}
*/
sin() {
var a = this["re"];
var b = this["im"];
return new _Complex(Math.sin(a) * cosh(b), Math.cos(a) * sinh(b));
}
/**
* Calculate the cosine
*
* @returns {Complex}
*/
cos() {
var a = this["re"];
var b = this["im"];
return new _Complex(Math.cos(a) * cosh(b), -Math.sin(a) * sinh(b));
}
/**
* Calculate the tangent
*
* @returns {Complex}
*/
tan() {
var a = 2 * this["re"];
var b = 2 * this["im"];
var d = Math.cos(a) + cosh(b);
return new _Complex(Math.sin(a) / d, sinh(b) / d);
}
/**
* Calculate the cotangent
*
* @returns {Complex}
*/
cot() {
var a = 2 * this["re"];
var b = 2 * this["im"];
var d = Math.cos(a) - cosh(b);
return new _Complex(-Math.sin(a) / d, sinh(b) / d);
}
/**
* Calculate the secant
*
* @returns {Complex}
*/
sec() {
var a = this["re"];
var b = this["im"];
var d = 0.5 * cosh(2 * b) + 0.5 * Math.cos(2 * a);
return new _Complex(Math.cos(a) * cosh(b) / d, Math.sin(a) * sinh(b) / d);
}
/**
* Calculate the cosecans
*
* @returns {Complex}
*/
csc() {
var a = this["re"];
var b = this["im"];
var d = 0.5 * cosh(2 * b) - 0.5 * Math.cos(2 * a);
return new _Complex(Math.sin(a) * cosh(b) / d, -Math.cos(a) * sinh(b) / d);
}
/**
* Calculate the complex arcus sinus
*
* @returns {Complex}
*/
asin() {
var a = this["re"];
var b = this["im"];
var t1 = new _Complex(b * b - a * a + 1, -2 * a * b)["sqrt"]();
var t2 = new _Complex(t1["re"] - b, t1["im"] + a)["log"]();
return new _Complex(t2["im"], -t2["re"]);
}
/**
* Calculate the complex arcus cosinus
*
* @returns {Complex}
*/
acos() {
var a = this["re"];
var b = this["im"];
var t1 = new _Complex(b * b - a * a + 1, -2 * a * b)["sqrt"]();
var t2 = new _Complex(t1["re"] - b, t1["im"] + a)["log"]();
return new _Complex(Math.PI / 2 - t2["im"], t2["re"]);
}
/**
* Calculate the complex arcus tangent
*
* @returns {Complex}
*/
atan() {
var a = this["re"];
var b = this["im"];
if (a === 0) {
if (b === 1) {
return new _Complex(0, Infinity);
}
if (b === -1) {
return new _Complex(0, -Infinity);
}
}
var d = a * a + (1 - b) * (1 - b);
var t1 = new _Complex((1 - b * b - a * a) / d, -2 * a / d).log();
return new _Complex(-0.5 * t1["im"], 0.5 * t1["re"]);
}
/**
* Calculate the complex arcus cotangent
*
* @returns {Complex}
*/
acot() {
var a = this["re"];
var b = this["im"];
if (b === 0) {
return new _Complex(Math.atan2(1, a), 0);
}
var d = a * a + b * b;
return d !== 0 ? new _Complex(a / d, -b / d).atan() : new _Complex(a !== 0 ? a / 0 : 0, b !== 0 ? -b / 0 : 0).atan();
}
/**
* Calculate the complex arcus secant
*
* @returns {Complex}
*/
asec() {
var a = this["re"];
var b = this["im"];
if (a === 0 && b === 0) {
return new _Complex(0, Infinity);
}
var d = a * a + b * b;
return d !== 0 ? new _Complex(a / d, -b / d).acos() : new _Complex(a !== 0 ? a / 0 : 0, b !== 0 ? -b / 0 : 0).acos();
}
/**
* Calculate the complex arcus cosecans
*
* @returns {Complex}
*/
acsc() {
var a = this["re"];
var b = this["im"];
if (a === 0 && b === 0) {
return new _Complex(Math.PI / 2, Infinity);
}
var d = a * a + b * b;
return d !== 0 ? new _Complex(a / d, -b / d).asin() : new _Complex(a !== 0 ? a / 0 : 0, b !== 0 ? -b / 0 : 0).asin();
}
/**
* Calculate the complex sinh
*
* @returns {Complex}
*/
sinh() {
var a = this["re"];
var b = this["im"];
return new _Complex(sinh(a) * Math.cos(b), cosh(a) * Math.sin(b));
}
/**
* Calculate the complex cosh
*
* @returns {Complex}
*/
cosh() {
var a = this["re"];
var b = this["im"];
return new _Complex(cosh(a) * Math.cos(b), sinh(a) * Math.sin(b));
}
/**
* Calculate the complex tanh
*
* @returns {Complex}
*/
tanh() {
var a = 2 * this["re"];
var b = 2 * this["im"];
var d = cosh(a) + Math.cos(b);
return new _Complex(sinh(a) / d, Math.sin(b) / d);
}
/**
* Calculate the complex coth
*
* @returns {Complex}
*/
coth() {
var a = 2 * this["re"];
var b = 2 * this["im"];
var d = cosh(a) - Math.cos(b);
return new _Complex(sinh(a) / d, -Math.sin(b) / d);
}
/**
* Calculate the complex coth
*
* @returns {Complex}
*/
csch() {
var a = this["re"];
var b = this["im"];
var d = Math.cos(2 * b) - cosh(2 * a);
return new _Complex(-2 * sinh(a) * Math.cos(b) / d, 2 * cosh(a) * Math.sin(b) / d);
}
/**
* Calculate the complex sech
*
* @returns {Complex}
*/
sech() {
var a = this["re"];
var b = this["im"];
var d = Math.cos(2 * b) + cosh(2 * a);
return new _Complex(2 * cosh(a) * Math.cos(b) / d, -2 * sinh(a) * Math.sin(b) / d);
}
/**
* Calculate the complex asinh
*
* @returns {Complex}
*/
asinh() {
var tmp = this["im"];
this["im"] = -this["re"];
this["re"] = tmp;
var res = this["asin"]();
this["re"] = -this["im"];
this["im"] = tmp;
tmp = res["re"];
res["re"] = -res["im"];
res["im"] = tmp;
return res;
}
/**
* Calculate the complex acosh
*
* @returns {Complex}
*/
acosh() {
var res = this["acos"]();
if (res["im"] <= 0) {
var tmp = res["re"];
res["re"] = -res["im"];
res["im"] = tmp;
} else {
var tmp = res["im"];
res["im"] = -res["re"];
res["re"] = tmp;
}
return res;
}
/**
* Calculate the complex atanh
*
* @returns {Complex}
*/
atanh() {
var a = this["re"];
var b = this["im"];
var noIM = a > 1 && b === 0;
var oneMinus = 1 - a;
var onePlus = 1 + a;
var d = oneMinus * oneMinus + b * b;
var x = d !== 0 ? new _Complex((onePlus * oneMinus - b * b) / d, (b * oneMinus + onePlus * b) / d) : new _Complex(a !== -1 ? a / 0 : 0, b !== 0 ? b / 0 : 0);
var temp = x["re"];
x["re"] = logHypot(x["re"], x["im"]) / 2;
x["im"] = Math.atan2(x["im"], temp) / 2;
if (noIM) {
x["im"] = -x["im"];
}
return x;
}
/**
* Calculate the complex acoth
*
* @returns {Complex}
*/
acoth() {
var a = this["re"];
var b = this["im"];
if (a === 0 && b === 0) {
return new _Complex(0, Math.PI / 2);
}
var d = a * a + b * b;
return d !== 0 ? new _Complex(a / d, -b / d).atanh() : new _Complex(a !== 0 ? a / 0 : 0, b !== 0 ? -b / 0 : 0).atanh();
}
/**
* Calculate the complex acsch
*
* @returns {Complex}
*/
acsch() {
var a = this["re"];
var b = this["im"];
if (b === 0) {
return new _Complex(a !== 0 ? Math.log(a + Math.sqrt(a * a + 1)) : Infinity, 0);
}
var d = a * a + b * b;
return d !== 0 ? new _Complex(a / d, -b / d).asinh() : new _Complex(a !== 0 ? a / 0 : 0, b !== 0 ? -b / 0 : 0).asinh();
}
/**
* Calculate the complex asech
*
* @returns {Complex}
*/
asech() {
var a = this["re"];
var b = this["im"];
if (this["isZero"]()) {
return _Complex["INFINITY"];
}
var d = a * a + b * b;
return d !== 0 ? new _Complex(a / d, -b / d).acosh() : new _Complex(a !== 0 ? a / 0 : 0, b !== 0 ? -b / 0 : 0).acosh();
}
/**
* Calculate the complex inverse 1/z
*
* @returns {Complex}
*/
inverse() {
if (this["isZero"]()) {
return _Complex["INFINITY"];
}
if (this["isInfinite"]()) {
return _Complex["ZERO"];
}
var a = this["re"];
var b = this["im"];
var d = a * a + b * b;
return new _Complex(a / d, -b / d);
}
/**
* Returns the complex conjugate
*
* @returns {Complex}
*/
conjugate() {
return new _Complex(this["re"], -this["im"]);
}
/**
* Gets the negated complex number
*
* @returns {Complex}
*/
neg() {
return new _Complex(-this["re"], -this["im"]);
}
/**
* Ceils the actual complex number
*
* @returns {Complex}
*/
ceil(places) {
places = Math.pow(10, places || 0);
return new _Complex(Math.ceil(this["re"] * places) / places, Math.ceil(this["im"] * places) / places);
}
/**
* Floors the actual complex number
*
* @returns {Complex}
*/
floor(places) {
places = Math.pow(10, places || 0);
return new _Complex(Math.floor(this["re"] * places) / places, Math.floor(this["im"] * places) / places);
}
/**
* Ceils the actual complex number
*
* @returns {Complex}
*/
round(places) {
places = Math.pow(10, places || 0);
return new _Complex(Math.round(this["re"] * places) / places, Math.round(this["im"] * places) / places);
}
/**
* Compares two complex numbers
*
* **Note:** new Complex(Infinity).equals(Infinity) === false
*
* @returns {boolean}
*/
equals(a, b) {
var z = new _Complex(a, b);
return Math.abs(z["re"] - this["re"]) <= _Complex["EPSILON"] && Math.abs(z["im"] - this["im"]) <= _Complex["EPSILON"];
}
/**
* Clones the actual object
*
* @returns {Complex}
*/
clone() {
return new _Complex(this["re"], this["im"]);
}
/**
* Gets a string of the actual complex number
*
* @returns {string}
*/
toString() {
var a = this["re"];
var b = this["im"];
var ret = "";
if (this["isNaN"]()) {
return "NaN";
}
if (this["isInfinite"]()) {
return "Infinity";
}
if (Math.abs(a) < _Complex["EPSILON"]) {
a = 0;
}
if (Math.abs(b) < _Complex["EPSILON"]) {
b = 0;
}
if (b === 0) {
return ret + a;
}
if (a !== 0) {
ret += a;
ret += " ";
if (b < 0) {
b = -b;
ret += "-";
} else {
ret += "+";
}
ret += " ";
} else if (b < 0) {
b = -b;
ret += "-";
}
if (1 !== b) {
ret += b;
}
return ret + "i";
}
/**
* Returns the actual number as a vector
*
* @returns {Array}
*/
toVector() {
return [this["re"], this["im"]];
}
/**
* Returns the actual real value of the current object
*
* @returns {number|null}
*/
valueOf() {
if (this["im"] === 0) {
return this["re"];
}
return null;
}
/**
* Determines whether a complex number is not on the Riemann sphere.
*
* @returns {boolean}
*/
isNaN() {
return isNaN(this["re"]) || isNaN(this["im"]);
}
/**
* Determines whether or not a complex number is at the zero pole of the
* Riemann sphere.
*
* @returns {boolean}
*/
isZero() {
return this["im"] === 0 && this["re"] === 0;
}
/**
* Determines whether a complex number is not at the infinity pole of the
* Riemann sphere.
*
* @returns {boolean}
*/
isFinite() {
return isFinite(this["re"]) && isFinite(this["im"]);
}
/**
* Determines whether or not a complex number is at the infinity pole of the
* Riemann sphere.
*
* @returns {boolean}
*/
isInfinite() {
return !(this["isNaN"]() || this["isFinite"]());
}
};
Complex["ZERO"] = new Complex(0, 0);
Complex["ONE"] = new Complex(1, 0);
Complex["I"] = new Complex(0, 1);
Complex["PI"] = new Complex(Math.PI, 0);
Complex["E"] = new Complex(Math.E, 0);
Complex["INFINITY"] = new Complex(Infinity, Infinity);
Complex["NAN"] = new Complex(NaN, NaN);
Complex["EPSILON"] = 1e-15;
// 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 sign2 = thisSig > 0n ? 1 : -1;
return thisMag > otherMag ? sign2 : -sign2;
}
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 exp3 = this.exponent;
if (exp3 >= 0) return this;
if (Number.isFinite(exp3)) {
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 exp3 = this.exponent;
if (exp3 >= 0) return this;
if (Number.isFinite(exp3)) {
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 exp3 = this.exponent;
if (exp3 >= 0) return this;
if (Number.isFinite(exp3)) {
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 exp3 = this.exponent;
if (exp3 >= 0) return this;
if (Number.isFinite(exp3)) {
const truncSig = this.significand / pow10(-exp3);
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 exp3 = expValue;
while (exp3 > 0n) {
if (exp3 & 1n) {
result = result.mul(base).toPrecision(prec);
}
exp3 >>= 1n;
if (exp3 > 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.s