@numio/bigmath
Version:
@numio/bigmath is an arbitrary-precision arithmetic library. It can be used for basic operations with decimal numbers (integers and float)
110 lines (109 loc) • 3.55 kB
JavaScript
export const bi2s = ([bigInt, fpe]) => {
if (bigInt === 0n)
return "0";
const isNeg = bigInt < 0n;
isNeg && (bigInt *= -1n);
const dp = bigInt % (10n ** tryBigInt(fpe));
const bigStr = bigInt.toString();
let fpIdx = bigStr.length - fpe;
if (fpIdx < 0)
fpIdx = 0;
const before = bigStr.slice(0, fpIdx);
const after = bigStr.slice(fpIdx);
if (before) {
return fillHead(bigStr.length, fpe, isNeg, true) +
(fpe > 0 && dp > 0 ? trimTail(`${before}.${after}`) : before);
}
return `${fillHead(bigStr.length, fpe, isNeg, false)}${trimTail(after)}`;
};
export const s2bi = (str, _fpi) => {
const fpi = _fpi !== null && _fpi !== void 0 ? _fpi : str.indexOf(".");
const isHex = str.startsWith("0x") || str.startsWith("-0x") ||
str.startsWith("-0X") || str.startsWith("0X");
const isOctal = str.startsWith("0o") || str.startsWith("-0o") ||
str.startsWith("-0O") || str.startsWith("0O");
const isBinary = str.startsWith("0b") || str.startsWith("-0b") ||
str.startsWith("-0B") || str.startsWith("0B");
if (fpi === -1 && !isHex && !isOctal && !isBinary)
return [tryBigInt(str), 0];
if (isHex || isBinary || isOctal) {
const isNegative = str[0] === "-";
const bi = tryBigInt(str.slice(isNegative ? 1 : 0));
return [isNegative ? -1n * bi : bi, 0];
}
if (str.length < 15 && str[0] !== "0") {
return [
tryBigInt(tryNumber(str.slice(0, fpi) + str.slice(fpi + 1), str)),
str.length - 1 - fpi,
];
}
return [
tryBigInt(str.slice(0, fpi) + str.slice(fpi + 1)),
str.length - 1 - fpi,
];
};
export const calcInner = (array, op, def) => {
let totalBi = def ? def[0] : array[0][0];
let totalFpe = def ? def[1] : array[0][1];
const opm = op(1n, 1n);
for (let i = def ? 0 : 1; i < array.length; i++) {
const [bi, fpe] = array[i];
if (fpe === 0 && totalFpe === 0) {
totalBi = op(totalBi, bi);
continue;
}
if (opm === 1n) {
totalBi = op(totalBi, bi);
totalFpe += fpe;
}
else {
if (totalFpe < fpe) {
const fpDiff = fpe - totalFpe;
totalBi = op(totalBi * (10n ** tryBigInt(fpDiff)), bi);
}
if (totalFpe > fpe) {
totalBi = op(totalBi, bi * (10n ** tryBigInt(totalFpe - fpe)));
}
if (totalFpe === fpe)
totalBi = op(totalBi, bi);
if (totalFpe < fpe)
totalFpe = fpe;
}
}
return [totalBi, totalFpe];
};
export const fillHead = (len, fpe, isNeg, hasBefore) => {
let head = (isNeg ? "-" : "") + (hasBefore ? "" : "0.");
while (len < fpe) {
head = head + "0";
len += 1;
}
return head;
};
export const trimTail = (str) => {
if (str[str.length - 1] !== "0")
return str;
let count = 0;
for (let i = str.length - 1; i >= 0; i -= 1) {
if (str[i] !== "0")
return str.slice(0, str.length - count);
count += 1;
}
return str;
};
export const tryBigInt = (value) => {
let bi;
try {
bi = BigInt(value);
}
catch (_) {
throw new Error(`Invalid input: ${value}`);
}
return bi;
};
export const tryNumber = (value, origin = value) => {
const num = +value;
if (Number.isNaN(num))
throw new Error(`Invalid input: ${origin}`);
return num;
};