exactnumber
Advanced tools
Comparing version 0.7.0 to 0.8.0
@@ -20,5 +20,6 @@ { | ||
"no-bitwise": "off", | ||
"no-continue": "off" | ||
"no-continue": "off", | ||
"no-underscore-dangle": "off" | ||
}, | ||
"ignorePatterns": [] | ||
} |
/*! | ||
* exactnumber v0.7.0 (https://www.npmjs.com/package/exactnumber) | ||
* exactnumber v0.8.0 (https://www.npmjs.com/package/exactnumber) | ||
* (c) Dani Biro | ||
@@ -35,2 +35,3 @@ * @license MIT | ||
/** Trims trailing zeros from numbers in fixed-point format (1.23000 -> 1.23) */ | ||
const trimTrailingZeros = (num) => { | ||
@@ -66,2 +67,13 @@ let zeropos = num.length; | ||
}; | ||
// export const modpow = (base: bigint, exp: bigint, mod: bigint) => { | ||
// let res = 1n; | ||
// while (exp > 0n) { | ||
// if (exp % 2n) { | ||
// res = (res * base) % mod; | ||
// } | ||
// base = base ** 2n % mod; | ||
// exp /= 2n; | ||
// } | ||
// return res; | ||
// }; | ||
@@ -156,8 +168,5 @@ class FixedNumber { | ||
const operand = parseParameter(x); | ||
if (!operand.isInteger()) { | ||
throw new Error('Invalid parameter'); | ||
} | ||
const exp = operand.toNumber(); | ||
if (!Number.isSafeInteger(exp)) { | ||
throw new Error('Invalid parameter'); | ||
if (!Number.isSafeInteger(exp) || exp < 0) { | ||
throw new Error('Unsupported parameter'); | ||
} | ||
@@ -214,3 +223,3 @@ const res = new FixedNumber(this.number ** BigInt(exp), this.decimalPos * exp); | ||
return this; | ||
return this.round(RoundingMode.TO_NEGATIVE, decimals); | ||
return this.round(decimals, RoundingMode.TO_NEGATIVE); | ||
} | ||
@@ -220,3 +229,3 @@ ceil(decimals) { | ||
return this; | ||
return this.round(RoundingMode.TO_POSITIVE, decimals); | ||
return this.round(decimals, RoundingMode.TO_POSITIVE); | ||
} | ||
@@ -226,5 +235,5 @@ trunc(decimals) { | ||
return this; | ||
return this.round(RoundingMode.TO_ZERO, decimals); | ||
return this.round(decimals, RoundingMode.TO_ZERO); | ||
} | ||
round(roundingMode, decimals) { | ||
round(decimals, roundingMode) { | ||
decimals = decimals === undefined ? 0 : decimals; | ||
@@ -256,2 +265,12 @@ if (!Number.isSafeInteger(decimals) || decimals < 0) { | ||
} | ||
if (![ | ||
undefined, | ||
RoundingMode.NEAREST_TO_ZERO, | ||
RoundingMode.NEAREST_AWAY_FROM_ZERO, | ||
RoundingMode.NEAREST_TO_POSITIVE, | ||
RoundingMode.NEAREST_TO_NEGATIVE, | ||
RoundingMode.NEAREST_TO_EVEN, | ||
].includes(roundingMode)) { | ||
throw new Error('Invalid rounding mode. Use the predefined values from the RoundingMode enum.'); | ||
} | ||
let fracStr = (fracPart < 0n ? -fracPart : fracPart).toString(); | ||
@@ -294,17 +313,28 @@ if (fracStr.length < expectedFracDecimals) { | ||
} | ||
if (roundingMode === undefined || | ||
roundingMode === RoundingMode.NEAREST_TO_ZERO || | ||
roundingMode === RoundingMode.NEAREST_AWAY_FROM_ZERO || | ||
roundingMode === RoundingMode.NEAREST_TO_POSITIVE || | ||
roundingMode === RoundingMode.NEAREST_TO_NEGATIVE || | ||
roundingMode === RoundingMode.NEAREST_TO_EVEN) { | ||
if (Number(fracStr[0]) < 5) { | ||
return new FixedNumber(numberToZero, decimals); | ||
if (Number(fracStr[0]) < 5) { | ||
return new FixedNumber(numberToZero, decimals); | ||
} | ||
const res = this.number < 0 ? numberToZero - 1n : numberToZero + 1n; | ||
return new FixedNumber(res, decimals); | ||
} | ||
_incExponent(amount) { | ||
if (amount === 0) | ||
return this; | ||
let newNumber = this.number; | ||
let newDecimalPos = this.decimalPos; | ||
if (amount < 0) { | ||
newDecimalPos -= amount; | ||
} | ||
else { | ||
// amount >= 0 | ||
const maxChange = Math.min(amount, this.decimalPos); | ||
newDecimalPos -= maxChange; | ||
const rem = amount - maxChange; | ||
if (rem > 0) { | ||
newNumber *= 10n ** BigInt(rem); | ||
} | ||
const res = this.number < 0 ? numberToZero - 1n : numberToZero + 1n; | ||
return new FixedNumber(res, decimals); | ||
} | ||
throw new Error('Invalid rounding mode. Use the predefined values from the RoundingMode enum.'); | ||
return new FixedNumber(newNumber, newDecimalPos); | ||
} | ||
roundToDigits(roundingMode, digits) { | ||
roundToDigits(digits, roundingMode) { | ||
if (!Number.isSafeInteger(digits) || digits < 1) { | ||
@@ -317,12 +347,6 @@ throw new Error('Invalid value for digits'); | ||
const str = absNumber.toString(); | ||
const newNumber = new FixedNumber(`0.${str}`); | ||
let roundedNumber = newNumber.round(roundingMode, digits); | ||
const totalDigits = str.length; | ||
const wholeDigits = totalDigits - this.decimalPos; | ||
if (wholeDigits < 0) { | ||
roundedNumber = roundedNumber.div(10n ** BigInt(-wholeDigits)); | ||
} | ||
else { | ||
roundedNumber = roundedNumber.mul(10n ** BigInt(wholeDigits)); | ||
} | ||
const numberBetweenZeroAndOne = new FixedNumber(absNumber, str.length); | ||
let roundedNumber = numberBetweenZeroAndOne.round(digits, roundingMode); | ||
const integerDigits = str.length - this.decimalPos; | ||
roundedNumber = roundedNumber._incExponent(integerDigits); | ||
return isNegative ? roundedNumber.neg() : roundedNumber; | ||
@@ -508,23 +532,22 @@ } | ||
} | ||
toFixed(digits, trimTrailingZeros) { | ||
if (!Number.isSafeInteger(digits) || digits < 0) | ||
toFixed(decimals, roundingMode = RoundingMode.TO_ZERO) { | ||
if (!Number.isSafeInteger(decimals) || decimals < 0) | ||
throw new Error('Invalid parameter'); | ||
const extraDigitsNeeded = digits - this.decimalPos; | ||
const exp = 10n ** BigInt(Math.abs(extraDigitsNeeded)); | ||
const num = extraDigitsNeeded < 0 ? this.number / exp : this.number * exp; | ||
const res = bigIntToStr(num, digits, Boolean(trimTrailingZeros)); | ||
return res; | ||
const rounded = this.round(decimals, roundingMode); | ||
return bigIntToStr(rounded.number, decimals, false); | ||
} | ||
toExponential(digits) { | ||
toExponential(digits, roundingMode = RoundingMode.TO_ZERO) { | ||
if (!Number.isSafeInteger(digits) || digits < 0) | ||
throw new Error('Invalid parameter'); | ||
const isNegative = this.number < 0n; | ||
const absNumber = isNegative ? -this.number : this.number; | ||
const str = absNumber.toString(); | ||
const rounded = this.roundToDigits(digits + 1, roundingMode).normalize(); | ||
const isNegative = rounded.sign() === -1; | ||
const absNumber = rounded.abs(); | ||
const str = absNumber.number.toString(); | ||
const slicedString = str.length <= digits ? `${str}${'0'.repeat(digits - str.length + 1)}` : str.slice(0, digits + 1); | ||
const strWithPoint = slicedString.length > 1 ? `${slicedString.slice(0, 1)}.${slicedString.slice(1)}` : slicedString; | ||
const fractionalDigitsBefore = this.decimalPos; | ||
const fractionalDigitsBefore = absNumber.decimalPos; | ||
const fractionalDigitsAfter = str.length - 1; | ||
const exponent = fractionalDigitsAfter - fractionalDigitsBefore; | ||
return `${isNegative ? '-' : ''}${strWithPoint}e${exponent >= 0 ? '+' : ''}${exponent}`; | ||
const res = `${isNegative ? '-' : ''}${strWithPoint}e${exponent >= 0 ? '+' : ''}${exponent}`; | ||
return res; | ||
} | ||
@@ -537,9 +560,6 @@ toBase(radix, maxDigits) { | ||
} | ||
if (radix === 10) { | ||
return maxDigits === undefined ? this.toString() : this.toFixed(maxDigits, true); | ||
} | ||
const num = this.normalize(); | ||
if (num.decimalPos === 0) | ||
return num.number.toString(radix); | ||
const loopEnd = maxDigits === undefined ? Number.MAX_SAFE_INTEGER : maxDigits + 1; | ||
const loopEnd = maxDigits === undefined ? Number.MAX_SAFE_INTEGER : maxDigits; | ||
let intPart = num.intPart(); | ||
@@ -555,4 +575,2 @@ let fracPart = num.sub(intPart); | ||
while (!fracPart.isZero()) { | ||
if (digits.length === loopEnd) | ||
break; | ||
const mul = fracPart.mul(radix); | ||
@@ -565,2 +583,5 @@ const mulStr = mul.toString(); | ||
} | ||
if (digits.length === loopEnd) { | ||
break; | ||
} | ||
const q = Math.abs(mul.intPart().toNumber()); | ||
@@ -571,5 +592,2 @@ digits.push(q.toString(radix)); | ||
} | ||
if (digits.length === loopEnd) { | ||
digits.pop(); | ||
} | ||
return [isNegative ? '-' : '', intPart.number.toString(radix), digits.length ? '.' : '', ...digits].join(''); | ||
@@ -587,2 +605,9 @@ } | ||
} | ||
toPrecision(digits, roundingMode = RoundingMode.TO_ZERO) { | ||
if (!Number.isSafeInteger(digits) || digits < 1) | ||
throw new Error('Invalid parameter'); | ||
const rounded = this.roundToDigits(digits, roundingMode); | ||
const res = bigIntToStr(rounded.number, rounded.decimalPos, false); | ||
return res; | ||
} | ||
valueOf() { | ||
@@ -620,3 +645,3 @@ throw new Error('Unsafe conversion to Number type! Use toNumber() instead.'); | ||
if (!m) { | ||
throw new Error(`Cannot parse number "${x}"`); | ||
throw new Error(`Cannot parse string "${x}"`); | ||
} | ||
@@ -673,2 +698,8 @@ const wholePart = m[1] === '-' ? '-0' : m[1]; | ||
} | ||
// if (false) { | ||
// const commonDenominator = this.lcm(this.denominator, denominator); | ||
// const lMultiplier = commonDenominator / this.denominator; | ||
// const rMultiplier = commonDenominator / denominator; | ||
// return new Fraction(this.numerator * lMultiplier + numerator * rMultiplier, commonDenominator); | ||
// } | ||
return new Fraction(this.numerator * denominator + numerator * this.denominator, denominator * this.denominator); | ||
@@ -691,3 +722,3 @@ } | ||
const num = this.div(x); | ||
return num.round(); | ||
return num.trunc(); | ||
} | ||
@@ -714,6 +745,8 @@ mod(r, type = ModType.TRUNCATED) { | ||
pow(x) { | ||
const { numerator, denominator } = this.parseParameter(x); | ||
if (denominator !== 1n) | ||
const param = this.parseParameter(x); | ||
if (!param.isInteger() || param.sign() === -1) { | ||
throw new Error('Unsupported parameter'); | ||
const res = new Fraction(this.numerator ** numerator, this.denominator ** numerator); | ||
} | ||
const intNum = param.numerator / param.denominator; | ||
const res = new Fraction(this.numerator ** intNum, this.denominator ** intNum); | ||
return res; | ||
@@ -728,3 +761,3 @@ } | ||
return new FixedNumber(this.numerator); | ||
return this.round(RoundingMode.TO_NEGATIVE, decimals); | ||
return this.round(decimals, RoundingMode.TO_NEGATIVE); | ||
} | ||
@@ -734,3 +767,3 @@ ceil(decimals) { | ||
return new FixedNumber(this.numerator); | ||
return this.round(RoundingMode.TO_POSITIVE, decimals); | ||
return this.round(decimals, RoundingMode.TO_POSITIVE); | ||
} | ||
@@ -740,5 +773,5 @@ trunc(decimals) { | ||
return new FixedNumber(this.numerator); | ||
return this.round(RoundingMode.TO_ZERO, decimals); | ||
return this.round(decimals, RoundingMode.TO_ZERO); | ||
} | ||
round(roundingMode, decimals) { | ||
round(decimals, roundingMode) { | ||
decimals = decimals === undefined ? 0 : decimals; | ||
@@ -753,3 +786,3 @@ if (!Number.isSafeInteger(decimals) || decimals < 0) { | ||
// nothing is lost | ||
return fixedPart.round(roundingMode, decimals); | ||
return fixedPart.round(decimals, roundingMode); | ||
} | ||
@@ -759,6 +792,6 @@ // 0.105 might got cutted to 0.1, which might round incorrectly | ||
const correctedFixedNum = new FixedNumber(`${fixedPart.toFixed(decimals + 1)}1`); | ||
const res = correctedFixedNum.round(roundingMode, decimals); | ||
const res = correctedFixedNum.round(decimals, roundingMode); | ||
return res; | ||
} | ||
roundToDigits(roundingMode, digits) { | ||
roundToDigits(digits, roundingMode) { | ||
if (!Number.isSafeInteger(digits) || digits < 1) { | ||
@@ -768,3 +801,3 @@ throw new Error('Invalid value for digits'); | ||
if (this.isZero()) | ||
return this; | ||
return new FixedNumber(0n); | ||
let x = this.abs(); | ||
@@ -782,9 +815,4 @@ // move the number to the [0.1, 1) interval | ||
} | ||
let roundedNumber = x.round(roundingMode, digits); | ||
if (divisions < 0) { | ||
roundedNumber = roundedNumber.div(10n ** BigInt(-divisions)); | ||
} | ||
else { | ||
roundedNumber = roundedNumber.mul(10n ** BigInt(divisions)); | ||
} | ||
let roundedNumber = x.round(digits, roundingMode); | ||
roundedNumber = roundedNumber._incExponent(divisions); | ||
return this.sign() === -1 ? roundedNumber.neg() : roundedNumber; | ||
@@ -956,12 +984,7 @@ } | ||
// eslint-disable-next-line @typescript-eslint/no-shadow | ||
toFixed(digits, trimTrailingZeros) { | ||
if (!Number.isSafeInteger(digits) || digits < 0) | ||
toFixed(decimals, roundingMode = RoundingMode.TO_ZERO) { | ||
if (!Number.isSafeInteger(decimals) || decimals < 0) | ||
throw new Error('Invalid parameter'); | ||
let { numerator } = this; | ||
if (digits > 0) { | ||
numerator *= 10n ** BigInt(digits); | ||
} | ||
const n = numerator / this.denominator; | ||
const res = bigIntToStr(n, digits, Boolean(trimTrailingZeros)); | ||
return res; | ||
const [number, decimalPos] = this.round(decimals, roundingMode).serialize(); | ||
return bigIntToStr(number, decimalPos, false); | ||
} | ||
@@ -996,7 +1019,7 @@ toRepeatingParts(maxDigits) { | ||
} | ||
toExponential(digits) { | ||
toExponential(digits, roundingMode = RoundingMode.TO_ZERO) { | ||
if (!Number.isSafeInteger(digits) || digits < 0) | ||
throw new Error('Invalid parameters'); | ||
const fixedNum = this.toFixedNumber(digits); | ||
return fixedNum.toExponential(digits); | ||
return fixedNum.toExponential(digits, roundingMode); | ||
} | ||
@@ -1019,3 +1042,3 @@ toFraction() { | ||
if (radix === 10) { | ||
return maxDigits === undefined ? this.toRepeatingDigits(maxDigits) : this.toFixed(maxDigits, true); | ||
return maxDigits === undefined ? this.toRepeatingDigits(maxDigits) : trimTrailingZeros(this.toFixed(maxDigits)); | ||
} | ||
@@ -1059,2 +1082,8 @@ const num = this.normalize(); | ||
} | ||
toPrecision(digits, roundingMode = RoundingMode.TO_ZERO) { | ||
if (!Number.isSafeInteger(digits) || digits < 1) | ||
throw new Error('Invalid parameter'); | ||
const [number, decimalPos] = this.roundToDigits(digits, roundingMode).serialize(); | ||
return bigIntToStr(number, decimalPos, false); | ||
} | ||
valueOf() { | ||
@@ -1386,3 +1415,3 @@ throw new Error('Unsafe conversion to Number type! Use toNumber() instead.'); | ||
const { x, quadrant } = toLessThanHalfPi(ExactNumber(angle), EXTRA_DIGITS); | ||
const x2 = x.round(RoundingMode.NEAREST_AWAY_FROM_ZERO, EXTRA_DIGITS).pow(2n).normalize(); | ||
const x2 = x.round(EXTRA_DIGITS, RoundingMode.NEAREST_AWAY_FROM_ZERO).pow(2n).normalize(); | ||
// cos x = 1 - x^2/2! + x^4/4! - ... | ||
@@ -1427,3 +1456,3 @@ let xPow = x2; | ||
const res = quadrant === 1 || quadrant === 4 ? xk : xk.neg(); | ||
const strRes = res.round(RoundingMode.TO_ZERO, digits + 3).toFixed(digits); | ||
const strRes = res.round(digits + 3, RoundingMode.TO_ZERO).toFixed(digits); | ||
return strRes; | ||
@@ -1576,2 +1605,2 @@ }; | ||
export { ExactNumber, ModType, PI, RoundingMode, acos, asin, atan, cbrt, cos, cosh, exp, log, log10, log2, logn, nthroot, pow, sin, sinh, sqrt, tan }; | ||
export { ExactNumber, ModType, PI, RoundingMode, acos, asin, atan, cbrt, cos, cosh, exp, log, log10, log2, logn, nthroot, pow, sin, sinh, sqrt, tan, trimTrailingZeros }; |
/*! | ||
* exactnumber v0.7.0 (https://www.npmjs.com/package/exactnumber) | ||
* exactnumber v0.8.0 (https://www.npmjs.com/package/exactnumber) | ||
* (c) Dani Biro | ||
@@ -7,2 +7,2 @@ * @license MIT | ||
var t,n;!function(t){t.NEAREST_TO_POSITIVE="NP",t.NEAREST_TO_NEGATIVE="NN",t.NEAREST_TO_EVEN="NE",t.NEAREST_TO_ZERO="NZ",t.NEAREST_AWAY_FROM_ZERO="NA",t.TO_POSITIVE="P",t.TO_NEGATIVE="N",t.TO_ZERO="Z",t.AWAY_FROM_ZERO="A"}(t||(t={})),function(t){t.TRUNCATED="T",t.FLOORED="F",t.EUCLIDEAN="E"}(n||(n={}));const r=t=>{let n=t.length;for(;n>0&&["0","."].includes(t.charAt(n-1));)n--;return n!==t.length?t.slice(0,n):t},e=(t,n,e)=>{let i=t.toString();if(0===n)return i;const o=i.startsWith("-");if(o&&(i=i.slice(1)),n>=i.length&&(i="0".repeat(n-i.length+1)+i),n>0){const t=i.slice(0,-n);let o=i.slice(-n);e&&(o=r(o)),i=o.length?`${t}.${o}`:t}return o?`-${i}`:i};class i{constructor(t,n=0){if(this.type="fixed","bigint"==typeof t)this.number=t,this.decimalPos=n;else{const n=this.parseConstructorParameter(t);this.number=n.number,this.decimalPos=n.decimalPos}}parseConstructorParameter(t){if(t instanceof i)return{number:t.number,decimalPos:t.decimalPos};if(t instanceof o){if(!t.isInteger())throw new Error("Cannot create FixedNumber from non-integer Fraction");return{number:t.trunc().number,decimalPos:0}}if("number"==typeof t){if(!Number.isSafeInteger(t))throw new Error("The specified number cannot be exactly represented as an integer. Please provide a string instead.");return{number:BigInt(t),decimalPos:0}}if("string"==typeof t){if(0===(t=t.trim()).length)throw new Error("Empty string is not allowed");const n=t.match(/^(-?[0-9]*)(?:\.([0-9]*))?(?:[eE]([+-]?[0-9]+))?$/);if(!n)throw new Error(`Cannot parse number "${t}"`);let r=0,e=n[1]??"0";if(void 0!==n[2]&&(e+=n[2],r+=n[2].length),void 0!==n[3]){const t=Number(n[3]);t>0?e+="0".repeat(t):r-=t}return{number:BigInt(e),decimalPos:r}}throw new Error("Unsupported parameter!")}scaleNumber(t,n){const r=Math.max(this.decimalPos,n);return{a:r===this.decimalPos?this.number:this.number*10n**BigInt(r-this.decimalPos),b:r===n?t:t*10n**BigInt(r-n),decimalPos:r}}add(t){const n=s(t);if(n instanceof o)return n.add(this);const r=n,{a:e,b:a,decimalPos:u}=this.scaleNumber(r.number,r.decimalPos);return new i(e+a,u)}sub(t){const n=s(t);return this.add(n.neg())}mul(t){const n=s(t);if(n instanceof o)return n.mul(this);const r=n;return new i(this.number*r.number,this.decimalPos+r.decimalPos)}pow(t){const n=s(t);if(!n.isInteger())throw new Error("Invalid parameter");const r=n.toNumber();if(!Number.isSafeInteger(r))throw new Error("Invalid parameter");return new i(this.number**BigInt(r),this.decimalPos*r)}div(t){return this.convertToFraction().div(t)}divToInt(t){const n=s(t);if(n instanceof o)return this.convertToFraction().divToInt(n);const r=n,{a:e,b:a}=this.scaleNumber(r.number,r.decimalPos);return new i(e/a)}mod(t,r=n.TRUNCATED){const e=s(t);if(e instanceof o)return this.convertToFraction().mod(e);const a=e,{a:u,b:m,decimalPos:h}=this.scaleNumber(a.number,a.decimalPos),c=u%m,d=new i(c,h);if(r===n.TRUNCATED)return d;if(r===n.FLOORED)return Number(u<0)^Number(m<0)?d.add(m):d;if(r===n.EUCLIDEAN)return c<0?d.add(m<0?-m:m):d;throw new Error("Invalid ModType")}abs(){return new i(this.number<0?-this.number:this.number,this.decimalPos)}neg(){return this.mul(-1n)}inv(){return this.convertToFraction().inv()}floor(n){return 0===this.decimalPos?this:this.round(t.TO_NEGATIVE,n)}ceil(n){return 0===this.decimalPos?this:this.round(t.TO_POSITIVE,n)}trunc(n){return 0===this.decimalPos?this:this.round(t.TO_ZERO,n)}round(n,r){if(r=void 0===r?0:r,!Number.isSafeInteger(r)||r<0)throw new Error("Invalid value for decimals");const e=this.decimalPos-r,o=10n**BigInt(Math.abs(e)),s=e>0?this.number/o:this.number*o;if(n===t.TO_ZERO)return new i(s,r);const a=e>0?Math.abs(e):r,u=e>0?this.number%o:s%10n**BigInt(r);if(0n===u)return new i(s,r);if(n===t.AWAY_FROM_ZERO){const t=this.number<0n?s-1n:s+1n;return new i(t,r)}if(n===t.TO_POSITIVE){const t=this.number<0n?s:s+1n;return new i(t,r)}if(n===t.TO_NEGATIVE){const t=this.number>=0n?s:s-1n;return new i(t,r)}let m=(u<0n?-u:u).toString();m.length<a&&(m="0".repeat(a-m.length)+m);let h="5"===m[0];if(h)for(let t=1;t<m.length;t++)if("0"!==m[t]){h=!1;break}if(h){if(n===t.NEAREST_TO_ZERO)return new i(s,r);if(n===t.NEAREST_AWAY_FROM_ZERO){const t=this.number<0n?s-1n:s+1n;return new i(t,r)}if(void 0===n||n===t.NEAREST_TO_POSITIVE){const t=this.number<0n?s:s+1n;return new i(t,r)}if(n===t.NEAREST_TO_NEGATIVE){const t=this.number>=0n?s:s-1n;return new i(t,r)}if(n===t.NEAREST_TO_EVEN){if(s%2n===0n)return new i(s,r);return new i(s<0n?s-1n:s+1n,r)}}if(void 0===n||n===t.NEAREST_TO_ZERO||n===t.NEAREST_AWAY_FROM_ZERO||n===t.NEAREST_TO_POSITIVE||n===t.NEAREST_TO_NEGATIVE||n===t.NEAREST_TO_EVEN){if(Number(m[0])<5)return new i(s,r);const t=this.number<0?s-1n:s+1n;return new i(t,r)}throw new Error("Invalid rounding mode. Use the predefined values from the RoundingMode enum.")}roundToDigits(t,n){if(!Number.isSafeInteger(n)||n<1)throw new Error("Invalid value for digits");const r=this.number<0n,e=(r?-this.number:this.number).toString();let o=new i(`0.${e}`).round(t,n);const s=e.length-this.decimalPos;return o=s<0?o.div(10n**BigInt(-s)):o.mul(10n**BigInt(s)),r?o.neg():o}intPart(){return this.trunc()}fracPart(){return this.sub(this.trunc())}sign(){return this.number<0n?-1:1}bitwiseAnd(t){if(t=a(t),!this.isInteger()||-1===this.sign()||!t.isInteger()||-1===t.sign())throw new Error("Only positive integers are supported");t instanceof o&&(t=t.trunc());const n=2n**24n;let r=this.normalize().number,e=t.trunc().normalize().number,s=0n,u=1n;for(;r>0&&e>0;){const t=BigInt.asUintN(24,r),i=BigInt.asUintN(24,e);s+=BigInt(Number(t)&Number(i))*u,u*=n,r/=n,e/=n}return new i(s)}bitwiseOr(t){if(t=a(t),!this.isInteger()||-1===this.sign()||!t.isInteger()||-1===t.sign())throw new Error("Only positive integers are supported");t instanceof o&&(t=t.trunc());const n=2n**24n;let r=this.normalize().number,e=t.trunc().normalize().number,s=0n,u=1n;for(;r>0||e>0;){const t=BigInt.asUintN(24,r),i=BigInt.asUintN(24,e);s+=BigInt(Number(t)|Number(i))*u,u*=n,r/=n,e/=n}return new i(s)}bitwiseXor(t){if(t=a(t),!this.isInteger()||-1===this.sign()||!t.isInteger()||-1===t.sign())throw new Error("Only positive integers are supported");t instanceof o&&(t=t.trunc());const n=2n**24n;let r=this.normalize().number,e=t.trunc().normalize().number,s=0n,u=1n;for(;r>0||e>0;){const t=BigInt.asUintN(24,r),i=BigInt.asUintN(24,e);s+=BigInt(Number(t)^Number(i))*u,u*=n,r/=n,e/=n}return new i(s)}shiftLeft(t){if(!this.isInteger()||-1===this.sign())throw new Error("Only positive integers are supported");if(!Number.isSafeInteger(t)||t<0)throw new Error("Invalid value for bitCount");const n=2n**BigInt(t);return this.mul(n)}shiftRight(t){if(!this.isInteger()||-1===this.sign())throw new Error("Only positive integers are supported");if(!Number.isSafeInteger(t)||t<0)throw new Error("Invalid value for bitCount");const n=2n**BigInt(t);return new i(this.normalize().number/n)}cmp(t){const n=s(t);if(n instanceof o)return-n.cmp(this);const r=n,{a:e,b:i}=this.scaleNumber(r.number,r.decimalPos);return e===i?0:e>i?1:-1}eq(t){return 0===this.cmp(t)}lt(t){return-1===this.cmp(t)}lte(t){return this.cmp(t)<=0}gt(t){return 1===this.cmp(t)}gte(t){return this.cmp(t)>=0}clamp(t,n){const r=a(t),e=a(n);if(r.gt(e))throw new Error("Min parameter has to be smaller than max");return this.lt(r)?r:this.gt(e)?e:this}isZero(){return 0n===this.number}isOne(){if(0===this.decimalPos)return 1n===this.number;const t=10n**BigInt(this.decimalPos),n=this.number/t;return 1n===n&&n*t===this.number}isInteger(){return 0===this.decimalPos||this.number%10n**BigInt(this.decimalPos)===0n}serialize(){return[this.number,this.decimalPos]}getFractionParts(t=!0){return this.convertToFraction().getFractionParts(t)}normalize(){if(0===this.decimalPos)return this;let t=this.decimalPos,n=this.number;for(;t>0&&n%10n===0n;)t--,n/=10n;return new i(n,t)}convertToFraction(){if(0===this.decimalPos)return new o(this.number,1n);const t=10n**BigInt(this.decimalPos);return new o(this.number,t)}toNumber(){return Number(this.toString())}toFixed(t,n){if(!Number.isSafeInteger(t)||t<0)throw new Error("Invalid parameter");const r=t-this.decimalPos,i=10n**BigInt(Math.abs(r)),o=r<0?this.number/i:this.number*i;return e(o,t,Boolean(n))}toExponential(t){if(!Number.isSafeInteger(t)||t<0)throw new Error("Invalid parameter");const n=this.number<0n,r=(n?-this.number:this.number).toString(),e=r.length<=t?`${r}${"0".repeat(t-r.length+1)}`:r.slice(0,t+1),i=e.length>1?`${e.slice(0,1)}.${e.slice(1)}`:e,o=this.decimalPos,s=r.length-1-o;return`${n?"-":""}${i}e${s>=0?"+":""}${s}`}toBase(t,n){if(!Number.isSafeInteger(t)||t<2||t>16)throw new Error("Invalid radix");if(void 0!==n&&(!Number.isSafeInteger(n)||n<0))throw new Error("Invalid parameter");if(10===t)return void 0===n?this.toString():this.toFixed(n,!0);const r=this.normalize();if(0===r.decimalPos)return r.number.toString(t);const e=void 0===n?Number.MAX_SAFE_INTEGER:n+1;let i=r.intPart(),o=r.sub(i);const s=-1===r.sign();s&&(i=i.neg(),o=o.neg());const a=new Map;let u=[];for(;!o.isZero()&&u.length!==e;){const n=o.mul(t),r=n.toString(),e=a.get(r);if(void 0!==e){u=[...u.slice(0,e-1),"(",...u.slice(e-1),")"];break}const i=Math.abs(n.intPart().toNumber());u.push(i.toString(t)),o=n.fracPart(),a.set(r,u.length)}return u.length===e&&u.pop(),[s?"-":"",i.number.toString(t),u.length?".":"",...u].join("")}toFraction(){return this.convertToFraction().toFraction()}toString(t,n){if(void 0===t||10===t){const t=void 0!==n?this.trunc(n):this;return e(t.number,t.decimalPos,!0)}return this.toBase(t,n)}valueOf(){throw new Error("Unsafe conversion to Number type! Use toNumber() instead.")}}class o{constructor(t,n){if(this.type="fraction","bigint"==typeof t&&"bigint"==typeof n)this.numerator=t,this.denominator=n;else{const r=this.parseParameter(t),e=this.parseParameter(n),o=r.div(e),s=o instanceof i?o.convertToFraction():o;this.numerator=s.numerator,this.denominator=s.denominator}if(0n===this.denominator)throw new Error("Division by zero")}parseRepeatingDecimal(t){if(!t.includes("("))return new i(t).convertToFraction();const n=(t=t.trim()).match(/^(-?[0-9]*)\.([0-9]+)?\(([0-9]+)\)(?:[eE]([+-]?[0-9]+))?$/);if(!n)throw new Error(`Cannot parse number "${t}"`);const r="-"===n[1]?"-0":n[1],e=n[2]??"",s=n[3],a=n[4],u=BigInt(r+e+s)-BigInt(r+e),m=BigInt("9".repeat(s.length)+"0".repeat(e.length)),h=new o(u,m);if(void 0!==a){const t=a.startsWith("-"),n=10n**BigInt(t?a.slice(1):a);return t?h.div(n).normalize():h.mul(n).normalize()}return h.normalize()}parseParameter(t){if(t instanceof o)return t;if(t instanceof i)return t.convertToFraction();if("number"==typeof t){if(!Number.isSafeInteger(t))throw new Error("Floating point values as numbers are unsafe. Please provide them as a string.");return new o(BigInt(t),1n)}if("bigint"==typeof t)return new o(t,1n);if("string"==typeof t){const n=t.split("/");if(n.length>2)throw new Error(`Cannot parse string '${t}'`);const r=this.parseRepeatingDecimal(n[0]),e=n[1]?this.parseRepeatingDecimal(n[1]):new o(1n,1n);return r.div(e).convertToFraction()}throw new Error("Unsupported parameter!")}add(t){const{numerator:n,denominator:r}=this.parseParameter(t);return this.denominator===r?new o(this.numerator+n,this.denominator):new o(this.numerator*r+n*this.denominator,r*this.denominator)}sub(t){const{numerator:n,denominator:r}=this.parseParameter(t);return this.add(new o(-n,r))}mul(t){const{numerator:n,denominator:r}=this.parseParameter(t);return new o(this.numerator*n,this.denominator*r)}div(t){const{numerator:n,denominator:r}=this.parseParameter(t);return this.mul(new o(r,n))}divToInt(t){return this.div(t).round()}mod(t,r=n.TRUNCATED){const e=this.parseParameter(t),i=e.denominator*this.numerator%(e.numerator*this.denominator),s=this.denominator*e.denominator,a=new o(i,s);if(r===n.TRUNCATED)return a;if(r===n.FLOORED)return Number(-1===this.sign())^Number(-1===e.sign())?a.add(e):a;if(r===n.EUCLIDEAN)return a.sign()<0?a.add(e.sign()<0?e.neg():e):a;throw new Error("Invalid ModType")}pow(t){const{numerator:n,denominator:r}=this.parseParameter(t);if(1n!==r)throw new Error("Unsupported parameter");return new o(this.numerator**n,this.denominator**n)}inv(){return new o(this.denominator,this.numerator)}floor(n){return 1n===this.denominator?new i(this.numerator):this.round(t.TO_NEGATIVE,n)}ceil(n){return 1n===this.denominator?new i(this.numerator):this.round(t.TO_POSITIVE,n)}trunc(n){return 1n===this.denominator?new i(this.numerator):this.round(t.TO_ZERO,n)}round(t,n){if(n=void 0===n?0:n,!Number.isSafeInteger(n)||n<0)throw new Error("Invalid value for decimals");const r=this.toFixedNumber(n+1);if(this.sub(r).isZero())return r.round(t,n);return new i(`${r.toFixed(n+1)}1`).round(t,n)}roundToDigits(t,n){if(!Number.isSafeInteger(n)||n<1)throw new Error("Invalid value for digits");if(this.isZero())return this;let r=this.abs(),e=0;for(;r.gte(1n);)r=r.div(10n),e++;const i=new o(1n,10n);for(;r.lt(i);)r=r.mul(10n),e--;let s=r.round(t,n);return s=e<0?s.div(10n**BigInt(-e)):s.mul(10n**BigInt(e)),-1===this.sign()?s.neg():s}gcd(t,n){let r=t<0?-t:t,e=n<0?-n:n;if(e>r){const t=r;r=e,e=t}for(;;){if(0n===e)return r;if(r%=e,0n===r)return e;e%=r}}lcm(t,n){return t*n/this.gcd(t,n)}normalize(){let{numerator:t,denominator:n}=this;const r=this.gcd(t,n);return r>1n&&(t/=r,n/=r),n<0n&&(t=-t,n=-n),new o(t,n)}getFractionParts(t=!0){const n=t?this.normalize():this;return{numerator:new i(n.numerator),denominator:new i(n.denominator)}}sign(){return(this.numerator<0n?-1:1)*(this.denominator<0n?-1:1)}abs(){return new o(this.numerator<0n?-this.numerator:this.numerator,this.denominator<0n?-this.denominator:this.denominator)}neg(){return this.mul(-1n)}intPart(){return this.trunc()}fracPart(){return this.sub(this.trunc())}cmp(t){const n=this.parseParameter(t),r=this.denominator===n.denominator,e=r?this.numerator:this.numerator*n.denominator,i=r?n.numerator:n.numerator*this.denominator;return e===i?0:e>i?1:-1}eq(t){return 0===this.cmp(t)}lt(t){return-1===this.cmp(t)}lte(t){return this.cmp(t)<=0}gt(t){return 1===this.cmp(t)}gte(t){return this.cmp(t)>=0}clamp(t,n){const r=a(t),e=a(n);if(r.gt(e))throw new Error("Min parameter has to be smaller than max");return this.lt(r)?r:this.gt(e)?e:this}isZero(){return 0n===this.numerator}isOne(){return this.numerator===this.denominator}isInteger(){return this.numerator%this.denominator===0n}serialize(){return[this.numerator,this.denominator]}toNumber(){return Number(this.numerator)/Number(this.denominator)}convertToFraction(){return this}getNumberForBitwiseOp(){if(!this.isInteger()||-1===this.sign())throw new Error("Only positive integers are supported");return this.intPart()}bitwiseAnd(t){return this.getNumberForBitwiseOp().bitwiseAnd(t)}bitwiseOr(t){return this.getNumberForBitwiseOp().bitwiseOr(t)}bitwiseXor(t){return this.getNumberForBitwiseOp().bitwiseXor(t)}shiftLeft(t){return this.getNumberForBitwiseOp().shiftLeft(t)}shiftRight(t){return this.getNumberForBitwiseOp().shiftRight(t)}getDecimalFormat(t){t=void 0===t?Number.MAX_SAFE_INTEGER:t;let n=this.denominator<0?-this.denominator:this.denominator,r=0;for(;n%2n===0n;)n/=2n,r++;let e=0;for(;n%5n===0n;)n/=5n,e++;const i=Math.max(r,e);if(1n===n)return{cycleLen:0,cycleStart:i};const o=Math.max(1,t-i);let s=10n%n,a=1;for(;1n!==s;){if(a===o)return{cycleLen:null,cycleStart:i};s=10n*s%n,a++}return{cycleLen:a,cycleStart:i}}toFixed(t,n){if(!Number.isSafeInteger(t)||t<0)throw new Error("Invalid parameter");let{numerator:r}=this;t>0&&(r*=10n**BigInt(t));const i=r/this.denominator;return e(i,t,Boolean(n))}toRepeatingParts(t){if(this.isZero())return["0","",""];const{cycleLen:n,cycleStart:e}=this.normalize().getDecimalFormat(t);if(null===n||0===n){const n=t??e,i=this.toFixed(n),o=r(i).split(".");return[o[0],o[1]??"",""]}const i=e+n,o=this.toFixed(i).split(".");return[o[0],o[1].slice(0,e),o[1].slice(e)]}toRepeatingDigits(t){const n=this.toRepeatingParts(t);let r=n[0];return(n[1]||n[2])&&(r+=`.${n[1]}`),n[2]&&(r+=`(${n[2]})`),r}toExponential(t){if(!Number.isSafeInteger(t)||t<0)throw new Error("Invalid parameters");return this.toFixedNumber(t).toExponential(t)}toFraction(){const{numerator:t,denominator:n}=this.normalize();return`${t.toString()}/${n.toString()}`}toFixedNumber(t){const n=this.numerator*10n**BigInt(t);return new i(n/this.denominator,t)}toBase(t,n){if(!Number.isSafeInteger(t)||t<2||t>16)throw new Error("Invalid radix");if(void 0!==n&&(!Number.isSafeInteger(n)||n<0))throw new Error("Invalid parameter");if(10===t)return void 0===n?this.toRepeatingDigits(n):this.toFixed(n,!0);const r=this.normalize(),e=void 0===n?Number.MAX_SAFE_INTEGER:n+1;let i=r.intPart(),o=r.sub(i);const s=-1===r.sign();s&&(i=i.neg(),o=o.neg());const a=new Map;let u=[];for(;!o.isZero()&&u.length!==e;){const n=o.mul(t),r=n.normalize().toFraction(),e=a.get(r);if(void 0!==e){u=[...u.slice(0,e-1),"(",...u.slice(e-1),")"];break}const i=Math.abs(n.intPart().toNumber());u.push(i.toString(t)),o=n.fracPart(),a.set(r,u.length)}return u.length===e&&u.pop(),[s?"-":"",i.toString(t),u.length?".":"",...u].join("")}toString(t,n){return void 0===t||10===t?this.toRepeatingDigits(n):this.toBase(t,n)}valueOf(){throw new Error("Unsafe conversion to Number type! Use toNumber() instead.")}}function s(t){if(t instanceof i||t instanceof o)return t;if("bigint"==typeof t)return new i(t);if("number"==typeof t){if(!Number.isSafeInteger(t))throw new Error("Floating point values as numbers are unsafe. Please provide them as a string.");return new i(t)}if("string"==typeof t)return t.includes("/")||t.includes("(")?new o(t,1n):new i(t);throw new Error("Unsupported parameter type")}const a=(t,n)=>{if(void 0===t)throw new Error("First parameter cannot be undefined");const r=s(t);if(void 0===n)return r;const e=s(n);return new o(r,1n).div(new o(e,1n))};a.min=(...t)=>{if(0===t.length)throw new Error("Got empty array");let n=a(t[0]);for(let r=1;r<t.length;r++){const e=a(t[r]);e.lt(n)&&(n=e)}return n},a.max=(...t)=>{if(0===t.length)throw new Error("Got empty array");let n=a(t[0]);for(let r=1;r<t.length;r++){const e=a(t[r]);e.gt(n)&&(n=e)}return n};const u=(t,n)=>{let r=0n;for(let e=0;e<t.length;e++){const i=t.charAt(e),o=parseInt(i,n);if(Number.isNaN(o))throw new Error(`Invalid digit "${i}"`);r*=BigInt(n),r+=BigInt(o)}return r};a.fromBase=(t,n)=>{if("string"!=typeof t)throw new Error("First parameter must be string");if(!Number.isSafeInteger(n)||n<2||n>16)throw new Error("Invalid radix");if(10===n)return a(t);if(0===(t=t.trim()).length)throw new Error("Empty string is not allowed");const r=t.startsWith("-");r&&(t=t.slice(1));const e=t.match(/^([0-9a-f]*)(?:\.([0-9a-f]*)(?:\(([0-9a-f]+)\))?)?$/i);if(!e)throw new Error(`Cannot parse number "${t}"`);const i=e[1]??"",s=e[2]??"",m=e[3]??"";if(m.length>0){const t=u([i,s,m].join(""),n)-u([i,s].join(""),n),e=u((n-1).toString(n).repeat(m.length)+"0".repeat(s.length),n),a=new o(t,e).normalize();return r?a.neg():a}const h=u(i,n),c=u(s,n),d=new o(c,BigInt(n)**BigInt(s.length)),l=new o(h,1n).add(d).normalize();return r?l.neg():l};const m=(t,n,r)=>{if(!Number.isSafeInteger(t))throw new Error("Integer is expected for N");if(t<0)throw new Error("Negative N is not supported");if(0===t)throw new Error("N cannot be zero");if(1===t)return a(n).toFixed(r);const e=a(n);if(t%2==0&&-1===e.sign())throw new Error("Complex numbers are not supported");if(e.isZero())return new i(0n).toFixed(r);if(e.isOne())return new i(1n).toFixed(r);const s=new o(t-1,t),u=new o(e,t),m=((t,n)=>{const r=n<0;r&&(n=-n);let e=n**(1/t);return r&&(e=-e),e.toString()})(t,e.toNumber());let h=new i(m),c=h.trunc(r);for(;;){h=s.mul(h).add(u.mul(h.inv().pow(t-1)));const n=h.trunc(r);if(h.isZero()||c.eq(n))break;c=n}return h.toFixed(r)},h=(t,n)=>m(2,t,n),c=(t,n)=>m(3,t,n),d=(t,n,r)=>{const e=new o(t,1n),i=new o(n,1n).getFractionParts(!1);return m(i.denominator.toNumber(),e.pow(i.numerator),r)},l=(t,n)=>{const r=a(t);let e=r.add(1n),i=6n,s=4n;const u=r.pow(2n);let m=u;const h=new o(1n,10n**BigInt(n+5));for(;;){const t=m.mul(r.add(s-1n)).div(i);if(i*=s*(s+1n),s+=2n,m=m.mul(u),e=e.add(t).trunc(n+5),t.abs().lte(h))break}return e.toFixed(n)};class g{constructor(t,n){this.cachedDigits=0,this.fn=t,this.max=n}get(t){if(t<=this.cachedDigits)return this.cache.trunc(t);const n=new i(this.fn(t)),r=Math.min(this.max,t);return this.cachedDigits!==r&&(this.cache=n.trunc(r),this.cachedDigits=r),n}}const f=(t,n)=>{let r=a(t);if(r.isOne())return new i(0).toFixed(n);if(r.lte(0n))throw new Error("Invalid parameter");let e=0;for(;r.sub(1n).abs().gt("0.1");)r=new i(h(r,n+10)),e++;const o=r.sub(1n).div(r.add(1n)),s=o.pow(2n).normalize();let u=o,m=1n,c=a(o);for(;;){let t=a(0);for(let r=0;r<4;r++){u=u.mul(s),m+=2n;const r=u.div(m);t=t.add(r).trunc(n+10)}if(t.isZero())break;c=c.add(t)}return c=c.mul(2n**BigInt(e+1)),c.toFixed(n)},w=(t,n,r)=>{if(!Number.isSafeInteger(t)||t<2)throw new Error("Invalid parameter for N");const e=f(n,r+10),o=f(t,r+10);return new i(e).div(o).toFixed(r)},b=new g((t=>f(2n,t)),200),p=(t,n)=>new i(f(t,n+10)).div(b.get(n+10)).toFixed(n),E=new g((t=>f(10n,t)),200),I=(t,n)=>new i(f(t,n+10)).div(E.get(n+10)).toFixed(n),v=new g((t=>{if(0===t)return"3";let n=1n,r=3n*10n**BigInt(t+20),e=r;for(;0n!==r;)r=r*n/(4n*(n+1n)),n+=2n,e+=r/n;return`3.${e.toString().slice(1,t+1)}`}),1e3),N=t=>0===t?"3":v.get(t).toFixed(t),T=(n,r)=>{const e=r+10,{x:o,quadrant:s}=((t,n)=>{const r=new i(N(n)),e=r.mul(2n);(t=t.mod(e)).gt(r)?t=t.sub(e):t.lt(r.neg())&&(t=t.add(e));const o=r.div(2n),s=t.div(o);let a=0;return s.gte(o)?(a=2,t=r.sub(t)):s.gte(0n)?a=1:s.gte(o.neg())?(a=4,t=t.neg()):(a=3,t=r.sub(t.neg())),{quadrant:a,x:t}})(a(n),e),u=o.round(t.NEAREST_AWAY_FROM_ZERO,e).pow(2n).normalize();let m=u,h=2n,c=a(1n).sub(m.div(h).trunc(e)),d=3n;const l=a(1n).div(10n**BigInt(e));let g=1;for(;;){h*=d*(d+1n),d+=2n;const t=d*(d+1n);d+=2n,m=m.mul(u),h*=t;let i=m.mul(t);m=m.mul(u),i=i.sub(m);const o=i.div(h).trunc(e);if(g++,c=c.add(o),o.lt(l)){const t=c.trunc(r),i=o.add(l.mul(g)),s=c.add(i).trunc(r);if(t.eq(s))break;return a(T(n,e+50)).toFixed(r)}}return(1===s||4===s?c:c.neg()).round(t.TO_ZERO,r+3).toFixed(r)},O=(t,n)=>{const r=new i(N(n+10)),e=a(t);return T(r.div(2n).sub(e),n)},F=(t,n)=>{if(a(t).isZero())return"0";return a(O(t,n+10)).div(T(t,n+10)).toFixed(n)},P=(t,n)=>{let r=a(t);if(r.isZero())return"0";if(r.abs().isOne())return a(N(n)).div(4*r.sign()).toFixed(n);let e=0;for(;r.abs().gt("0.42");){const t=a(h(r.pow(2n).add(1n),n+10));r=r.div(t.add(1n)),e++}const i=r.pow(2).normalize(),o=i.pow(2).normalize();let s=3n,u=r.sub(r.mul(i).div(s)),m=r.mul(o);const c=a(1n).div(10n**BigInt(n+10));for(;;){s+=2n;const t=s+2n,r=m.mul(i.mul(-s).add(t)).div(s*t);if(s=t,m=m.mul(o),u=u.add(r).trunc(n+10),r.abs().lt(c))break}return u=u.mul(2n**BigInt(e)),u.toFixed(n)},S=(t,n)=>{const r=a(t);if(r.isZero())return"0";if(r.abs().isOne())return a(N(n)).mul(r.sign()).div(2n).toFixed(n);if(r.abs().eq("1/2"))return a(N(n)).mul(r.sign()).div(6n).toFixed(n);if(r.gt(1n)||r.lt(-1n))throw new Error("Out of range");const e=a(h(r.pow(2n).neg().add(1),n+10));return a(P(r.div(e.add(1n)),n+10)).mul(2).toFixed(n)},R=(t,n)=>{const r=a(t);if(r.isZero())return a(N(n)).div(2n).toFixed(n);if(r.isOne())return"0";if(r.abs().isOne())return N(n);if(r.abs().eq("1/2")){const t=a(N(n)).div(3n);return-1===r.sign()?t.mul(2n).toFixed(n):t.toFixed(n)}if(r.gt(1n)||r.lt(-1n))throw new Error("Out of range");return a(N(n+10)).div(2n).sub(S(r,n+10)).toFixed(n)},_=(t,n)=>{const r=a(t),e=r.pow(2n).normalize();let i=r,o=1n,s=r.trunc(n+5),u=2n;const m=a(1n).div(10n**BigInt(n+5));for(;;){i=i.mul(e),o*=u*(u+1n),u+=2n;const t=i.div(o);if(s=s.add(t).trunc(n+5),t.abs().lt(m))break}return s.toFixed(n)},B=(t,n)=>{const r=a(t).pow(2n).normalize();let e=r,i=2n,o=e.div(i).add(1n).trunc(n+5),s=3n;const u=a(1n).div(10n**BigInt(n+5));for(;;){e=e.mul(r),i*=s*(s+1n),s+=2n;const t=e.div(i);if(o=o.add(t).trunc(n+5),t.abs().lt(u))break}return o.toFixed(n)};export{a as ExactNumber,n as ModType,N as PI,t as RoundingMode,R as acos,S as asin,P as atan,c as cbrt,T as cos,B as cosh,l as exp,f as log,I as log10,p as log2,w as logn,m as nthroot,d as pow,O as sin,_ as sinh,h as sqrt,F as tan}; | ||
var t,n;!function(t){t.NEAREST_TO_POSITIVE="NP",t.NEAREST_TO_NEGATIVE="NN",t.NEAREST_TO_EVEN="NE",t.NEAREST_TO_ZERO="NZ",t.NEAREST_AWAY_FROM_ZERO="NA",t.TO_POSITIVE="P",t.TO_NEGATIVE="N",t.TO_ZERO="Z",t.AWAY_FROM_ZERO="A"}(t||(t={})),function(t){t.TRUNCATED="T",t.FLOORED="F",t.EUCLIDEAN="E"}(n||(n={}));const r=t=>{let n=t.length;for(;n>0&&["0","."].includes(t.charAt(n-1));)n--;return n!==t.length?t.slice(0,n):t},e=(t,n,e)=>{let i=t.toString();if(0===n)return i;const o=i.startsWith("-");if(o&&(i=i.slice(1)),n>=i.length&&(i="0".repeat(n-i.length+1)+i),n>0){const t=i.slice(0,-n);let o=i.slice(-n);e&&(o=r(o)),i=o.length?`${t}.${o}`:t}return o?`-${i}`:i};class i{constructor(t,n=0){if(this.type="fixed","bigint"==typeof t)this.number=t,this.decimalPos=n;else{const n=this.parseConstructorParameter(t);this.number=n.number,this.decimalPos=n.decimalPos}}parseConstructorParameter(t){if(t instanceof i)return{number:t.number,decimalPos:t.decimalPos};if(t instanceof o){if(!t.isInteger())throw new Error("Cannot create FixedNumber from non-integer Fraction");return{number:t.trunc().number,decimalPos:0}}if("number"==typeof t){if(!Number.isSafeInteger(t))throw new Error("The specified number cannot be exactly represented as an integer. Please provide a string instead.");return{number:BigInt(t),decimalPos:0}}if("string"==typeof t){if(0===(t=t.trim()).length)throw new Error("Empty string is not allowed");const n=t.match(/^(-?[0-9]*)(?:\.([0-9]*))?(?:[eE]([+-]?[0-9]+))?$/);if(!n)throw new Error(`Cannot parse number "${t}"`);let r=0,e=n[1]??"0";if(void 0!==n[2]&&(e+=n[2],r+=n[2].length),void 0!==n[3]){const t=Number(n[3]);t>0?e+="0".repeat(t):r-=t}return{number:BigInt(e),decimalPos:r}}throw new Error("Unsupported parameter!")}scaleNumber(t,n){const r=Math.max(this.decimalPos,n);return{a:r===this.decimalPos?this.number:this.number*10n**BigInt(r-this.decimalPos),b:r===n?t:t*10n**BigInt(r-n),decimalPos:r}}add(t){const n=s(t);if(n instanceof o)return n.add(this);const r=n,{a:e,b:a,decimalPos:u}=this.scaleNumber(r.number,r.decimalPos);return new i(e+a,u)}sub(t){const n=s(t);return this.add(n.neg())}mul(t){const n=s(t);if(n instanceof o)return n.mul(this);const r=n;return new i(this.number*r.number,this.decimalPos+r.decimalPos)}pow(t){const n=s(t).toNumber();if(!Number.isSafeInteger(n)||n<0)throw new Error("Unsupported parameter");return new i(this.number**BigInt(n),this.decimalPos*n)}div(t){return this.convertToFraction().div(t)}divToInt(t){const n=s(t);if(n instanceof o)return this.convertToFraction().divToInt(n);const r=n,{a:e,b:a}=this.scaleNumber(r.number,r.decimalPos);return new i(e/a)}mod(t,r=n.TRUNCATED){const e=s(t);if(e instanceof o)return this.convertToFraction().mod(e);const a=e,{a:u,b:m,decimalPos:h}=this.scaleNumber(a.number,a.decimalPos),c=u%m,d=new i(c,h);if(r===n.TRUNCATED)return d;if(r===n.FLOORED)return Number(u<0)^Number(m<0)?d.add(m):d;if(r===n.EUCLIDEAN)return c<0?d.add(m<0?-m:m):d;throw new Error("Invalid ModType")}abs(){return new i(this.number<0?-this.number:this.number,this.decimalPos)}neg(){return this.mul(-1n)}inv(){return this.convertToFraction().inv()}floor(n){return 0===this.decimalPos?this:this.round(n,t.TO_NEGATIVE)}ceil(n){return 0===this.decimalPos?this:this.round(n,t.TO_POSITIVE)}trunc(n){return 0===this.decimalPos?this:this.round(n,t.TO_ZERO)}round(n,r){if(n=void 0===n?0:n,!Number.isSafeInteger(n)||n<0)throw new Error("Invalid value for decimals");const e=this.decimalPos-n,o=10n**BigInt(Math.abs(e)),s=e>0?this.number/o:this.number*o;if(r===t.TO_ZERO)return new i(s,n);const a=e>0?Math.abs(e):n,u=e>0?this.number%o:s%10n**BigInt(n);if(0n===u)return new i(s,n);if(r===t.AWAY_FROM_ZERO){const t=this.number<0n?s-1n:s+1n;return new i(t,n)}if(r===t.TO_POSITIVE){const t=this.number<0n?s:s+1n;return new i(t,n)}if(r===t.TO_NEGATIVE){const t=this.number>=0n?s:s-1n;return new i(t,n)}if(![void 0,t.NEAREST_TO_ZERO,t.NEAREST_AWAY_FROM_ZERO,t.NEAREST_TO_POSITIVE,t.NEAREST_TO_NEGATIVE,t.NEAREST_TO_EVEN].includes(r))throw new Error("Invalid rounding mode. Use the predefined values from the RoundingMode enum.");let m=(u<0n?-u:u).toString();m.length<a&&(m="0".repeat(a-m.length)+m);let h="5"===m[0];if(h)for(let t=1;t<m.length;t++)if("0"!==m[t]){h=!1;break}if(h){if(r===t.NEAREST_TO_ZERO)return new i(s,n);if(r===t.NEAREST_AWAY_FROM_ZERO){const t=this.number<0n?s-1n:s+1n;return new i(t,n)}if(void 0===r||r===t.NEAREST_TO_POSITIVE){const t=this.number<0n?s:s+1n;return new i(t,n)}if(r===t.NEAREST_TO_NEGATIVE){const t=this.number>=0n?s:s-1n;return new i(t,n)}if(r===t.NEAREST_TO_EVEN){if(s%2n===0n)return new i(s,n);return new i(s<0n?s-1n:s+1n,n)}}if(Number(m[0])<5)return new i(s,n);const c=this.number<0?s-1n:s+1n;return new i(c,n)}_incExponent(t){if(0===t)return this;let n=this.number,r=this.decimalPos;if(t<0)r-=t;else{const e=Math.min(t,this.decimalPos);r-=e;const i=t-e;i>0&&(n*=10n**BigInt(i))}return new i(n,r)}roundToDigits(t,n){if(!Number.isSafeInteger(t)||t<1)throw new Error("Invalid value for digits");const r=this.number<0n,e=r?-this.number:this.number,o=e.toString();let s=new i(e,o.length).round(t,n);const a=o.length-this.decimalPos;return s=s._incExponent(a),r?s.neg():s}intPart(){return this.trunc()}fracPart(){return this.sub(this.trunc())}sign(){return this.number<0n?-1:1}bitwiseAnd(t){if(t=a(t),!this.isInteger()||-1===this.sign()||!t.isInteger()||-1===t.sign())throw new Error("Only positive integers are supported");t instanceof o&&(t=t.trunc());const n=2n**24n;let r=this.normalize().number,e=t.trunc().normalize().number,s=0n,u=1n;for(;r>0&&e>0;){const t=BigInt.asUintN(24,r),i=BigInt.asUintN(24,e);s+=BigInt(Number(t)&Number(i))*u,u*=n,r/=n,e/=n}return new i(s)}bitwiseOr(t){if(t=a(t),!this.isInteger()||-1===this.sign()||!t.isInteger()||-1===t.sign())throw new Error("Only positive integers are supported");t instanceof o&&(t=t.trunc());const n=2n**24n;let r=this.normalize().number,e=t.trunc().normalize().number,s=0n,u=1n;for(;r>0||e>0;){const t=BigInt.asUintN(24,r),i=BigInt.asUintN(24,e);s+=BigInt(Number(t)|Number(i))*u,u*=n,r/=n,e/=n}return new i(s)}bitwiseXor(t){if(t=a(t),!this.isInteger()||-1===this.sign()||!t.isInteger()||-1===t.sign())throw new Error("Only positive integers are supported");t instanceof o&&(t=t.trunc());const n=2n**24n;let r=this.normalize().number,e=t.trunc().normalize().number,s=0n,u=1n;for(;r>0||e>0;){const t=BigInt.asUintN(24,r),i=BigInt.asUintN(24,e);s+=BigInt(Number(t)^Number(i))*u,u*=n,r/=n,e/=n}return new i(s)}shiftLeft(t){if(!this.isInteger()||-1===this.sign())throw new Error("Only positive integers are supported");if(!Number.isSafeInteger(t)||t<0)throw new Error("Invalid value for bitCount");const n=2n**BigInt(t);return this.mul(n)}shiftRight(t){if(!this.isInteger()||-1===this.sign())throw new Error("Only positive integers are supported");if(!Number.isSafeInteger(t)||t<0)throw new Error("Invalid value for bitCount");const n=2n**BigInt(t);return new i(this.normalize().number/n)}cmp(t){const n=s(t);if(n instanceof o)return-n.cmp(this);const r=n,{a:e,b:i}=this.scaleNumber(r.number,r.decimalPos);return e===i?0:e>i?1:-1}eq(t){return 0===this.cmp(t)}lt(t){return-1===this.cmp(t)}lte(t){return this.cmp(t)<=0}gt(t){return 1===this.cmp(t)}gte(t){return this.cmp(t)>=0}clamp(t,n){const r=a(t),e=a(n);if(r.gt(e))throw new Error("Min parameter has to be smaller than max");return this.lt(r)?r:this.gt(e)?e:this}isZero(){return 0n===this.number}isOne(){if(0===this.decimalPos)return 1n===this.number;const t=10n**BigInt(this.decimalPos),n=this.number/t;return 1n===n&&n*t===this.number}isInteger(){return 0===this.decimalPos||this.number%10n**BigInt(this.decimalPos)===0n}serialize(){return[this.number,this.decimalPos]}getFractionParts(t=!0){return this.convertToFraction().getFractionParts(t)}normalize(){if(0===this.decimalPos)return this;let t=this.decimalPos,n=this.number;for(;t>0&&n%10n===0n;)t--,n/=10n;return new i(n,t)}convertToFraction(){if(0===this.decimalPos)return new o(this.number,1n);const t=10n**BigInt(this.decimalPos);return new o(this.number,t)}toNumber(){return Number(this.toString())}toFixed(n,r=t.TO_ZERO){if(!Number.isSafeInteger(n)||n<0)throw new Error("Invalid parameter");const i=this.round(n,r);return e(i.number,n,!1)}toExponential(n,r=t.TO_ZERO){if(!Number.isSafeInteger(n)||n<0)throw new Error("Invalid parameter");const e=this.roundToDigits(n+1,r).normalize(),i=-1===e.sign(),o=e.abs(),s=o.number.toString(),a=s.length<=n?`${s}${"0".repeat(n-s.length+1)}`:s.slice(0,n+1),u=a.length>1?`${a.slice(0,1)}.${a.slice(1)}`:a,m=o.decimalPos,h=s.length-1-m;return`${i?"-":""}${u}e${h>=0?"+":""}${h}`}toBase(t,n){if(!Number.isSafeInteger(t)||t<2||t>16)throw new Error("Invalid radix");if(void 0!==n&&(!Number.isSafeInteger(n)||n<0))throw new Error("Invalid parameter");const r=this.normalize();if(0===r.decimalPos)return r.number.toString(t);const e=void 0===n?Number.MAX_SAFE_INTEGER:n;let i=r.intPart(),o=r.sub(i);const s=-1===r.sign();s&&(i=i.neg(),o=o.neg());const a=new Map;let u=[];for(;!o.isZero();){const n=o.mul(t),r=n.toString(),i=a.get(r);if(void 0!==i){u=[...u.slice(0,i-1),"(",...u.slice(i-1),")"];break}if(u.length===e)break;const s=Math.abs(n.intPart().toNumber());u.push(s.toString(t)),o=n.fracPart(),a.set(r,u.length)}return[s?"-":"",i.number.toString(t),u.length?".":"",...u].join("")}toFraction(){return this.convertToFraction().toFraction()}toString(t,n){if(void 0===t||10===t){const t=void 0!==n?this.trunc(n):this;return e(t.number,t.decimalPos,!0)}return this.toBase(t,n)}toPrecision(n,r=t.TO_ZERO){if(!Number.isSafeInteger(n)||n<1)throw new Error("Invalid parameter");const i=this.roundToDigits(n,r);return e(i.number,i.decimalPos,!1)}valueOf(){throw new Error("Unsafe conversion to Number type! Use toNumber() instead.")}}class o{constructor(t,n){if(this.type="fraction","bigint"==typeof t&&"bigint"==typeof n)this.numerator=t,this.denominator=n;else{const r=this.parseParameter(t),e=this.parseParameter(n),o=r.div(e),s=o instanceof i?o.convertToFraction():o;this.numerator=s.numerator,this.denominator=s.denominator}if(0n===this.denominator)throw new Error("Division by zero")}parseRepeatingDecimal(t){if(!t.includes("("))return new i(t).convertToFraction();const n=(t=t.trim()).match(/^(-?[0-9]*)\.([0-9]+)?\(([0-9]+)\)(?:[eE]([+-]?[0-9]+))?$/);if(!n)throw new Error(`Cannot parse string "${t}"`);const r="-"===n[1]?"-0":n[1],e=n[2]??"",s=n[3],a=n[4],u=BigInt(r+e+s)-BigInt(r+e),m=BigInt("9".repeat(s.length)+"0".repeat(e.length)),h=new o(u,m);if(void 0!==a){const t=a.startsWith("-"),n=10n**BigInt(t?a.slice(1):a);return t?h.div(n).normalize():h.mul(n).normalize()}return h.normalize()}parseParameter(t){if(t instanceof o)return t;if(t instanceof i)return t.convertToFraction();if("number"==typeof t){if(!Number.isSafeInteger(t))throw new Error("Floating point values as numbers are unsafe. Please provide them as a string.");return new o(BigInt(t),1n)}if("bigint"==typeof t)return new o(t,1n);if("string"==typeof t){const n=t.split("/");if(n.length>2)throw new Error(`Cannot parse string '${t}'`);const r=this.parseRepeatingDecimal(n[0]),e=n[1]?this.parseRepeatingDecimal(n[1]):new o(1n,1n);return r.div(e).convertToFraction()}throw new Error("Unsupported parameter!")}add(t){const{numerator:n,denominator:r}=this.parseParameter(t);return this.denominator===r?new o(this.numerator+n,this.denominator):new o(this.numerator*r+n*this.denominator,r*this.denominator)}sub(t){const{numerator:n,denominator:r}=this.parseParameter(t);return this.add(new o(-n,r))}mul(t){const{numerator:n,denominator:r}=this.parseParameter(t);return new o(this.numerator*n,this.denominator*r)}div(t){const{numerator:n,denominator:r}=this.parseParameter(t);return this.mul(new o(r,n))}divToInt(t){return this.div(t).trunc()}mod(t,r=n.TRUNCATED){const e=this.parseParameter(t),i=e.denominator*this.numerator%(e.numerator*this.denominator),s=this.denominator*e.denominator,a=new o(i,s);if(r===n.TRUNCATED)return a;if(r===n.FLOORED)return Number(-1===this.sign())^Number(-1===e.sign())?a.add(e):a;if(r===n.EUCLIDEAN)return a.sign()<0?a.add(e.sign()<0?e.neg():e):a;throw new Error("Invalid ModType")}pow(t){const n=this.parseParameter(t);if(!n.isInteger()||-1===n.sign())throw new Error("Unsupported parameter");const r=n.numerator/n.denominator;return new o(this.numerator**r,this.denominator**r)}inv(){return new o(this.denominator,this.numerator)}floor(n){return 1n===this.denominator?new i(this.numerator):this.round(n,t.TO_NEGATIVE)}ceil(n){return 1n===this.denominator?new i(this.numerator):this.round(n,t.TO_POSITIVE)}trunc(n){return 1n===this.denominator?new i(this.numerator):this.round(n,t.TO_ZERO)}round(t,n){if(t=void 0===t?0:t,!Number.isSafeInteger(t)||t<0)throw new Error("Invalid value for decimals");const r=this.toFixedNumber(t+1);if(this.sub(r).isZero())return r.round(t,n);return new i(`${r.toFixed(t+1)}1`).round(t,n)}roundToDigits(t,n){if(!Number.isSafeInteger(t)||t<1)throw new Error("Invalid value for digits");if(this.isZero())return new i(0n);let r=this.abs(),e=0;for(;r.gte(1n);)r=r.div(10n),e++;const s=new o(1n,10n);for(;r.lt(s);)r=r.mul(10n),e--;let a=r.round(t,n);return a=a._incExponent(e),-1===this.sign()?a.neg():a}gcd(t,n){let r=t<0?-t:t,e=n<0?-n:n;if(e>r){const t=r;r=e,e=t}for(;;){if(0n===e)return r;if(r%=e,0n===r)return e;e%=r}}lcm(t,n){return t*n/this.gcd(t,n)}normalize(){let{numerator:t,denominator:n}=this;const r=this.gcd(t,n);return r>1n&&(t/=r,n/=r),n<0n&&(t=-t,n=-n),new o(t,n)}getFractionParts(t=!0){const n=t?this.normalize():this;return{numerator:new i(n.numerator),denominator:new i(n.denominator)}}sign(){return(this.numerator<0n?-1:1)*(this.denominator<0n?-1:1)}abs(){return new o(this.numerator<0n?-this.numerator:this.numerator,this.denominator<0n?-this.denominator:this.denominator)}neg(){return this.mul(-1n)}intPart(){return this.trunc()}fracPart(){return this.sub(this.trunc())}cmp(t){const n=this.parseParameter(t),r=this.denominator===n.denominator,e=r?this.numerator:this.numerator*n.denominator,i=r?n.numerator:n.numerator*this.denominator;return e===i?0:e>i?1:-1}eq(t){return 0===this.cmp(t)}lt(t){return-1===this.cmp(t)}lte(t){return this.cmp(t)<=0}gt(t){return 1===this.cmp(t)}gte(t){return this.cmp(t)>=0}clamp(t,n){const r=a(t),e=a(n);if(r.gt(e))throw new Error("Min parameter has to be smaller than max");return this.lt(r)?r:this.gt(e)?e:this}isZero(){return 0n===this.numerator}isOne(){return this.numerator===this.denominator}isInteger(){return this.numerator%this.denominator===0n}serialize(){return[this.numerator,this.denominator]}toNumber(){return Number(this.numerator)/Number(this.denominator)}convertToFraction(){return this}getNumberForBitwiseOp(){if(!this.isInteger()||-1===this.sign())throw new Error("Only positive integers are supported");return this.intPart()}bitwiseAnd(t){return this.getNumberForBitwiseOp().bitwiseAnd(t)}bitwiseOr(t){return this.getNumberForBitwiseOp().bitwiseOr(t)}bitwiseXor(t){return this.getNumberForBitwiseOp().bitwiseXor(t)}shiftLeft(t){return this.getNumberForBitwiseOp().shiftLeft(t)}shiftRight(t){return this.getNumberForBitwiseOp().shiftRight(t)}getDecimalFormat(t){t=void 0===t?Number.MAX_SAFE_INTEGER:t;let n=this.denominator<0?-this.denominator:this.denominator,r=0;for(;n%2n===0n;)n/=2n,r++;let e=0;for(;n%5n===0n;)n/=5n,e++;const i=Math.max(r,e);if(1n===n)return{cycleLen:0,cycleStart:i};const o=Math.max(1,t-i);let s=10n%n,a=1;for(;1n!==s;){if(a===o)return{cycleLen:null,cycleStart:i};s=10n*s%n,a++}return{cycleLen:a,cycleStart:i}}toFixed(n,r=t.TO_ZERO){if(!Number.isSafeInteger(n)||n<0)throw new Error("Invalid parameter");const[i,o]=this.round(n,r).serialize();return e(i,o,!1)}toRepeatingParts(t){if(this.isZero())return["0","",""];const{cycleLen:n,cycleStart:e}=this.normalize().getDecimalFormat(t);if(null===n||0===n){const n=t??e,i=this.toFixed(n),o=r(i).split(".");return[o[0],o[1]??"",""]}const i=e+n,o=this.toFixed(i).split(".");return[o[0],o[1].slice(0,e),o[1].slice(e)]}toRepeatingDigits(t){const n=this.toRepeatingParts(t);let r=n[0];return(n[1]||n[2])&&(r+=`.${n[1]}`),n[2]&&(r+=`(${n[2]})`),r}toExponential(n,r=t.TO_ZERO){if(!Number.isSafeInteger(n)||n<0)throw new Error("Invalid parameters");return this.toFixedNumber(n).toExponential(n,r)}toFraction(){const{numerator:t,denominator:n}=this.normalize();return`${t.toString()}/${n.toString()}`}toFixedNumber(t){const n=this.numerator*10n**BigInt(t);return new i(n/this.denominator,t)}toBase(t,n){if(!Number.isSafeInteger(t)||t<2||t>16)throw new Error("Invalid radix");if(void 0!==n&&(!Number.isSafeInteger(n)||n<0))throw new Error("Invalid parameter");if(10===t)return void 0===n?this.toRepeatingDigits(n):r(this.toFixed(n));const e=this.normalize(),i=void 0===n?Number.MAX_SAFE_INTEGER:n+1;let o=e.intPart(),s=e.sub(o);const a=-1===e.sign();a&&(o=o.neg(),s=s.neg());const u=new Map;let m=[];for(;!s.isZero()&&m.length!==i;){const n=s.mul(t),r=n.normalize().toFraction(),e=u.get(r);if(void 0!==e){m=[...m.slice(0,e-1),"(",...m.slice(e-1),")"];break}const i=Math.abs(n.intPart().toNumber());m.push(i.toString(t)),s=n.fracPart(),u.set(r,m.length)}return m.length===i&&m.pop(),[a?"-":"",o.toString(t),m.length?".":"",...m].join("")}toString(t,n){return void 0===t||10===t?this.toRepeatingDigits(n):this.toBase(t,n)}toPrecision(n,r=t.TO_ZERO){if(!Number.isSafeInteger(n)||n<1)throw new Error("Invalid parameter");const[i,o]=this.roundToDigits(n,r).serialize();return e(i,o,!1)}valueOf(){throw new Error("Unsafe conversion to Number type! Use toNumber() instead.")}}function s(t){if(t instanceof i||t instanceof o)return t;if("bigint"==typeof t)return new i(t);if("number"==typeof t){if(!Number.isSafeInteger(t))throw new Error("Floating point values as numbers are unsafe. Please provide them as a string.");return new i(t)}if("string"==typeof t)return t.includes("/")||t.includes("(")?new o(t,1n):new i(t);throw new Error("Unsupported parameter type")}const a=(t,n)=>{if(void 0===t)throw new Error("First parameter cannot be undefined");const r=s(t);if(void 0===n)return r;const e=s(n);return new o(r,1n).div(new o(e,1n))};a.min=(...t)=>{if(0===t.length)throw new Error("Got empty array");let n=a(t[0]);for(let r=1;r<t.length;r++){const e=a(t[r]);e.lt(n)&&(n=e)}return n},a.max=(...t)=>{if(0===t.length)throw new Error("Got empty array");let n=a(t[0]);for(let r=1;r<t.length;r++){const e=a(t[r]);e.gt(n)&&(n=e)}return n};const u=(t,n)=>{let r=0n;for(let e=0;e<t.length;e++){const i=t.charAt(e),o=parseInt(i,n);if(Number.isNaN(o))throw new Error(`Invalid digit "${i}"`);r*=BigInt(n),r+=BigInt(o)}return r};a.fromBase=(t,n)=>{if("string"!=typeof t)throw new Error("First parameter must be string");if(!Number.isSafeInteger(n)||n<2||n>16)throw new Error("Invalid radix");if(10===n)return a(t);if(0===(t=t.trim()).length)throw new Error("Empty string is not allowed");const r=t.startsWith("-");r&&(t=t.slice(1));const e=t.match(/^([0-9a-f]*)(?:\.([0-9a-f]*)(?:\(([0-9a-f]+)\))?)?$/i);if(!e)throw new Error(`Cannot parse number "${t}"`);const i=e[1]??"",s=e[2]??"",m=e[3]??"";if(m.length>0){const t=u([i,s,m].join(""),n)-u([i,s].join(""),n),e=u((n-1).toString(n).repeat(m.length)+"0".repeat(s.length),n),a=new o(t,e).normalize();return r?a.neg():a}const h=u(i,n),c=u(s,n),d=new o(c,BigInt(n)**BigInt(s.length)),l=new o(h,1n).add(d).normalize();return r?l.neg():l};const m=(t,n,r)=>{if(!Number.isSafeInteger(t))throw new Error("Integer is expected for N");if(t<0)throw new Error("Negative N is not supported");if(0===t)throw new Error("N cannot be zero");if(1===t)return a(n).toFixed(r);const e=a(n);if(t%2==0&&-1===e.sign())throw new Error("Complex numbers are not supported");if(e.isZero())return new i(0n).toFixed(r);if(e.isOne())return new i(1n).toFixed(r);const s=new o(t-1,t),u=new o(e,t),m=((t,n)=>{const r=n<0;r&&(n=-n);let e=n**(1/t);return r&&(e=-e),e.toString()})(t,e.toNumber());let h=new i(m),c=h.trunc(r);for(;;){h=s.mul(h).add(u.mul(h.inv().pow(t-1)));const n=h.trunc(r);if(h.isZero()||c.eq(n))break;c=n}return h.toFixed(r)},h=(t,n)=>m(2,t,n),c=(t,n)=>m(3,t,n),d=(t,n,r)=>{const e=new o(t,1n),i=new o(n,1n).getFractionParts(!1);return m(i.denominator.toNumber(),e.pow(i.numerator),r)},l=(t,n)=>{const r=a(t);let e=r.add(1n),i=6n,s=4n;const u=r.pow(2n);let m=u;const h=new o(1n,10n**BigInt(n+5));for(;;){const t=m.mul(r.add(s-1n)).div(i);if(i*=s*(s+1n),s+=2n,m=m.mul(u),e=e.add(t).trunc(n+5),t.abs().lte(h))break}return e.toFixed(n)};class g{constructor(t,n){this.cachedDigits=0,this.fn=t,this.max=n}get(t){if(t<=this.cachedDigits)return this.cache.trunc(t);const n=new i(this.fn(t)),r=Math.min(this.max,t);return this.cachedDigits!==r&&(this.cache=n.trunc(r),this.cachedDigits=r),n}}const f=(t,n)=>{let r=a(t);if(r.isOne())return new i(0).toFixed(n);if(r.lte(0n))throw new Error("Invalid parameter");let e=0;for(;r.sub(1n).abs().gt("0.1");)r=new i(h(r,n+10)),e++;const o=r.sub(1n).div(r.add(1n)),s=o.pow(2n).normalize();let u=o,m=1n,c=a(o);for(;;){let t=a(0);for(let r=0;r<4;r++){u=u.mul(s),m+=2n;const r=u.div(m);t=t.add(r).trunc(n+10)}if(t.isZero())break;c=c.add(t)}return c=c.mul(2n**BigInt(e+1)),c.toFixed(n)},w=(t,n,r)=>{if(!Number.isSafeInteger(t)||t<2)throw new Error("Invalid parameter for N");const e=f(n,r+10),o=f(t,r+10);return new i(e).div(o).toFixed(r)},b=new g((t=>f(2n,t)),200),E=(t,n)=>new i(f(t,n+10)).div(b.get(n+10)).toFixed(n),p=new g((t=>f(10n,t)),200),I=(t,n)=>new i(f(t,n+10)).div(p.get(n+10)).toFixed(n),v=new g((t=>{if(0===t)return"3";let n=1n,r=3n*10n**BigInt(t+20),e=r;for(;0n!==r;)r=r*n/(4n*(n+1n)),n+=2n,e+=r/n;return`3.${e.toString().slice(1,t+1)}`}),1e3),N=t=>0===t?"3":v.get(t).toFixed(t),T=(n,r)=>{const e=r+10,{x:o,quadrant:s}=((t,n)=>{const r=new i(N(n)),e=r.mul(2n);(t=t.mod(e)).gt(r)?t=t.sub(e):t.lt(r.neg())&&(t=t.add(e));const o=r.div(2n),s=t.div(o);let a=0;return s.gte(o)?(a=2,t=r.sub(t)):s.gte(0n)?a=1:s.gte(o.neg())?(a=4,t=t.neg()):(a=3,t=r.sub(t.neg())),{quadrant:a,x:t}})(a(n),e),u=o.round(e,t.NEAREST_AWAY_FROM_ZERO).pow(2n).normalize();let m=u,h=2n,c=a(1n).sub(m.div(h).trunc(e)),d=3n;const l=a(1n).div(10n**BigInt(e));let g=1;for(;;){h*=d*(d+1n),d+=2n;const t=d*(d+1n);d+=2n,m=m.mul(u),h*=t;let i=m.mul(t);m=m.mul(u),i=i.sub(m);const o=i.div(h).trunc(e);if(g++,c=c.add(o),o.lt(l)){const t=c.trunc(r),i=o.add(l.mul(g)),s=c.add(i).trunc(r);if(t.eq(s))break;return a(T(n,e+50)).toFixed(r)}}return(1===s||4===s?c:c.neg()).round(r+3,t.TO_ZERO).toFixed(r)},O=(t,n)=>{const r=new i(N(n+10)),e=a(t);return T(r.div(2n).sub(e),n)},P=(t,n)=>{if(a(t).isZero())return"0";return a(O(t,n+10)).div(T(t,n+10)).toFixed(n)},F=(t,n)=>{let r=a(t);if(r.isZero())return"0";if(r.abs().isOne())return a(N(n)).div(4*r.sign()).toFixed(n);let e=0;for(;r.abs().gt("0.42");){const t=a(h(r.pow(2n).add(1n),n+10));r=r.div(t.add(1n)),e++}const i=r.pow(2).normalize(),o=i.pow(2).normalize();let s=3n,u=r.sub(r.mul(i).div(s)),m=r.mul(o);const c=a(1n).div(10n**BigInt(n+10));for(;;){s+=2n;const t=s+2n,r=m.mul(i.mul(-s).add(t)).div(s*t);if(s=t,m=m.mul(o),u=u.add(r).trunc(n+10),r.abs().lt(c))break}return u=u.mul(2n**BigInt(e)),u.toFixed(n)},S=(t,n)=>{const r=a(t);if(r.isZero())return"0";if(r.abs().isOne())return a(N(n)).mul(r.sign()).div(2n).toFixed(n);if(r.abs().eq("1/2"))return a(N(n)).mul(r.sign()).div(6n).toFixed(n);if(r.gt(1n)||r.lt(-1n))throw new Error("Out of range");const e=a(h(r.pow(2n).neg().add(1),n+10));return a(F(r.div(e.add(1n)),n+10)).mul(2).toFixed(n)},_=(t,n)=>{const r=a(t);if(r.isZero())return a(N(n)).div(2n).toFixed(n);if(r.isOne())return"0";if(r.abs().isOne())return N(n);if(r.abs().eq("1/2")){const t=a(N(n)).div(3n);return-1===r.sign()?t.mul(2n).toFixed(n):t.toFixed(n)}if(r.gt(1n)||r.lt(-1n))throw new Error("Out of range");return a(N(n+10)).div(2n).sub(S(r,n+10)).toFixed(n)},R=(t,n)=>{const r=a(t),e=r.pow(2n).normalize();let i=r,o=1n,s=r.trunc(n+5),u=2n;const m=a(1n).div(10n**BigInt(n+5));for(;;){i=i.mul(e),o*=u*(u+1n),u+=2n;const t=i.div(o);if(s=s.add(t).trunc(n+5),t.abs().lt(m))break}return s.toFixed(n)},x=(t,n)=>{const r=a(t).pow(2n).normalize();let e=r,i=2n,o=e.div(i).add(1n).trunc(n+5),s=3n;const u=a(1n).div(10n**BigInt(n+5));for(;;){e=e.mul(r),i*=s*(s+1n),s+=2n;const t=e.div(i);if(o=o.add(t).trunc(n+5),t.abs().lt(u))break}return o.toFixed(n)};export{a as ExactNumber,n as ModType,N as PI,t as RoundingMode,_ as acos,S as asin,F as atan,c as cbrt,T as cos,x as cosh,l as exp,f as log,I as log10,E as log2,w as logn,m as nthroot,d as pow,O as sin,R as sinh,h as sqrt,P as tan,r as trimTrailingZeros}; |
/*! | ||
* exactnumber v0.7.0 (https://www.npmjs.com/package/exactnumber) | ||
* exactnumber v0.8.0 (https://www.npmjs.com/package/exactnumber) | ||
* (c) Dani Biro | ||
@@ -41,2 +41,3 @@ * @license MIT | ||
/** Trims trailing zeros from numbers in fixed-point format (1.23000 -> 1.23) */ | ||
const trimTrailingZeros = (num) => { | ||
@@ -72,2 +73,13 @@ let zeropos = num.length; | ||
}; | ||
// export const modpow = (base: bigint, exp: bigint, mod: bigint) => { | ||
// let res = 1n; | ||
// while (exp > 0n) { | ||
// if (exp % 2n) { | ||
// res = (res * base) % mod; | ||
// } | ||
// base = base ** 2n % mod; | ||
// exp /= 2n; | ||
// } | ||
// return res; | ||
// }; | ||
@@ -162,8 +174,5 @@ class FixedNumber { | ||
const operand = parseParameter(x); | ||
if (!operand.isInteger()) { | ||
throw new Error('Invalid parameter'); | ||
} | ||
const exp = operand.toNumber(); | ||
if (!Number.isSafeInteger(exp)) { | ||
throw new Error('Invalid parameter'); | ||
if (!Number.isSafeInteger(exp) || exp < 0) { | ||
throw new Error('Unsupported parameter'); | ||
} | ||
@@ -220,3 +229,3 @@ const res = new FixedNumber(this.number ** BigInt(exp), this.decimalPos * exp); | ||
return this; | ||
return this.round(exports.RoundingMode.TO_NEGATIVE, decimals); | ||
return this.round(decimals, exports.RoundingMode.TO_NEGATIVE); | ||
} | ||
@@ -226,3 +235,3 @@ ceil(decimals) { | ||
return this; | ||
return this.round(exports.RoundingMode.TO_POSITIVE, decimals); | ||
return this.round(decimals, exports.RoundingMode.TO_POSITIVE); | ||
} | ||
@@ -232,5 +241,5 @@ trunc(decimals) { | ||
return this; | ||
return this.round(exports.RoundingMode.TO_ZERO, decimals); | ||
return this.round(decimals, exports.RoundingMode.TO_ZERO); | ||
} | ||
round(roundingMode, decimals) { | ||
round(decimals, roundingMode) { | ||
decimals = decimals === undefined ? 0 : decimals; | ||
@@ -262,2 +271,12 @@ if (!Number.isSafeInteger(decimals) || decimals < 0) { | ||
} | ||
if (![ | ||
undefined, | ||
exports.RoundingMode.NEAREST_TO_ZERO, | ||
exports.RoundingMode.NEAREST_AWAY_FROM_ZERO, | ||
exports.RoundingMode.NEAREST_TO_POSITIVE, | ||
exports.RoundingMode.NEAREST_TO_NEGATIVE, | ||
exports.RoundingMode.NEAREST_TO_EVEN, | ||
].includes(roundingMode)) { | ||
throw new Error('Invalid rounding mode. Use the predefined values from the RoundingMode enum.'); | ||
} | ||
let fracStr = (fracPart < 0n ? -fracPart : fracPart).toString(); | ||
@@ -300,17 +319,28 @@ if (fracStr.length < expectedFracDecimals) { | ||
} | ||
if (roundingMode === undefined || | ||
roundingMode === exports.RoundingMode.NEAREST_TO_ZERO || | ||
roundingMode === exports.RoundingMode.NEAREST_AWAY_FROM_ZERO || | ||
roundingMode === exports.RoundingMode.NEAREST_TO_POSITIVE || | ||
roundingMode === exports.RoundingMode.NEAREST_TO_NEGATIVE || | ||
roundingMode === exports.RoundingMode.NEAREST_TO_EVEN) { | ||
if (Number(fracStr[0]) < 5) { | ||
return new FixedNumber(numberToZero, decimals); | ||
if (Number(fracStr[0]) < 5) { | ||
return new FixedNumber(numberToZero, decimals); | ||
} | ||
const res = this.number < 0 ? numberToZero - 1n : numberToZero + 1n; | ||
return new FixedNumber(res, decimals); | ||
} | ||
_incExponent(amount) { | ||
if (amount === 0) | ||
return this; | ||
let newNumber = this.number; | ||
let newDecimalPos = this.decimalPos; | ||
if (amount < 0) { | ||
newDecimalPos -= amount; | ||
} | ||
else { | ||
// amount >= 0 | ||
const maxChange = Math.min(amount, this.decimalPos); | ||
newDecimalPos -= maxChange; | ||
const rem = amount - maxChange; | ||
if (rem > 0) { | ||
newNumber *= 10n ** BigInt(rem); | ||
} | ||
const res = this.number < 0 ? numberToZero - 1n : numberToZero + 1n; | ||
return new FixedNumber(res, decimals); | ||
} | ||
throw new Error('Invalid rounding mode. Use the predefined values from the RoundingMode enum.'); | ||
return new FixedNumber(newNumber, newDecimalPos); | ||
} | ||
roundToDigits(roundingMode, digits) { | ||
roundToDigits(digits, roundingMode) { | ||
if (!Number.isSafeInteger(digits) || digits < 1) { | ||
@@ -323,12 +353,6 @@ throw new Error('Invalid value for digits'); | ||
const str = absNumber.toString(); | ||
const newNumber = new FixedNumber(`0.${str}`); | ||
let roundedNumber = newNumber.round(roundingMode, digits); | ||
const totalDigits = str.length; | ||
const wholeDigits = totalDigits - this.decimalPos; | ||
if (wholeDigits < 0) { | ||
roundedNumber = roundedNumber.div(10n ** BigInt(-wholeDigits)); | ||
} | ||
else { | ||
roundedNumber = roundedNumber.mul(10n ** BigInt(wholeDigits)); | ||
} | ||
const numberBetweenZeroAndOne = new FixedNumber(absNumber, str.length); | ||
let roundedNumber = numberBetweenZeroAndOne.round(digits, roundingMode); | ||
const integerDigits = str.length - this.decimalPos; | ||
roundedNumber = roundedNumber._incExponent(integerDigits); | ||
return isNegative ? roundedNumber.neg() : roundedNumber; | ||
@@ -514,23 +538,22 @@ } | ||
} | ||
toFixed(digits, trimTrailingZeros) { | ||
if (!Number.isSafeInteger(digits) || digits < 0) | ||
toFixed(decimals, roundingMode = exports.RoundingMode.TO_ZERO) { | ||
if (!Number.isSafeInteger(decimals) || decimals < 0) | ||
throw new Error('Invalid parameter'); | ||
const extraDigitsNeeded = digits - this.decimalPos; | ||
const exp = 10n ** BigInt(Math.abs(extraDigitsNeeded)); | ||
const num = extraDigitsNeeded < 0 ? this.number / exp : this.number * exp; | ||
const res = bigIntToStr(num, digits, Boolean(trimTrailingZeros)); | ||
return res; | ||
const rounded = this.round(decimals, roundingMode); | ||
return bigIntToStr(rounded.number, decimals, false); | ||
} | ||
toExponential(digits) { | ||
toExponential(digits, roundingMode = exports.RoundingMode.TO_ZERO) { | ||
if (!Number.isSafeInteger(digits) || digits < 0) | ||
throw new Error('Invalid parameter'); | ||
const isNegative = this.number < 0n; | ||
const absNumber = isNegative ? -this.number : this.number; | ||
const str = absNumber.toString(); | ||
const rounded = this.roundToDigits(digits + 1, roundingMode).normalize(); | ||
const isNegative = rounded.sign() === -1; | ||
const absNumber = rounded.abs(); | ||
const str = absNumber.number.toString(); | ||
const slicedString = str.length <= digits ? `${str}${'0'.repeat(digits - str.length + 1)}` : str.slice(0, digits + 1); | ||
const strWithPoint = slicedString.length > 1 ? `${slicedString.slice(0, 1)}.${slicedString.slice(1)}` : slicedString; | ||
const fractionalDigitsBefore = this.decimalPos; | ||
const fractionalDigitsBefore = absNumber.decimalPos; | ||
const fractionalDigitsAfter = str.length - 1; | ||
const exponent = fractionalDigitsAfter - fractionalDigitsBefore; | ||
return `${isNegative ? '-' : ''}${strWithPoint}e${exponent >= 0 ? '+' : ''}${exponent}`; | ||
const res = `${isNegative ? '-' : ''}${strWithPoint}e${exponent >= 0 ? '+' : ''}${exponent}`; | ||
return res; | ||
} | ||
@@ -543,9 +566,6 @@ toBase(radix, maxDigits) { | ||
} | ||
if (radix === 10) { | ||
return maxDigits === undefined ? this.toString() : this.toFixed(maxDigits, true); | ||
} | ||
const num = this.normalize(); | ||
if (num.decimalPos === 0) | ||
return num.number.toString(radix); | ||
const loopEnd = maxDigits === undefined ? Number.MAX_SAFE_INTEGER : maxDigits + 1; | ||
const loopEnd = maxDigits === undefined ? Number.MAX_SAFE_INTEGER : maxDigits; | ||
let intPart = num.intPart(); | ||
@@ -561,4 +581,2 @@ let fracPart = num.sub(intPart); | ||
while (!fracPart.isZero()) { | ||
if (digits.length === loopEnd) | ||
break; | ||
const mul = fracPart.mul(radix); | ||
@@ -571,2 +589,5 @@ const mulStr = mul.toString(); | ||
} | ||
if (digits.length === loopEnd) { | ||
break; | ||
} | ||
const q = Math.abs(mul.intPart().toNumber()); | ||
@@ -577,5 +598,2 @@ digits.push(q.toString(radix)); | ||
} | ||
if (digits.length === loopEnd) { | ||
digits.pop(); | ||
} | ||
return [isNegative ? '-' : '', intPart.number.toString(radix), digits.length ? '.' : '', ...digits].join(''); | ||
@@ -593,2 +611,9 @@ } | ||
} | ||
toPrecision(digits, roundingMode = exports.RoundingMode.TO_ZERO) { | ||
if (!Number.isSafeInteger(digits) || digits < 1) | ||
throw new Error('Invalid parameter'); | ||
const rounded = this.roundToDigits(digits, roundingMode); | ||
const res = bigIntToStr(rounded.number, rounded.decimalPos, false); | ||
return res; | ||
} | ||
valueOf() { | ||
@@ -626,3 +651,3 @@ throw new Error('Unsafe conversion to Number type! Use toNumber() instead.'); | ||
if (!m) { | ||
throw new Error(`Cannot parse number "${x}"`); | ||
throw new Error(`Cannot parse string "${x}"`); | ||
} | ||
@@ -679,2 +704,8 @@ const wholePart = m[1] === '-' ? '-0' : m[1]; | ||
} | ||
// if (false) { | ||
// const commonDenominator = this.lcm(this.denominator, denominator); | ||
// const lMultiplier = commonDenominator / this.denominator; | ||
// const rMultiplier = commonDenominator / denominator; | ||
// return new Fraction(this.numerator * lMultiplier + numerator * rMultiplier, commonDenominator); | ||
// } | ||
return new Fraction(this.numerator * denominator + numerator * this.denominator, denominator * this.denominator); | ||
@@ -697,3 +728,3 @@ } | ||
const num = this.div(x); | ||
return num.round(); | ||
return num.trunc(); | ||
} | ||
@@ -720,6 +751,8 @@ mod(r, type = exports.ModType.TRUNCATED) { | ||
pow(x) { | ||
const { numerator, denominator } = this.parseParameter(x); | ||
if (denominator !== 1n) | ||
const param = this.parseParameter(x); | ||
if (!param.isInteger() || param.sign() === -1) { | ||
throw new Error('Unsupported parameter'); | ||
const res = new Fraction(this.numerator ** numerator, this.denominator ** numerator); | ||
} | ||
const intNum = param.numerator / param.denominator; | ||
const res = new Fraction(this.numerator ** intNum, this.denominator ** intNum); | ||
return res; | ||
@@ -734,3 +767,3 @@ } | ||
return new FixedNumber(this.numerator); | ||
return this.round(exports.RoundingMode.TO_NEGATIVE, decimals); | ||
return this.round(decimals, exports.RoundingMode.TO_NEGATIVE); | ||
} | ||
@@ -740,3 +773,3 @@ ceil(decimals) { | ||
return new FixedNumber(this.numerator); | ||
return this.round(exports.RoundingMode.TO_POSITIVE, decimals); | ||
return this.round(decimals, exports.RoundingMode.TO_POSITIVE); | ||
} | ||
@@ -746,5 +779,5 @@ trunc(decimals) { | ||
return new FixedNumber(this.numerator); | ||
return this.round(exports.RoundingMode.TO_ZERO, decimals); | ||
return this.round(decimals, exports.RoundingMode.TO_ZERO); | ||
} | ||
round(roundingMode, decimals) { | ||
round(decimals, roundingMode) { | ||
decimals = decimals === undefined ? 0 : decimals; | ||
@@ -759,3 +792,3 @@ if (!Number.isSafeInteger(decimals) || decimals < 0) { | ||
// nothing is lost | ||
return fixedPart.round(roundingMode, decimals); | ||
return fixedPart.round(decimals, roundingMode); | ||
} | ||
@@ -765,6 +798,6 @@ // 0.105 might got cutted to 0.1, which might round incorrectly | ||
const correctedFixedNum = new FixedNumber(`${fixedPart.toFixed(decimals + 1)}1`); | ||
const res = correctedFixedNum.round(roundingMode, decimals); | ||
const res = correctedFixedNum.round(decimals, roundingMode); | ||
return res; | ||
} | ||
roundToDigits(roundingMode, digits) { | ||
roundToDigits(digits, roundingMode) { | ||
if (!Number.isSafeInteger(digits) || digits < 1) { | ||
@@ -774,3 +807,3 @@ throw new Error('Invalid value for digits'); | ||
if (this.isZero()) | ||
return this; | ||
return new FixedNumber(0n); | ||
let x = this.abs(); | ||
@@ -788,9 +821,4 @@ // move the number to the [0.1, 1) interval | ||
} | ||
let roundedNumber = x.round(roundingMode, digits); | ||
if (divisions < 0) { | ||
roundedNumber = roundedNumber.div(10n ** BigInt(-divisions)); | ||
} | ||
else { | ||
roundedNumber = roundedNumber.mul(10n ** BigInt(divisions)); | ||
} | ||
let roundedNumber = x.round(digits, roundingMode); | ||
roundedNumber = roundedNumber._incExponent(divisions); | ||
return this.sign() === -1 ? roundedNumber.neg() : roundedNumber; | ||
@@ -962,12 +990,7 @@ } | ||
// eslint-disable-next-line @typescript-eslint/no-shadow | ||
toFixed(digits, trimTrailingZeros) { | ||
if (!Number.isSafeInteger(digits) || digits < 0) | ||
toFixed(decimals, roundingMode = exports.RoundingMode.TO_ZERO) { | ||
if (!Number.isSafeInteger(decimals) || decimals < 0) | ||
throw new Error('Invalid parameter'); | ||
let { numerator } = this; | ||
if (digits > 0) { | ||
numerator *= 10n ** BigInt(digits); | ||
} | ||
const n = numerator / this.denominator; | ||
const res = bigIntToStr(n, digits, Boolean(trimTrailingZeros)); | ||
return res; | ||
const [number, decimalPos] = this.round(decimals, roundingMode).serialize(); | ||
return bigIntToStr(number, decimalPos, false); | ||
} | ||
@@ -1002,7 +1025,7 @@ toRepeatingParts(maxDigits) { | ||
} | ||
toExponential(digits) { | ||
toExponential(digits, roundingMode = exports.RoundingMode.TO_ZERO) { | ||
if (!Number.isSafeInteger(digits) || digits < 0) | ||
throw new Error('Invalid parameters'); | ||
const fixedNum = this.toFixedNumber(digits); | ||
return fixedNum.toExponential(digits); | ||
return fixedNum.toExponential(digits, roundingMode); | ||
} | ||
@@ -1025,3 +1048,3 @@ toFraction() { | ||
if (radix === 10) { | ||
return maxDigits === undefined ? this.toRepeatingDigits(maxDigits) : this.toFixed(maxDigits, true); | ||
return maxDigits === undefined ? this.toRepeatingDigits(maxDigits) : trimTrailingZeros(this.toFixed(maxDigits)); | ||
} | ||
@@ -1065,2 +1088,8 @@ const num = this.normalize(); | ||
} | ||
toPrecision(digits, roundingMode = exports.RoundingMode.TO_ZERO) { | ||
if (!Number.isSafeInteger(digits) || digits < 1) | ||
throw new Error('Invalid parameter'); | ||
const [number, decimalPos] = this.roundToDigits(digits, roundingMode).serialize(); | ||
return bigIntToStr(number, decimalPos, false); | ||
} | ||
valueOf() { | ||
@@ -1392,3 +1421,3 @@ throw new Error('Unsafe conversion to Number type! Use toNumber() instead.'); | ||
const { x, quadrant } = toLessThanHalfPi(ExactNumber(angle), EXTRA_DIGITS); | ||
const x2 = x.round(exports.RoundingMode.NEAREST_AWAY_FROM_ZERO, EXTRA_DIGITS).pow(2n).normalize(); | ||
const x2 = x.round(EXTRA_DIGITS, exports.RoundingMode.NEAREST_AWAY_FROM_ZERO).pow(2n).normalize(); | ||
// cos x = 1 - x^2/2! + x^4/4! - ... | ||
@@ -1433,3 +1462,3 @@ let xPow = x2; | ||
const res = quadrant === 1 || quadrant === 4 ? xk : xk.neg(); | ||
const strRes = res.round(exports.RoundingMode.TO_ZERO, digits + 3).toFixed(digits); | ||
const strRes = res.round(digits + 3, exports.RoundingMode.TO_ZERO).toFixed(digits); | ||
return strRes; | ||
@@ -1601,2 +1630,3 @@ }; | ||
exports.tan = tan; | ||
exports.trimTrailingZeros = trimTrailingZeros; | ||
@@ -1603,0 +1633,0 @@ Object.defineProperty(exports, '__esModule', { value: true }); |
/*! | ||
* exactnumber v0.7.0 (https://www.npmjs.com/package/exactnumber) | ||
* exactnumber v0.8.0 (https://www.npmjs.com/package/exactnumber) | ||
* (c) Dani Biro | ||
@@ -7,2 +7,2 @@ * @license MIT | ||
!function(n,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((n="undefined"!=typeof globalThis?globalThis:n||self).exactnumber={})}(this,(function(n){"use strict";var t,e;n.RoundingMode=void 0,(t=n.RoundingMode||(n.RoundingMode={})).NEAREST_TO_POSITIVE="NP",t.NEAREST_TO_NEGATIVE="NN",t.NEAREST_TO_EVEN="NE",t.NEAREST_TO_ZERO="NZ",t.NEAREST_AWAY_FROM_ZERO="NA",t.TO_POSITIVE="P",t.TO_NEGATIVE="N",t.TO_ZERO="Z",t.AWAY_FROM_ZERO="A",n.ModType=void 0,(e=n.ModType||(n.ModType={})).TRUNCATED="T",e.FLOORED="F",e.EUCLIDEAN="E";const r=n=>{let t=n.length;for(;t>0&&["0","."].includes(n.charAt(t-1));)t--;return t!==n.length?n.slice(0,t):n},i=(n,t,e)=>{let i=n.toString();if(0===t)return i;const o=i.startsWith("-");if(o&&(i=i.slice(1)),t>=i.length&&(i="0".repeat(t-i.length+1)+i),t>0){const n=i.slice(0,-t);let o=i.slice(-t);e&&(o=r(o)),i=o.length?`${n}.${o}`:n}return o?`-${i}`:i};class o{constructor(n,t=0){if(this.type="fixed","bigint"==typeof n)this.number=n,this.decimalPos=t;else{const t=this.parseConstructorParameter(n);this.number=t.number,this.decimalPos=t.decimalPos}}parseConstructorParameter(n){if(n instanceof o)return{number:n.number,decimalPos:n.decimalPos};if(n instanceof s){if(!n.isInteger())throw new Error("Cannot create FixedNumber from non-integer Fraction");return{number:n.trunc().number,decimalPos:0}}if("number"==typeof n){if(!Number.isSafeInteger(n))throw new Error("The specified number cannot be exactly represented as an integer. Please provide a string instead.");return{number:BigInt(n),decimalPos:0}}if("string"==typeof n){if(0===(n=n.trim()).length)throw new Error("Empty string is not allowed");const t=n.match(/^(-?[0-9]*)(?:\.([0-9]*))?(?:[eE]([+-]?[0-9]+))?$/);if(!t)throw new Error(`Cannot parse number "${n}"`);let e=0,r=t[1]??"0";if(void 0!==t[2]&&(r+=t[2],e+=t[2].length),void 0!==t[3]){const n=Number(t[3]);n>0?r+="0".repeat(n):e-=n}return{number:BigInt(r),decimalPos:e}}throw new Error("Unsupported parameter!")}scaleNumber(n,t){const e=Math.max(this.decimalPos,t);return{a:e===this.decimalPos?this.number:this.number*10n**BigInt(e-this.decimalPos),b:e===t?n:n*10n**BigInt(e-t),decimalPos:e}}add(n){const t=a(n);if(t instanceof s)return t.add(this);const e=t,{a:r,b:i,decimalPos:u}=this.scaleNumber(e.number,e.decimalPos);return new o(r+i,u)}sub(n){const t=a(n);return this.add(t.neg())}mul(n){const t=a(n);if(t instanceof s)return t.mul(this);const e=t;return new o(this.number*e.number,this.decimalPos+e.decimalPos)}pow(n){const t=a(n);if(!t.isInteger())throw new Error("Invalid parameter");const e=t.toNumber();if(!Number.isSafeInteger(e))throw new Error("Invalid parameter");return new o(this.number**BigInt(e),this.decimalPos*e)}div(n){return this.convertToFraction().div(n)}divToInt(n){const t=a(n);if(t instanceof s)return this.convertToFraction().divToInt(t);const e=t,{a:r,b:i}=this.scaleNumber(e.number,e.decimalPos);return new o(r/i)}mod(t,e=n.ModType.TRUNCATED){const r=a(t);if(r instanceof s)return this.convertToFraction().mod(r);const i=r,{a:u,b:d,decimalPos:m}=this.scaleNumber(i.number,i.decimalPos),h=u%d,c=new o(h,m);if(e===n.ModType.TRUNCATED)return c;if(e===n.ModType.FLOORED)return Number(u<0)^Number(d<0)?c.add(d):c;if(e===n.ModType.EUCLIDEAN)return h<0?c.add(d<0?-d:d):c;throw new Error("Invalid ModType")}abs(){return new o(this.number<0?-this.number:this.number,this.decimalPos)}neg(){return this.mul(-1n)}inv(){return this.convertToFraction().inv()}floor(t){return 0===this.decimalPos?this:this.round(n.RoundingMode.TO_NEGATIVE,t)}ceil(t){return 0===this.decimalPos?this:this.round(n.RoundingMode.TO_POSITIVE,t)}trunc(t){return 0===this.decimalPos?this:this.round(n.RoundingMode.TO_ZERO,t)}round(t,e){if(e=void 0===e?0:e,!Number.isSafeInteger(e)||e<0)throw new Error("Invalid value for decimals");const r=this.decimalPos-e,i=10n**BigInt(Math.abs(r)),s=r>0?this.number/i:this.number*i;if(t===n.RoundingMode.TO_ZERO)return new o(s,e);const a=r>0?Math.abs(r):e,u=r>0?this.number%i:s%10n**BigInt(e);if(0n===u)return new o(s,e);if(t===n.RoundingMode.AWAY_FROM_ZERO){const n=this.number<0n?s-1n:s+1n;return new o(n,e)}if(t===n.RoundingMode.TO_POSITIVE){const n=this.number<0n?s:s+1n;return new o(n,e)}if(t===n.RoundingMode.TO_NEGATIVE){const n=this.number>=0n?s:s-1n;return new o(n,e)}let d=(u<0n?-u:u).toString();d.length<a&&(d="0".repeat(a-d.length)+d);let m="5"===d[0];if(m)for(let n=1;n<d.length;n++)if("0"!==d[n]){m=!1;break}if(m){if(t===n.RoundingMode.NEAREST_TO_ZERO)return new o(s,e);if(t===n.RoundingMode.NEAREST_AWAY_FROM_ZERO){const n=this.number<0n?s-1n:s+1n;return new o(n,e)}if(void 0===t||t===n.RoundingMode.NEAREST_TO_POSITIVE){const n=this.number<0n?s:s+1n;return new o(n,e)}if(t===n.RoundingMode.NEAREST_TO_NEGATIVE){const n=this.number>=0n?s:s-1n;return new o(n,e)}if(t===n.RoundingMode.NEAREST_TO_EVEN){if(s%2n===0n)return new o(s,e);return new o(s<0n?s-1n:s+1n,e)}}if(void 0===t||t===n.RoundingMode.NEAREST_TO_ZERO||t===n.RoundingMode.NEAREST_AWAY_FROM_ZERO||t===n.RoundingMode.NEAREST_TO_POSITIVE||t===n.RoundingMode.NEAREST_TO_NEGATIVE||t===n.RoundingMode.NEAREST_TO_EVEN){if(Number(d[0])<5)return new o(s,e);const n=this.number<0?s-1n:s+1n;return new o(n,e)}throw new Error("Invalid rounding mode. Use the predefined values from the RoundingMode enum.")}roundToDigits(n,t){if(!Number.isSafeInteger(t)||t<1)throw new Error("Invalid value for digits");const e=this.number<0n,r=(e?-this.number:this.number).toString();let i=new o(`0.${r}`).round(n,t);const s=r.length-this.decimalPos;return i=s<0?i.div(10n**BigInt(-s)):i.mul(10n**BigInt(s)),e?i.neg():i}intPart(){return this.trunc()}fracPart(){return this.sub(this.trunc())}sign(){return this.number<0n?-1:1}bitwiseAnd(n){if(n=u(n),!this.isInteger()||-1===this.sign()||!n.isInteger()||-1===n.sign())throw new Error("Only positive integers are supported");n instanceof s&&(n=n.trunc());const t=2n**24n;let e=this.normalize().number,r=n.trunc().normalize().number,i=0n,a=1n;for(;e>0&&r>0;){const n=BigInt.asUintN(24,e),o=BigInt.asUintN(24,r);i+=BigInt(Number(n)&Number(o))*a,a*=t,e/=t,r/=t}return new o(i)}bitwiseOr(n){if(n=u(n),!this.isInteger()||-1===this.sign()||!n.isInteger()||-1===n.sign())throw new Error("Only positive integers are supported");n instanceof s&&(n=n.trunc());const t=2n**24n;let e=this.normalize().number,r=n.trunc().normalize().number,i=0n,a=1n;for(;e>0||r>0;){const n=BigInt.asUintN(24,e),o=BigInt.asUintN(24,r);i+=BigInt(Number(n)|Number(o))*a,a*=t,e/=t,r/=t}return new o(i)}bitwiseXor(n){if(n=u(n),!this.isInteger()||-1===this.sign()||!n.isInteger()||-1===n.sign())throw new Error("Only positive integers are supported");n instanceof s&&(n=n.trunc());const t=2n**24n;let e=this.normalize().number,r=n.trunc().normalize().number,i=0n,a=1n;for(;e>0||r>0;){const n=BigInt.asUintN(24,e),o=BigInt.asUintN(24,r);i+=BigInt(Number(n)^Number(o))*a,a*=t,e/=t,r/=t}return new o(i)}shiftLeft(n){if(!this.isInteger()||-1===this.sign())throw new Error("Only positive integers are supported");if(!Number.isSafeInteger(n)||n<0)throw new Error("Invalid value for bitCount");const t=2n**BigInt(n);return this.mul(t)}shiftRight(n){if(!this.isInteger()||-1===this.sign())throw new Error("Only positive integers are supported");if(!Number.isSafeInteger(n)||n<0)throw new Error("Invalid value for bitCount");const t=2n**BigInt(n);return new o(this.normalize().number/t)}cmp(n){const t=a(n);if(t instanceof s)return-t.cmp(this);const e=t,{a:r,b:i}=this.scaleNumber(e.number,e.decimalPos);return r===i?0:r>i?1:-1}eq(n){return 0===this.cmp(n)}lt(n){return-1===this.cmp(n)}lte(n){return this.cmp(n)<=0}gt(n){return 1===this.cmp(n)}gte(n){return this.cmp(n)>=0}clamp(n,t){const e=u(n),r=u(t);if(e.gt(r))throw new Error("Min parameter has to be smaller than max");return this.lt(e)?e:this.gt(r)?r:this}isZero(){return 0n===this.number}isOne(){if(0===this.decimalPos)return 1n===this.number;const n=10n**BigInt(this.decimalPos),t=this.number/n;return 1n===t&&t*n===this.number}isInteger(){return 0===this.decimalPos||this.number%10n**BigInt(this.decimalPos)===0n}serialize(){return[this.number,this.decimalPos]}getFractionParts(n=!0){return this.convertToFraction().getFractionParts(n)}normalize(){if(0===this.decimalPos)return this;let n=this.decimalPos,t=this.number;for(;n>0&&t%10n===0n;)n--,t/=10n;return new o(t,n)}convertToFraction(){if(0===this.decimalPos)return new s(this.number,1n);const n=10n**BigInt(this.decimalPos);return new s(this.number,n)}toNumber(){return Number(this.toString())}toFixed(n,t){if(!Number.isSafeInteger(n)||n<0)throw new Error("Invalid parameter");const e=n-this.decimalPos,r=10n**BigInt(Math.abs(e)),o=e<0?this.number/r:this.number*r;return i(o,n,Boolean(t))}toExponential(n){if(!Number.isSafeInteger(n)||n<0)throw new Error("Invalid parameter");const t=this.number<0n,e=(t?-this.number:this.number).toString(),r=e.length<=n?`${e}${"0".repeat(n-e.length+1)}`:e.slice(0,n+1),i=r.length>1?`${r.slice(0,1)}.${r.slice(1)}`:r,o=this.decimalPos,s=e.length-1-o;return`${t?"-":""}${i}e${s>=0?"+":""}${s}`}toBase(n,t){if(!Number.isSafeInteger(n)||n<2||n>16)throw new Error("Invalid radix");if(void 0!==t&&(!Number.isSafeInteger(t)||t<0))throw new Error("Invalid parameter");if(10===n)return void 0===t?this.toString():this.toFixed(t,!0);const e=this.normalize();if(0===e.decimalPos)return e.number.toString(n);const r=void 0===t?Number.MAX_SAFE_INTEGER:t+1;let i=e.intPart(),o=e.sub(i);const s=-1===e.sign();s&&(i=i.neg(),o=o.neg());const a=new Map;let u=[];for(;!o.isZero()&&u.length!==r;){const t=o.mul(n),e=t.toString(),r=a.get(e);if(void 0!==r){u=[...u.slice(0,r-1),"(",...u.slice(r-1),")"];break}const i=Math.abs(t.intPart().toNumber());u.push(i.toString(n)),o=t.fracPart(),a.set(e,u.length)}return u.length===r&&u.pop(),[s?"-":"",i.number.toString(n),u.length?".":"",...u].join("")}toFraction(){return this.convertToFraction().toFraction()}toString(n,t){if(void 0===n||10===n){const n=void 0!==t?this.trunc(t):this;return i(n.number,n.decimalPos,!0)}return this.toBase(n,t)}valueOf(){throw new Error("Unsafe conversion to Number type! Use toNumber() instead.")}}class s{constructor(n,t){if(this.type="fraction","bigint"==typeof n&&"bigint"==typeof t)this.numerator=n,this.denominator=t;else{const e=this.parseParameter(n),r=this.parseParameter(t),i=e.div(r),s=i instanceof o?i.convertToFraction():i;this.numerator=s.numerator,this.denominator=s.denominator}if(0n===this.denominator)throw new Error("Division by zero")}parseRepeatingDecimal(n){if(!n.includes("("))return new o(n).convertToFraction();const t=(n=n.trim()).match(/^(-?[0-9]*)\.([0-9]+)?\(([0-9]+)\)(?:[eE]([+-]?[0-9]+))?$/);if(!t)throw new Error(`Cannot parse number "${n}"`);const e="-"===t[1]?"-0":t[1],r=t[2]??"",i=t[3],a=t[4],u=BigInt(e+r+i)-BigInt(e+r),d=BigInt("9".repeat(i.length)+"0".repeat(r.length)),m=new s(u,d);if(void 0!==a){const n=a.startsWith("-"),t=10n**BigInt(n?a.slice(1):a);return n?m.div(t).normalize():m.mul(t).normalize()}return m.normalize()}parseParameter(n){if(n instanceof s)return n;if(n instanceof o)return n.convertToFraction();if("number"==typeof n){if(!Number.isSafeInteger(n))throw new Error("Floating point values as numbers are unsafe. Please provide them as a string.");return new s(BigInt(n),1n)}if("bigint"==typeof n)return new s(n,1n);if("string"==typeof n){const t=n.split("/");if(t.length>2)throw new Error(`Cannot parse string '${n}'`);const e=this.parseRepeatingDecimal(t[0]),r=t[1]?this.parseRepeatingDecimal(t[1]):new s(1n,1n);return e.div(r).convertToFraction()}throw new Error("Unsupported parameter!")}add(n){const{numerator:t,denominator:e}=this.parseParameter(n);return this.denominator===e?new s(this.numerator+t,this.denominator):new s(this.numerator*e+t*this.denominator,e*this.denominator)}sub(n){const{numerator:t,denominator:e}=this.parseParameter(n);return this.add(new s(-t,e))}mul(n){const{numerator:t,denominator:e}=this.parseParameter(n);return new s(this.numerator*t,this.denominator*e)}div(n){const{numerator:t,denominator:e}=this.parseParameter(n);return this.mul(new s(e,t))}divToInt(n){return this.div(n).round()}mod(t,e=n.ModType.TRUNCATED){const r=this.parseParameter(t),i=r.denominator*this.numerator%(r.numerator*this.denominator),o=this.denominator*r.denominator,a=new s(i,o);if(e===n.ModType.TRUNCATED)return a;if(e===n.ModType.FLOORED)return Number(-1===this.sign())^Number(-1===r.sign())?a.add(r):a;if(e===n.ModType.EUCLIDEAN)return a.sign()<0?a.add(r.sign()<0?r.neg():r):a;throw new Error("Invalid ModType")}pow(n){const{numerator:t,denominator:e}=this.parseParameter(n);if(1n!==e)throw new Error("Unsupported parameter");return new s(this.numerator**t,this.denominator**t)}inv(){return new s(this.denominator,this.numerator)}floor(t){return 1n===this.denominator?new o(this.numerator):this.round(n.RoundingMode.TO_NEGATIVE,t)}ceil(t){return 1n===this.denominator?new o(this.numerator):this.round(n.RoundingMode.TO_POSITIVE,t)}trunc(t){return 1n===this.denominator?new o(this.numerator):this.round(n.RoundingMode.TO_ZERO,t)}round(n,t){if(t=void 0===t?0:t,!Number.isSafeInteger(t)||t<0)throw new Error("Invalid value for decimals");const e=this.toFixedNumber(t+1);if(this.sub(e).isZero())return e.round(n,t);return new o(`${e.toFixed(t+1)}1`).round(n,t)}roundToDigits(n,t){if(!Number.isSafeInteger(t)||t<1)throw new Error("Invalid value for digits");if(this.isZero())return this;let e=this.abs(),r=0;for(;e.gte(1n);)e=e.div(10n),r++;const i=new s(1n,10n);for(;e.lt(i);)e=e.mul(10n),r--;let o=e.round(n,t);return o=r<0?o.div(10n**BigInt(-r)):o.mul(10n**BigInt(r)),-1===this.sign()?o.neg():o}gcd(n,t){let e=n<0?-n:n,r=t<0?-t:t;if(r>e){const n=e;e=r,r=n}for(;;){if(0n===r)return e;if(e%=r,0n===e)return r;r%=e}}lcm(n,t){return n*t/this.gcd(n,t)}normalize(){let{numerator:n,denominator:t}=this;const e=this.gcd(n,t);return e>1n&&(n/=e,t/=e),t<0n&&(n=-n,t=-t),new s(n,t)}getFractionParts(n=!0){const t=n?this.normalize():this;return{numerator:new o(t.numerator),denominator:new o(t.denominator)}}sign(){return(this.numerator<0n?-1:1)*(this.denominator<0n?-1:1)}abs(){return new s(this.numerator<0n?-this.numerator:this.numerator,this.denominator<0n?-this.denominator:this.denominator)}neg(){return this.mul(-1n)}intPart(){return this.trunc()}fracPart(){return this.sub(this.trunc())}cmp(n){const t=this.parseParameter(n),e=this.denominator===t.denominator,r=e?this.numerator:this.numerator*t.denominator,i=e?t.numerator:t.numerator*this.denominator;return r===i?0:r>i?1:-1}eq(n){return 0===this.cmp(n)}lt(n){return-1===this.cmp(n)}lte(n){return this.cmp(n)<=0}gt(n){return 1===this.cmp(n)}gte(n){return this.cmp(n)>=0}clamp(n,t){const e=u(n),r=u(t);if(e.gt(r))throw new Error("Min parameter has to be smaller than max");return this.lt(e)?e:this.gt(r)?r:this}isZero(){return 0n===this.numerator}isOne(){return this.numerator===this.denominator}isInteger(){return this.numerator%this.denominator===0n}serialize(){return[this.numerator,this.denominator]}toNumber(){return Number(this.numerator)/Number(this.denominator)}convertToFraction(){return this}getNumberForBitwiseOp(){if(!this.isInteger()||-1===this.sign())throw new Error("Only positive integers are supported");return this.intPart()}bitwiseAnd(n){return this.getNumberForBitwiseOp().bitwiseAnd(n)}bitwiseOr(n){return this.getNumberForBitwiseOp().bitwiseOr(n)}bitwiseXor(n){return this.getNumberForBitwiseOp().bitwiseXor(n)}shiftLeft(n){return this.getNumberForBitwiseOp().shiftLeft(n)}shiftRight(n){return this.getNumberForBitwiseOp().shiftRight(n)}getDecimalFormat(n){n=void 0===n?Number.MAX_SAFE_INTEGER:n;let t=this.denominator<0?-this.denominator:this.denominator,e=0;for(;t%2n===0n;)t/=2n,e++;let r=0;for(;t%5n===0n;)t/=5n,r++;const i=Math.max(e,r);if(1n===t)return{cycleLen:0,cycleStart:i};const o=Math.max(1,n-i);let s=10n%t,a=1;for(;1n!==s;){if(a===o)return{cycleLen:null,cycleStart:i};s=10n*s%t,a++}return{cycleLen:a,cycleStart:i}}toFixed(n,t){if(!Number.isSafeInteger(n)||n<0)throw new Error("Invalid parameter");let{numerator:e}=this;n>0&&(e*=10n**BigInt(n));const r=e/this.denominator;return i(r,n,Boolean(t))}toRepeatingParts(n){if(this.isZero())return["0","",""];const{cycleLen:t,cycleStart:e}=this.normalize().getDecimalFormat(n);if(null===t||0===t){const t=n??e,i=this.toFixed(t),o=r(i).split(".");return[o[0],o[1]??"",""]}const i=e+t,o=this.toFixed(i).split(".");return[o[0],o[1].slice(0,e),o[1].slice(e)]}toRepeatingDigits(n){const t=this.toRepeatingParts(n);let e=t[0];return(t[1]||t[2])&&(e+=`.${t[1]}`),t[2]&&(e+=`(${t[2]})`),e}toExponential(n){if(!Number.isSafeInteger(n)||n<0)throw new Error("Invalid parameters");return this.toFixedNumber(n).toExponential(n)}toFraction(){const{numerator:n,denominator:t}=this.normalize();return`${n.toString()}/${t.toString()}`}toFixedNumber(n){const t=this.numerator*10n**BigInt(n);return new o(t/this.denominator,n)}toBase(n,t){if(!Number.isSafeInteger(n)||n<2||n>16)throw new Error("Invalid radix");if(void 0!==t&&(!Number.isSafeInteger(t)||t<0))throw new Error("Invalid parameter");if(10===n)return void 0===t?this.toRepeatingDigits(t):this.toFixed(t,!0);const e=this.normalize(),r=void 0===t?Number.MAX_SAFE_INTEGER:t+1;let i=e.intPart(),o=e.sub(i);const s=-1===e.sign();s&&(i=i.neg(),o=o.neg());const a=new Map;let u=[];for(;!o.isZero()&&u.length!==r;){const t=o.mul(n),e=t.normalize().toFraction(),r=a.get(e);if(void 0!==r){u=[...u.slice(0,r-1),"(",...u.slice(r-1),")"];break}const i=Math.abs(t.intPart().toNumber());u.push(i.toString(n)),o=t.fracPart(),a.set(e,u.length)}return u.length===r&&u.pop(),[s?"-":"",i.toString(n),u.length?".":"",...u].join("")}toString(n,t){return void 0===n||10===n?this.toRepeatingDigits(t):this.toBase(n,t)}valueOf(){throw new Error("Unsafe conversion to Number type! Use toNumber() instead.")}}function a(n){if(n instanceof o||n instanceof s)return n;if("bigint"==typeof n)return new o(n);if("number"==typeof n){if(!Number.isSafeInteger(n))throw new Error("Floating point values as numbers are unsafe. Please provide them as a string.");return new o(n)}if("string"==typeof n)return n.includes("/")||n.includes("(")?new s(n,1n):new o(n);throw new Error("Unsupported parameter type")}const u=(n,t)=>{if(void 0===n)throw new Error("First parameter cannot be undefined");const e=a(n);if(void 0===t)return e;const r=a(t);return new s(e,1n).div(new s(r,1n))};u.min=(...n)=>{if(0===n.length)throw new Error("Got empty array");let t=u(n[0]);for(let e=1;e<n.length;e++){const r=u(n[e]);r.lt(t)&&(t=r)}return t},u.max=(...n)=>{if(0===n.length)throw new Error("Got empty array");let t=u(n[0]);for(let e=1;e<n.length;e++){const r=u(n[e]);r.gt(t)&&(t=r)}return t};const d=(n,t)=>{let e=0n;for(let r=0;r<n.length;r++){const i=n.charAt(r),o=parseInt(i,t);if(Number.isNaN(o))throw new Error(`Invalid digit "${i}"`);e*=BigInt(t),e+=BigInt(o)}return e};u.fromBase=(n,t)=>{if("string"!=typeof n)throw new Error("First parameter must be string");if(!Number.isSafeInteger(t)||t<2||t>16)throw new Error("Invalid radix");if(10===t)return u(n);if(0===(n=n.trim()).length)throw new Error("Empty string is not allowed");const e=n.startsWith("-");e&&(n=n.slice(1));const r=n.match(/^([0-9a-f]*)(?:\.([0-9a-f]*)(?:\(([0-9a-f]+)\))?)?$/i);if(!r)throw new Error(`Cannot parse number "${n}"`);const i=r[1]??"",o=r[2]??"",a=r[3]??"";if(a.length>0){const n=d([i,o,a].join(""),t)-d([i,o].join(""),t),r=d((t-1).toString(t).repeat(a.length)+"0".repeat(o.length),t),u=new s(n,r).normalize();return e?u.neg():u}const m=d(i,t),h=d(o,t),c=new s(h,BigInt(t)**BigInt(o.length)),l=new s(m,1n).add(c).normalize();return e?l.neg():l};const m=(n,t,e)=>{if(!Number.isSafeInteger(n))throw new Error("Integer is expected for N");if(n<0)throw new Error("Negative N is not supported");if(0===n)throw new Error("N cannot be zero");if(1===n)return u(t).toFixed(e);const r=u(t);if(n%2==0&&-1===r.sign())throw new Error("Complex numbers are not supported");if(r.isZero())return new o(0n).toFixed(e);if(r.isOne())return new o(1n).toFixed(e);const i=new s(n-1,n),a=new s(r,n),d=((n,t)=>{const e=t<0;e&&(t=-t);let r=t**(1/n);return e&&(r=-r),r.toString()})(n,r.toNumber());let m=new o(d),h=m.trunc(e);for(;;){m=i.mul(m).add(a.mul(m.inv().pow(n-1)));const t=m.trunc(e);if(m.isZero()||h.eq(t))break;h=t}return m.toFixed(e)},h=(n,t)=>m(2,n,t);class c{constructor(n,t){this.cachedDigits=0,this.fn=n,this.max=t}get(n){if(n<=this.cachedDigits)return this.cache.trunc(n);const t=new o(this.fn(n)),e=Math.min(this.max,n);return this.cachedDigits!==e&&(this.cache=t.trunc(e),this.cachedDigits=e),t}}const l=(n,t)=>{let e=u(n);if(e.isOne())return new o(0).toFixed(t);if(e.lte(0n))throw new Error("Invalid parameter");let r=0;for(;e.sub(1n).abs().gt("0.1");)e=new o(h(e,t+10)),r++;const i=e.sub(1n).div(e.add(1n)),s=i.pow(2n).normalize();let a=i,d=1n,m=u(i);for(;;){let n=u(0);for(let e=0;e<4;e++){a=a.mul(s),d+=2n;const e=a.div(d);n=n.add(e).trunc(t+10)}if(n.isZero())break;m=m.add(n)}return m=m.mul(2n**BigInt(r+1)),m.toFixed(t)},g=new c((n=>l(2n,n)),200),f=new c((n=>l(10n,n)),200),w=new c((n=>{if(0===n)return"3";let t=1n,e=3n*10n**BigInt(n+20),r=e;for(;0n!==e;)e=e*t/(4n*(t+1n)),t+=2n,r+=e/t;return`3.${r.toString().slice(1,n+1)}`}),1e3),b=n=>0===n?"3":w.get(n).toFixed(n),p=(t,e)=>{const r=e+10,{x:i,quadrant:s}=((n,t)=>{const e=new o(b(t)),r=e.mul(2n);(n=n.mod(r)).gt(e)?n=n.sub(r):n.lt(e.neg())&&(n=n.add(r));const i=e.div(2n),s=n.div(i);let a=0;return s.gte(i)?(a=2,n=e.sub(n)):s.gte(0n)?a=1:s.gte(i.neg())?(a=4,n=n.neg()):(a=3,n=e.sub(n.neg())),{quadrant:a,x:n}})(u(t),r),a=i.round(n.RoundingMode.NEAREST_AWAY_FROM_ZERO,r).pow(2n).normalize();let d=a,m=2n,h=u(1n).sub(d.div(m).trunc(r)),c=3n;const l=u(1n).div(10n**BigInt(r));let g=1;for(;;){m*=c*(c+1n),c+=2n;const n=c*(c+1n);c+=2n,d=d.mul(a),m*=n;let i=d.mul(n);d=d.mul(a),i=i.sub(d);const o=i.div(m).trunc(r);if(g++,h=h.add(o),o.lt(l)){const n=h.trunc(e),i=o.add(l.mul(g)),s=h.add(i).trunc(e);if(n.eq(s))break;return u(p(t,r+50)).toFixed(e)}}return(1===s||4===s?h:h.neg()).round(n.RoundingMode.TO_ZERO,e+3).toFixed(e)},E=(n,t)=>{const e=new o(b(t+10)),r=u(n);return p(e.div(2n).sub(r),t)},I=(n,t)=>{let e=u(n);if(e.isZero())return"0";if(e.abs().isOne())return u(b(t)).div(4*e.sign()).toFixed(t);let r=0;for(;e.abs().gt("0.42");){const n=u(h(e.pow(2n).add(1n),t+10));e=e.div(n.add(1n)),r++}const i=e.pow(2).normalize(),o=i.pow(2).normalize();let s=3n,a=e.sub(e.mul(i).div(s)),d=e.mul(o);const m=u(1n).div(10n**BigInt(t+10));for(;;){s+=2n;const n=s+2n,e=d.mul(i.mul(-s).add(n)).div(s*n);if(s=n,d=d.mul(o),a=a.add(e).trunc(t+10),e.abs().lt(m))break}return a=a.mul(2n**BigInt(r)),a.toFixed(t)},v=(n,t)=>{const e=u(n);if(e.isZero())return"0";if(e.abs().isOne())return u(b(t)).mul(e.sign()).div(2n).toFixed(t);if(e.abs().eq("1/2"))return u(b(t)).mul(e.sign()).div(6n).toFixed(t);if(e.gt(1n)||e.lt(-1n))throw new Error("Out of range");const r=u(h(e.pow(2n).neg().add(1),t+10));return u(I(e.div(r.add(1n)),t+10)).mul(2).toFixed(t)};n.ExactNumber=u,n.PI=b,n.acos=(n,t)=>{const e=u(n);if(e.isZero())return u(b(t)).div(2n).toFixed(t);if(e.isOne())return"0";if(e.abs().isOne())return b(t);if(e.abs().eq("1/2")){const n=u(b(t)).div(3n);return-1===e.sign()?n.mul(2n).toFixed(t):n.toFixed(t)}if(e.gt(1n)||e.lt(-1n))throw new Error("Out of range");return u(b(t+10)).div(2n).sub(v(e,t+10)).toFixed(t)},n.asin=v,n.atan=I,n.cbrt=(n,t)=>m(3,n,t),n.cos=p,n.cosh=(n,t)=>{const e=u(n).pow(2n).normalize();let r=e,i=2n,o=r.div(i).add(1n).trunc(t+5),s=3n;const a=u(1n).div(10n**BigInt(t+5));for(;;){r=r.mul(e),i*=s*(s+1n),s+=2n;const n=r.div(i);if(o=o.add(n).trunc(t+5),n.abs().lt(a))break}return o.toFixed(t)},n.exp=(n,t)=>{const e=u(n);let r=e.add(1n),i=6n,o=4n;const a=e.pow(2n);let d=a;const m=new s(1n,10n**BigInt(t+5));for(;;){const n=d.mul(e.add(o-1n)).div(i);if(i*=o*(o+1n),o+=2n,d=d.mul(a),r=r.add(n).trunc(t+5),n.abs().lte(m))break}return r.toFixed(t)},n.log=l,n.log10=(n,t)=>new o(l(n,t+10)).div(f.get(t+10)).toFixed(t),n.log2=(n,t)=>new o(l(n,t+10)).div(g.get(t+10)).toFixed(t),n.logn=(n,t,e)=>{if(!Number.isSafeInteger(n)||n<2)throw new Error("Invalid parameter for N");const r=l(t,e+10),i=l(n,e+10);return new o(r).div(i).toFixed(e)},n.nthroot=m,n.pow=(n,t,e)=>{const r=new s(n,1n),i=new s(t,1n).getFractionParts(!1);return m(i.denominator.toNumber(),r.pow(i.numerator),e)},n.sin=E,n.sinh=(n,t)=>{const e=u(n),r=e.pow(2n).normalize();let i=e,o=1n,s=e.trunc(t+5),a=2n;const d=u(1n).div(10n**BigInt(t+5));for(;;){i=i.mul(r),o*=a*(a+1n),a+=2n;const n=i.div(o);if(s=s.add(n).trunc(t+5),n.abs().lt(d))break}return s.toFixed(t)},n.sqrt=h,n.tan=(n,t)=>{if(u(n).isZero())return"0";return u(E(n,t+10)).div(p(n,t+10)).toFixed(t)},Object.defineProperty(n,"__esModule",{value:!0})})); | ||
!function(n,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((n="undefined"!=typeof globalThis?globalThis:n||self).exactnumber={})}(this,(function(n){"use strict";var t,e;n.RoundingMode=void 0,(t=n.RoundingMode||(n.RoundingMode={})).NEAREST_TO_POSITIVE="NP",t.NEAREST_TO_NEGATIVE="NN",t.NEAREST_TO_EVEN="NE",t.NEAREST_TO_ZERO="NZ",t.NEAREST_AWAY_FROM_ZERO="NA",t.TO_POSITIVE="P",t.TO_NEGATIVE="N",t.TO_ZERO="Z",t.AWAY_FROM_ZERO="A",n.ModType=void 0,(e=n.ModType||(n.ModType={})).TRUNCATED="T",e.FLOORED="F",e.EUCLIDEAN="E";const r=n=>{let t=n.length;for(;t>0&&["0","."].includes(n.charAt(t-1));)t--;return t!==n.length?n.slice(0,t):n},i=(n,t,e)=>{let i=n.toString();if(0===t)return i;const o=i.startsWith("-");if(o&&(i=i.slice(1)),t>=i.length&&(i="0".repeat(t-i.length+1)+i),t>0){const n=i.slice(0,-t);let o=i.slice(-t);e&&(o=r(o)),i=o.length?`${n}.${o}`:n}return o?`-${i}`:i};class o{constructor(n,t=0){if(this.type="fixed","bigint"==typeof n)this.number=n,this.decimalPos=t;else{const t=this.parseConstructorParameter(n);this.number=t.number,this.decimalPos=t.decimalPos}}parseConstructorParameter(n){if(n instanceof o)return{number:n.number,decimalPos:n.decimalPos};if(n instanceof s){if(!n.isInteger())throw new Error("Cannot create FixedNumber from non-integer Fraction");return{number:n.trunc().number,decimalPos:0}}if("number"==typeof n){if(!Number.isSafeInteger(n))throw new Error("The specified number cannot be exactly represented as an integer. Please provide a string instead.");return{number:BigInt(n),decimalPos:0}}if("string"==typeof n){if(0===(n=n.trim()).length)throw new Error("Empty string is not allowed");const t=n.match(/^(-?[0-9]*)(?:\.([0-9]*))?(?:[eE]([+-]?[0-9]+))?$/);if(!t)throw new Error(`Cannot parse number "${n}"`);let e=0,r=t[1]??"0";if(void 0!==t[2]&&(r+=t[2],e+=t[2].length),void 0!==t[3]){const n=Number(t[3]);n>0?r+="0".repeat(n):e-=n}return{number:BigInt(r),decimalPos:e}}throw new Error("Unsupported parameter!")}scaleNumber(n,t){const e=Math.max(this.decimalPos,t);return{a:e===this.decimalPos?this.number:this.number*10n**BigInt(e-this.decimalPos),b:e===t?n:n*10n**BigInt(e-t),decimalPos:e}}add(n){const t=a(n);if(t instanceof s)return t.add(this);const e=t,{a:r,b:i,decimalPos:u}=this.scaleNumber(e.number,e.decimalPos);return new o(r+i,u)}sub(n){const t=a(n);return this.add(t.neg())}mul(n){const t=a(n);if(t instanceof s)return t.mul(this);const e=t;return new o(this.number*e.number,this.decimalPos+e.decimalPos)}pow(n){const t=a(n).toNumber();if(!Number.isSafeInteger(t)||t<0)throw new Error("Unsupported parameter");return new o(this.number**BigInt(t),this.decimalPos*t)}div(n){return this.convertToFraction().div(n)}divToInt(n){const t=a(n);if(t instanceof s)return this.convertToFraction().divToInt(t);const e=t,{a:r,b:i}=this.scaleNumber(e.number,e.decimalPos);return new o(r/i)}mod(t,e=n.ModType.TRUNCATED){const r=a(t);if(r instanceof s)return this.convertToFraction().mod(r);const i=r,{a:u,b:d,decimalPos:m}=this.scaleNumber(i.number,i.decimalPos),c=u%d,h=new o(c,m);if(e===n.ModType.TRUNCATED)return h;if(e===n.ModType.FLOORED)return Number(u<0)^Number(d<0)?h.add(d):h;if(e===n.ModType.EUCLIDEAN)return c<0?h.add(d<0?-d:d):h;throw new Error("Invalid ModType")}abs(){return new o(this.number<0?-this.number:this.number,this.decimalPos)}neg(){return this.mul(-1n)}inv(){return this.convertToFraction().inv()}floor(t){return 0===this.decimalPos?this:this.round(t,n.RoundingMode.TO_NEGATIVE)}ceil(t){return 0===this.decimalPos?this:this.round(t,n.RoundingMode.TO_POSITIVE)}trunc(t){return 0===this.decimalPos?this:this.round(t,n.RoundingMode.TO_ZERO)}round(t,e){if(t=void 0===t?0:t,!Number.isSafeInteger(t)||t<0)throw new Error("Invalid value for decimals");const r=this.decimalPos-t,i=10n**BigInt(Math.abs(r)),s=r>0?this.number/i:this.number*i;if(e===n.RoundingMode.TO_ZERO)return new o(s,t);const a=r>0?Math.abs(r):t,u=r>0?this.number%i:s%10n**BigInt(t);if(0n===u)return new o(s,t);if(e===n.RoundingMode.AWAY_FROM_ZERO){const n=this.number<0n?s-1n:s+1n;return new o(n,t)}if(e===n.RoundingMode.TO_POSITIVE){const n=this.number<0n?s:s+1n;return new o(n,t)}if(e===n.RoundingMode.TO_NEGATIVE){const n=this.number>=0n?s:s-1n;return new o(n,t)}if(![void 0,n.RoundingMode.NEAREST_TO_ZERO,n.RoundingMode.NEAREST_AWAY_FROM_ZERO,n.RoundingMode.NEAREST_TO_POSITIVE,n.RoundingMode.NEAREST_TO_NEGATIVE,n.RoundingMode.NEAREST_TO_EVEN].includes(e))throw new Error("Invalid rounding mode. Use the predefined values from the RoundingMode enum.");let d=(u<0n?-u:u).toString();d.length<a&&(d="0".repeat(a-d.length)+d);let m="5"===d[0];if(m)for(let n=1;n<d.length;n++)if("0"!==d[n]){m=!1;break}if(m){if(e===n.RoundingMode.NEAREST_TO_ZERO)return new o(s,t);if(e===n.RoundingMode.NEAREST_AWAY_FROM_ZERO){const n=this.number<0n?s-1n:s+1n;return new o(n,t)}if(void 0===e||e===n.RoundingMode.NEAREST_TO_POSITIVE){const n=this.number<0n?s:s+1n;return new o(n,t)}if(e===n.RoundingMode.NEAREST_TO_NEGATIVE){const n=this.number>=0n?s:s-1n;return new o(n,t)}if(e===n.RoundingMode.NEAREST_TO_EVEN){if(s%2n===0n)return new o(s,t);return new o(s<0n?s-1n:s+1n,t)}}if(Number(d[0])<5)return new o(s,t);const c=this.number<0?s-1n:s+1n;return new o(c,t)}_incExponent(n){if(0===n)return this;let t=this.number,e=this.decimalPos;if(n<0)e-=n;else{const r=Math.min(n,this.decimalPos);e-=r;const i=n-r;i>0&&(t*=10n**BigInt(i))}return new o(t,e)}roundToDigits(n,t){if(!Number.isSafeInteger(n)||n<1)throw new Error("Invalid value for digits");const e=this.number<0n,r=e?-this.number:this.number,i=r.toString();let s=new o(r,i.length).round(n,t);const a=i.length-this.decimalPos;return s=s._incExponent(a),e?s.neg():s}intPart(){return this.trunc()}fracPart(){return this.sub(this.trunc())}sign(){return this.number<0n?-1:1}bitwiseAnd(n){if(n=u(n),!this.isInteger()||-1===this.sign()||!n.isInteger()||-1===n.sign())throw new Error("Only positive integers are supported");n instanceof s&&(n=n.trunc());const t=2n**24n;let e=this.normalize().number,r=n.trunc().normalize().number,i=0n,a=1n;for(;e>0&&r>0;){const n=BigInt.asUintN(24,e),o=BigInt.asUintN(24,r);i+=BigInt(Number(n)&Number(o))*a,a*=t,e/=t,r/=t}return new o(i)}bitwiseOr(n){if(n=u(n),!this.isInteger()||-1===this.sign()||!n.isInteger()||-1===n.sign())throw new Error("Only positive integers are supported");n instanceof s&&(n=n.trunc());const t=2n**24n;let e=this.normalize().number,r=n.trunc().normalize().number,i=0n,a=1n;for(;e>0||r>0;){const n=BigInt.asUintN(24,e),o=BigInt.asUintN(24,r);i+=BigInt(Number(n)|Number(o))*a,a*=t,e/=t,r/=t}return new o(i)}bitwiseXor(n){if(n=u(n),!this.isInteger()||-1===this.sign()||!n.isInteger()||-1===n.sign())throw new Error("Only positive integers are supported");n instanceof s&&(n=n.trunc());const t=2n**24n;let e=this.normalize().number,r=n.trunc().normalize().number,i=0n,a=1n;for(;e>0||r>0;){const n=BigInt.asUintN(24,e),o=BigInt.asUintN(24,r);i+=BigInt(Number(n)^Number(o))*a,a*=t,e/=t,r/=t}return new o(i)}shiftLeft(n){if(!this.isInteger()||-1===this.sign())throw new Error("Only positive integers are supported");if(!Number.isSafeInteger(n)||n<0)throw new Error("Invalid value for bitCount");const t=2n**BigInt(n);return this.mul(t)}shiftRight(n){if(!this.isInteger()||-1===this.sign())throw new Error("Only positive integers are supported");if(!Number.isSafeInteger(n)||n<0)throw new Error("Invalid value for bitCount");const t=2n**BigInt(n);return new o(this.normalize().number/t)}cmp(n){const t=a(n);if(t instanceof s)return-t.cmp(this);const e=t,{a:r,b:i}=this.scaleNumber(e.number,e.decimalPos);return r===i?0:r>i?1:-1}eq(n){return 0===this.cmp(n)}lt(n){return-1===this.cmp(n)}lte(n){return this.cmp(n)<=0}gt(n){return 1===this.cmp(n)}gte(n){return this.cmp(n)>=0}clamp(n,t){const e=u(n),r=u(t);if(e.gt(r))throw new Error("Min parameter has to be smaller than max");return this.lt(e)?e:this.gt(r)?r:this}isZero(){return 0n===this.number}isOne(){if(0===this.decimalPos)return 1n===this.number;const n=10n**BigInt(this.decimalPos),t=this.number/n;return 1n===t&&t*n===this.number}isInteger(){return 0===this.decimalPos||this.number%10n**BigInt(this.decimalPos)===0n}serialize(){return[this.number,this.decimalPos]}getFractionParts(n=!0){return this.convertToFraction().getFractionParts(n)}normalize(){if(0===this.decimalPos)return this;let n=this.decimalPos,t=this.number;for(;n>0&&t%10n===0n;)n--,t/=10n;return new o(t,n)}convertToFraction(){if(0===this.decimalPos)return new s(this.number,1n);const n=10n**BigInt(this.decimalPos);return new s(this.number,n)}toNumber(){return Number(this.toString())}toFixed(t,e=n.RoundingMode.TO_ZERO){if(!Number.isSafeInteger(t)||t<0)throw new Error("Invalid parameter");const r=this.round(t,e);return i(r.number,t,!1)}toExponential(t,e=n.RoundingMode.TO_ZERO){if(!Number.isSafeInteger(t)||t<0)throw new Error("Invalid parameter");const r=this.roundToDigits(t+1,e).normalize(),i=-1===r.sign(),o=r.abs(),s=o.number.toString(),a=s.length<=t?`${s}${"0".repeat(t-s.length+1)}`:s.slice(0,t+1),u=a.length>1?`${a.slice(0,1)}.${a.slice(1)}`:a,d=o.decimalPos,m=s.length-1-d;return`${i?"-":""}${u}e${m>=0?"+":""}${m}`}toBase(n,t){if(!Number.isSafeInteger(n)||n<2||n>16)throw new Error("Invalid radix");if(void 0!==t&&(!Number.isSafeInteger(t)||t<0))throw new Error("Invalid parameter");const e=this.normalize();if(0===e.decimalPos)return e.number.toString(n);const r=void 0===t?Number.MAX_SAFE_INTEGER:t;let i=e.intPart(),o=e.sub(i);const s=-1===e.sign();s&&(i=i.neg(),o=o.neg());const a=new Map;let u=[];for(;!o.isZero();){const t=o.mul(n),e=t.toString(),i=a.get(e);if(void 0!==i){u=[...u.slice(0,i-1),"(",...u.slice(i-1),")"];break}if(u.length===r)break;const s=Math.abs(t.intPart().toNumber());u.push(s.toString(n)),o=t.fracPart(),a.set(e,u.length)}return[s?"-":"",i.number.toString(n),u.length?".":"",...u].join("")}toFraction(){return this.convertToFraction().toFraction()}toString(n,t){if(void 0===n||10===n){const n=void 0!==t?this.trunc(t):this;return i(n.number,n.decimalPos,!0)}return this.toBase(n,t)}toPrecision(t,e=n.RoundingMode.TO_ZERO){if(!Number.isSafeInteger(t)||t<1)throw new Error("Invalid parameter");const r=this.roundToDigits(t,e);return i(r.number,r.decimalPos,!1)}valueOf(){throw new Error("Unsafe conversion to Number type! Use toNumber() instead.")}}class s{constructor(n,t){if(this.type="fraction","bigint"==typeof n&&"bigint"==typeof t)this.numerator=n,this.denominator=t;else{const e=this.parseParameter(n),r=this.parseParameter(t),i=e.div(r),s=i instanceof o?i.convertToFraction():i;this.numerator=s.numerator,this.denominator=s.denominator}if(0n===this.denominator)throw new Error("Division by zero")}parseRepeatingDecimal(n){if(!n.includes("("))return new o(n).convertToFraction();const t=(n=n.trim()).match(/^(-?[0-9]*)\.([0-9]+)?\(([0-9]+)\)(?:[eE]([+-]?[0-9]+))?$/);if(!t)throw new Error(`Cannot parse string "${n}"`);const e="-"===t[1]?"-0":t[1],r=t[2]??"",i=t[3],a=t[4],u=BigInt(e+r+i)-BigInt(e+r),d=BigInt("9".repeat(i.length)+"0".repeat(r.length)),m=new s(u,d);if(void 0!==a){const n=a.startsWith("-"),t=10n**BigInt(n?a.slice(1):a);return n?m.div(t).normalize():m.mul(t).normalize()}return m.normalize()}parseParameter(n){if(n instanceof s)return n;if(n instanceof o)return n.convertToFraction();if("number"==typeof n){if(!Number.isSafeInteger(n))throw new Error("Floating point values as numbers are unsafe. Please provide them as a string.");return new s(BigInt(n),1n)}if("bigint"==typeof n)return new s(n,1n);if("string"==typeof n){const t=n.split("/");if(t.length>2)throw new Error(`Cannot parse string '${n}'`);const e=this.parseRepeatingDecimal(t[0]),r=t[1]?this.parseRepeatingDecimal(t[1]):new s(1n,1n);return e.div(r).convertToFraction()}throw new Error("Unsupported parameter!")}add(n){const{numerator:t,denominator:e}=this.parseParameter(n);return this.denominator===e?new s(this.numerator+t,this.denominator):new s(this.numerator*e+t*this.denominator,e*this.denominator)}sub(n){const{numerator:t,denominator:e}=this.parseParameter(n);return this.add(new s(-t,e))}mul(n){const{numerator:t,denominator:e}=this.parseParameter(n);return new s(this.numerator*t,this.denominator*e)}div(n){const{numerator:t,denominator:e}=this.parseParameter(n);return this.mul(new s(e,t))}divToInt(n){return this.div(n).trunc()}mod(t,e=n.ModType.TRUNCATED){const r=this.parseParameter(t),i=r.denominator*this.numerator%(r.numerator*this.denominator),o=this.denominator*r.denominator,a=new s(i,o);if(e===n.ModType.TRUNCATED)return a;if(e===n.ModType.FLOORED)return Number(-1===this.sign())^Number(-1===r.sign())?a.add(r):a;if(e===n.ModType.EUCLIDEAN)return a.sign()<0?a.add(r.sign()<0?r.neg():r):a;throw new Error("Invalid ModType")}pow(n){const t=this.parseParameter(n);if(!t.isInteger()||-1===t.sign())throw new Error("Unsupported parameter");const e=t.numerator/t.denominator;return new s(this.numerator**e,this.denominator**e)}inv(){return new s(this.denominator,this.numerator)}floor(t){return 1n===this.denominator?new o(this.numerator):this.round(t,n.RoundingMode.TO_NEGATIVE)}ceil(t){return 1n===this.denominator?new o(this.numerator):this.round(t,n.RoundingMode.TO_POSITIVE)}trunc(t){return 1n===this.denominator?new o(this.numerator):this.round(t,n.RoundingMode.TO_ZERO)}round(n,t){if(n=void 0===n?0:n,!Number.isSafeInteger(n)||n<0)throw new Error("Invalid value for decimals");const e=this.toFixedNumber(n+1);if(this.sub(e).isZero())return e.round(n,t);return new o(`${e.toFixed(n+1)}1`).round(n,t)}roundToDigits(n,t){if(!Number.isSafeInteger(n)||n<1)throw new Error("Invalid value for digits");if(this.isZero())return new o(0n);let e=this.abs(),r=0;for(;e.gte(1n);)e=e.div(10n),r++;const i=new s(1n,10n);for(;e.lt(i);)e=e.mul(10n),r--;let a=e.round(n,t);return a=a._incExponent(r),-1===this.sign()?a.neg():a}gcd(n,t){let e=n<0?-n:n,r=t<0?-t:t;if(r>e){const n=e;e=r,r=n}for(;;){if(0n===r)return e;if(e%=r,0n===e)return r;r%=e}}lcm(n,t){return n*t/this.gcd(n,t)}normalize(){let{numerator:n,denominator:t}=this;const e=this.gcd(n,t);return e>1n&&(n/=e,t/=e),t<0n&&(n=-n,t=-t),new s(n,t)}getFractionParts(n=!0){const t=n?this.normalize():this;return{numerator:new o(t.numerator),denominator:new o(t.denominator)}}sign(){return(this.numerator<0n?-1:1)*(this.denominator<0n?-1:1)}abs(){return new s(this.numerator<0n?-this.numerator:this.numerator,this.denominator<0n?-this.denominator:this.denominator)}neg(){return this.mul(-1n)}intPart(){return this.trunc()}fracPart(){return this.sub(this.trunc())}cmp(n){const t=this.parseParameter(n),e=this.denominator===t.denominator,r=e?this.numerator:this.numerator*t.denominator,i=e?t.numerator:t.numerator*this.denominator;return r===i?0:r>i?1:-1}eq(n){return 0===this.cmp(n)}lt(n){return-1===this.cmp(n)}lte(n){return this.cmp(n)<=0}gt(n){return 1===this.cmp(n)}gte(n){return this.cmp(n)>=0}clamp(n,t){const e=u(n),r=u(t);if(e.gt(r))throw new Error("Min parameter has to be smaller than max");return this.lt(e)?e:this.gt(r)?r:this}isZero(){return 0n===this.numerator}isOne(){return this.numerator===this.denominator}isInteger(){return this.numerator%this.denominator===0n}serialize(){return[this.numerator,this.denominator]}toNumber(){return Number(this.numerator)/Number(this.denominator)}convertToFraction(){return this}getNumberForBitwiseOp(){if(!this.isInteger()||-1===this.sign())throw new Error("Only positive integers are supported");return this.intPart()}bitwiseAnd(n){return this.getNumberForBitwiseOp().bitwiseAnd(n)}bitwiseOr(n){return this.getNumberForBitwiseOp().bitwiseOr(n)}bitwiseXor(n){return this.getNumberForBitwiseOp().bitwiseXor(n)}shiftLeft(n){return this.getNumberForBitwiseOp().shiftLeft(n)}shiftRight(n){return this.getNumberForBitwiseOp().shiftRight(n)}getDecimalFormat(n){n=void 0===n?Number.MAX_SAFE_INTEGER:n;let t=this.denominator<0?-this.denominator:this.denominator,e=0;for(;t%2n===0n;)t/=2n,e++;let r=0;for(;t%5n===0n;)t/=5n,r++;const i=Math.max(e,r);if(1n===t)return{cycleLen:0,cycleStart:i};const o=Math.max(1,n-i);let s=10n%t,a=1;for(;1n!==s;){if(a===o)return{cycleLen:null,cycleStart:i};s=10n*s%t,a++}return{cycleLen:a,cycleStart:i}}toFixed(t,e=n.RoundingMode.TO_ZERO){if(!Number.isSafeInteger(t)||t<0)throw new Error("Invalid parameter");const[r,o]=this.round(t,e).serialize();return i(r,o,!1)}toRepeatingParts(n){if(this.isZero())return["0","",""];const{cycleLen:t,cycleStart:e}=this.normalize().getDecimalFormat(n);if(null===t||0===t){const t=n??e,i=this.toFixed(t),o=r(i).split(".");return[o[0],o[1]??"",""]}const i=e+t,o=this.toFixed(i).split(".");return[o[0],o[1].slice(0,e),o[1].slice(e)]}toRepeatingDigits(n){const t=this.toRepeatingParts(n);let e=t[0];return(t[1]||t[2])&&(e+=`.${t[1]}`),t[2]&&(e+=`(${t[2]})`),e}toExponential(t,e=n.RoundingMode.TO_ZERO){if(!Number.isSafeInteger(t)||t<0)throw new Error("Invalid parameters");return this.toFixedNumber(t).toExponential(t,e)}toFraction(){const{numerator:n,denominator:t}=this.normalize();return`${n.toString()}/${t.toString()}`}toFixedNumber(n){const t=this.numerator*10n**BigInt(n);return new o(t/this.denominator,n)}toBase(n,t){if(!Number.isSafeInteger(n)||n<2||n>16)throw new Error("Invalid radix");if(void 0!==t&&(!Number.isSafeInteger(t)||t<0))throw new Error("Invalid parameter");if(10===n)return void 0===t?this.toRepeatingDigits(t):r(this.toFixed(t));const e=this.normalize(),i=void 0===t?Number.MAX_SAFE_INTEGER:t+1;let o=e.intPart(),s=e.sub(o);const a=-1===e.sign();a&&(o=o.neg(),s=s.neg());const u=new Map;let d=[];for(;!s.isZero()&&d.length!==i;){const t=s.mul(n),e=t.normalize().toFraction(),r=u.get(e);if(void 0!==r){d=[...d.slice(0,r-1),"(",...d.slice(r-1),")"];break}const i=Math.abs(t.intPart().toNumber());d.push(i.toString(n)),s=t.fracPart(),u.set(e,d.length)}return d.length===i&&d.pop(),[a?"-":"",o.toString(n),d.length?".":"",...d].join("")}toString(n,t){return void 0===n||10===n?this.toRepeatingDigits(t):this.toBase(n,t)}toPrecision(t,e=n.RoundingMode.TO_ZERO){if(!Number.isSafeInteger(t)||t<1)throw new Error("Invalid parameter");const[r,o]=this.roundToDigits(t,e).serialize();return i(r,o,!1)}valueOf(){throw new Error("Unsafe conversion to Number type! Use toNumber() instead.")}}function a(n){if(n instanceof o||n instanceof s)return n;if("bigint"==typeof n)return new o(n);if("number"==typeof n){if(!Number.isSafeInteger(n))throw new Error("Floating point values as numbers are unsafe. Please provide them as a string.");return new o(n)}if("string"==typeof n)return n.includes("/")||n.includes("(")?new s(n,1n):new o(n);throw new Error("Unsupported parameter type")}const u=(n,t)=>{if(void 0===n)throw new Error("First parameter cannot be undefined");const e=a(n);if(void 0===t)return e;const r=a(t);return new s(e,1n).div(new s(r,1n))};u.min=(...n)=>{if(0===n.length)throw new Error("Got empty array");let t=u(n[0]);for(let e=1;e<n.length;e++){const r=u(n[e]);r.lt(t)&&(t=r)}return t},u.max=(...n)=>{if(0===n.length)throw new Error("Got empty array");let t=u(n[0]);for(let e=1;e<n.length;e++){const r=u(n[e]);r.gt(t)&&(t=r)}return t};const d=(n,t)=>{let e=0n;for(let r=0;r<n.length;r++){const i=n.charAt(r),o=parseInt(i,t);if(Number.isNaN(o))throw new Error(`Invalid digit "${i}"`);e*=BigInt(t),e+=BigInt(o)}return e};u.fromBase=(n,t)=>{if("string"!=typeof n)throw new Error("First parameter must be string");if(!Number.isSafeInteger(t)||t<2||t>16)throw new Error("Invalid radix");if(10===t)return u(n);if(0===(n=n.trim()).length)throw new Error("Empty string is not allowed");const e=n.startsWith("-");e&&(n=n.slice(1));const r=n.match(/^([0-9a-f]*)(?:\.([0-9a-f]*)(?:\(([0-9a-f]+)\))?)?$/i);if(!r)throw new Error(`Cannot parse number "${n}"`);const i=r[1]??"",o=r[2]??"",a=r[3]??"";if(a.length>0){const n=d([i,o,a].join(""),t)-d([i,o].join(""),t),r=d((t-1).toString(t).repeat(a.length)+"0".repeat(o.length),t),u=new s(n,r).normalize();return e?u.neg():u}const m=d(i,t),c=d(o,t),h=new s(c,BigInt(t)**BigInt(o.length)),l=new s(m,1n).add(h).normalize();return e?l.neg():l};const m=(n,t,e)=>{if(!Number.isSafeInteger(n))throw new Error("Integer is expected for N");if(n<0)throw new Error("Negative N is not supported");if(0===n)throw new Error("N cannot be zero");if(1===n)return u(t).toFixed(e);const r=u(t);if(n%2==0&&-1===r.sign())throw new Error("Complex numbers are not supported");if(r.isZero())return new o(0n).toFixed(e);if(r.isOne())return new o(1n).toFixed(e);const i=new s(n-1,n),a=new s(r,n),d=((n,t)=>{const e=t<0;e&&(t=-t);let r=t**(1/n);return e&&(r=-r),r.toString()})(n,r.toNumber());let m=new o(d),c=m.trunc(e);for(;;){m=i.mul(m).add(a.mul(m.inv().pow(n-1)));const t=m.trunc(e);if(m.isZero()||c.eq(t))break;c=t}return m.toFixed(e)},c=(n,t)=>m(2,n,t);class h{constructor(n,t){this.cachedDigits=0,this.fn=n,this.max=t}get(n){if(n<=this.cachedDigits)return this.cache.trunc(n);const t=new o(this.fn(n)),e=Math.min(this.max,n);return this.cachedDigits!==e&&(this.cache=t.trunc(e),this.cachedDigits=e),t}}const l=(n,t)=>{let e=u(n);if(e.isOne())return new o(0).toFixed(t);if(e.lte(0n))throw new Error("Invalid parameter");let r=0;for(;e.sub(1n).abs().gt("0.1");)e=new o(c(e,t+10)),r++;const i=e.sub(1n).div(e.add(1n)),s=i.pow(2n).normalize();let a=i,d=1n,m=u(i);for(;;){let n=u(0);for(let e=0;e<4;e++){a=a.mul(s),d+=2n;const e=a.div(d);n=n.add(e).trunc(t+10)}if(n.isZero())break;m=m.add(n)}return m=m.mul(2n**BigInt(r+1)),m.toFixed(t)},g=new h((n=>l(2n,n)),200),f=new h((n=>l(10n,n)),200),w=new h((n=>{if(0===n)return"3";let t=1n,e=3n*10n**BigInt(n+20),r=e;for(;0n!==e;)e=e*t/(4n*(t+1n)),t+=2n,r+=e/t;return`3.${r.toString().slice(1,n+1)}`}),1e3),b=n=>0===n?"3":w.get(n).toFixed(n),p=(t,e)=>{const r=e+10,{x:i,quadrant:s}=((n,t)=>{const e=new o(b(t)),r=e.mul(2n);(n=n.mod(r)).gt(e)?n=n.sub(r):n.lt(e.neg())&&(n=n.add(r));const i=e.div(2n),s=n.div(i);let a=0;return s.gte(i)?(a=2,n=e.sub(n)):s.gte(0n)?a=1:s.gte(i.neg())?(a=4,n=n.neg()):(a=3,n=e.sub(n.neg())),{quadrant:a,x:n}})(u(t),r),a=i.round(r,n.RoundingMode.NEAREST_AWAY_FROM_ZERO).pow(2n).normalize();let d=a,m=2n,c=u(1n).sub(d.div(m).trunc(r)),h=3n;const l=u(1n).div(10n**BigInt(r));let g=1;for(;;){m*=h*(h+1n),h+=2n;const n=h*(h+1n);h+=2n,d=d.mul(a),m*=n;let i=d.mul(n);d=d.mul(a),i=i.sub(d);const o=i.div(m).trunc(r);if(g++,c=c.add(o),o.lt(l)){const n=c.trunc(e),i=o.add(l.mul(g)),s=c.add(i).trunc(e);if(n.eq(s))break;return u(p(t,r+50)).toFixed(e)}}return(1===s||4===s?c:c.neg()).round(e+3,n.RoundingMode.TO_ZERO).toFixed(e)},E=(n,t)=>{const e=new o(b(t+10)),r=u(n);return p(e.div(2n).sub(r),t)},I=(n,t)=>{let e=u(n);if(e.isZero())return"0";if(e.abs().isOne())return u(b(t)).div(4*e.sign()).toFixed(t);let r=0;for(;e.abs().gt("0.42");){const n=u(c(e.pow(2n).add(1n),t+10));e=e.div(n.add(1n)),r++}const i=e.pow(2).normalize(),o=i.pow(2).normalize();let s=3n,a=e.sub(e.mul(i).div(s)),d=e.mul(o);const m=u(1n).div(10n**BigInt(t+10));for(;;){s+=2n;const n=s+2n,e=d.mul(i.mul(-s).add(n)).div(s*n);if(s=n,d=d.mul(o),a=a.add(e).trunc(t+10),e.abs().lt(m))break}return a=a.mul(2n**BigInt(r)),a.toFixed(t)},v=(n,t)=>{const e=u(n);if(e.isZero())return"0";if(e.abs().isOne())return u(b(t)).mul(e.sign()).div(2n).toFixed(t);if(e.abs().eq("1/2"))return u(b(t)).mul(e.sign()).div(6n).toFixed(t);if(e.gt(1n)||e.lt(-1n))throw new Error("Out of range");const r=u(c(e.pow(2n).neg().add(1),t+10));return u(I(e.div(r.add(1n)),t+10)).mul(2).toFixed(t)};n.ExactNumber=u,n.PI=b,n.acos=(n,t)=>{const e=u(n);if(e.isZero())return u(b(t)).div(2n).toFixed(t);if(e.isOne())return"0";if(e.abs().isOne())return b(t);if(e.abs().eq("1/2")){const n=u(b(t)).div(3n);return-1===e.sign()?n.mul(2n).toFixed(t):n.toFixed(t)}if(e.gt(1n)||e.lt(-1n))throw new Error("Out of range");return u(b(t+10)).div(2n).sub(v(e,t+10)).toFixed(t)},n.asin=v,n.atan=I,n.cbrt=(n,t)=>m(3,n,t),n.cos=p,n.cosh=(n,t)=>{const e=u(n).pow(2n).normalize();let r=e,i=2n,o=r.div(i).add(1n).trunc(t+5),s=3n;const a=u(1n).div(10n**BigInt(t+5));for(;;){r=r.mul(e),i*=s*(s+1n),s+=2n;const n=r.div(i);if(o=o.add(n).trunc(t+5),n.abs().lt(a))break}return o.toFixed(t)},n.exp=(n,t)=>{const e=u(n);let r=e.add(1n),i=6n,o=4n;const a=e.pow(2n);let d=a;const m=new s(1n,10n**BigInt(t+5));for(;;){const n=d.mul(e.add(o-1n)).div(i);if(i*=o*(o+1n),o+=2n,d=d.mul(a),r=r.add(n).trunc(t+5),n.abs().lte(m))break}return r.toFixed(t)},n.log=l,n.log10=(n,t)=>new o(l(n,t+10)).div(f.get(t+10)).toFixed(t),n.log2=(n,t)=>new o(l(n,t+10)).div(g.get(t+10)).toFixed(t),n.logn=(n,t,e)=>{if(!Number.isSafeInteger(n)||n<2)throw new Error("Invalid parameter for N");const r=l(t,e+10),i=l(n,e+10);return new o(r).div(i).toFixed(e)},n.nthroot=m,n.pow=(n,t,e)=>{const r=new s(n,1n),i=new s(t,1n).getFractionParts(!1);return m(i.denominator.toNumber(),r.pow(i.numerator),e)},n.sin=E,n.sinh=(n,t)=>{const e=u(n),r=e.pow(2n).normalize();let i=e,o=1n,s=e.trunc(t+5),a=2n;const d=u(1n).div(10n**BigInt(t+5));for(;;){i=i.mul(r),o*=a*(a+1n),a+=2n;const n=i.div(o);if(s=s.add(n).trunc(t+5),n.abs().lt(d))break}return s.toFixed(t)},n.sqrt=c,n.tan=(n,t)=>{if(u(n).isZero())return"0";return u(E(n,t+10)).div(p(n,t+10)).toFixed(t)},n.trimTrailingZeros=r,Object.defineProperty(n,"__esModule",{value:!0})})); |
@@ -17,4 +17,4 @@ import { Fraction } from './Fraction'; | ||
mod(x: number | bigint | string | ExactNumberType, type?: ModType): ExactNumberType; | ||
abs(): ExactNumberType; | ||
neg(): ExactNumberType; | ||
abs(): FixedNumber; | ||
neg(): FixedNumber; | ||
inv(): ExactNumberType; | ||
@@ -24,4 +24,5 @@ floor(decimals?: number): FixedNumber; | ||
trunc(decimals?: number): FixedNumber; | ||
round(roundingMode?: RoundingMode, decimals?: number): FixedNumber; | ||
roundToDigits(roundingMode: RoundingMode, digits: number): ExactNumberType | FixedNumber; | ||
round(decimals?: number, roundingMode?: RoundingMode): FixedNumber; | ||
_incExponent(amount: number): FixedNumber; | ||
roundToDigits(digits: number, roundingMode: RoundingMode): FixedNumber; | ||
intPart(): ExactNumberType; | ||
@@ -45,3 +46,3 @@ fracPart(): ExactNumberType; | ||
isInteger(): boolean; | ||
serialize(): (number | bigint)[]; | ||
serialize(): [bigint, number]; | ||
getFractionParts(normalize?: boolean): { | ||
@@ -54,8 +55,9 @@ numerator: FixedNumber; | ||
toNumber(): number; | ||
toFixed(digits: number, trimTrailingZeros?: boolean): string; | ||
toExponential(digits: number): string; | ||
toFixed(decimals: number, roundingMode?: RoundingMode): string; | ||
toExponential(digits: number, roundingMode?: RoundingMode): string; | ||
private toBase; | ||
toFraction(): string; | ||
toString(radix?: number, maxDigits?: number): string; | ||
toPrecision(digits: number, roundingMode?: RoundingMode): string; | ||
valueOf(): number; | ||
} |
@@ -21,4 +21,4 @@ import { ExactNumberType, ModType, RoundingMode } from './types'; | ||
trunc(decimals?: number): FixedNumber; | ||
round(roundingMode?: RoundingMode, decimals?: number): FixedNumber; | ||
roundToDigits(roundingMode: RoundingMode, digits: number): ExactNumberType | this; | ||
round(decimals?: number, roundingMode?: RoundingMode): FixedNumber; | ||
roundToDigits(digits: number, roundingMode: RoundingMode): FixedNumber; | ||
private gcd; | ||
@@ -34,3 +34,3 @@ private lcm; | ||
neg(): ExactNumberType; | ||
intPart(): ExactNumberType; | ||
intPart(): FixedNumber; | ||
fracPart(): ExactNumberType; | ||
@@ -47,3 +47,3 @@ cmp(x: number | bigint | string | ExactNumberType): -1 | 0 | 1; | ||
isInteger(): boolean; | ||
serialize(): bigint[]; | ||
serialize(): [bigint, bigint]; | ||
toNumber(): number; | ||
@@ -58,6 +58,6 @@ convertToFraction(): this; | ||
private getDecimalFormat; | ||
toFixed(digits: number, trimTrailingZeros?: boolean): string; | ||
toFixed(decimals: number, roundingMode?: RoundingMode): string; | ||
private toRepeatingParts; | ||
toRepeatingDigits(maxDigits: number | undefined): string; | ||
toExponential(digits: number): string; | ||
toExponential(digits: number, roundingMode?: RoundingMode): string; | ||
toFraction(): string; | ||
@@ -67,3 +67,4 @@ private toFixedNumber; | ||
toString(radix?: number, maxDigits?: number): string; | ||
toPrecision(digits: number, roundingMode?: RoundingMode): string; | ||
valueOf(): number; | ||
} |
export { ExactNumber } from './ExactNumber'; | ||
export { RoundingMode, ModType, ExactNumberType, ExactNumberParameter } from './types'; | ||
export { trimTrailingZeros } from './util'; | ||
export * from './approx'; |
@@ -67,6 +67,6 @@ import { Fraction } from './Fraction'; | ||
trunc(decimals?: number): ExactNumberType; | ||
/** Rounds current number to the specified amount of decimals. */ | ||
round(roundingMode?: RoundingMode, decimals?: number): ExactNumberType; | ||
/** Rounds current number to the specified amount of decimals. RoundingMode.NEAREST_TO_POSITIVE is the default */ | ||
round(decimals?: number, roundingMode?: RoundingMode): ExactNumberType; | ||
/** Rounds current number to the specified amount of significant digits. */ | ||
roundToDigits(roundingMode: RoundingMode, digits: number): ExactNumberType; | ||
roundToDigits(digits: number, roundingMode: RoundingMode): ExactNumberType; | ||
/** Returns the integer bitwise-and combined with another integer. */ | ||
@@ -102,3 +102,3 @@ bitwiseAnd(x: number | bigint | string | ExactNumberType): ExactNumberType; | ||
* By default it simplifies the fraction */ | ||
getFractionParts(normalize: boolean): { | ||
getFractionParts(normalize?: boolean): { | ||
numerator: ExactNumberType; | ||
@@ -110,9 +110,11 @@ denominator: ExactNumberType; | ||
normalize(): ExactNumberType; | ||
/** Returns a string representing the number using fixed-point notation. */ | ||
toFixed(digits: number, trimTrailingZeros?: boolean): string; | ||
/** Returns a string representing the number using fixed-point notation, rounded to the specified number of decimals. */ | ||
toFixed(decimals: number, roundingMode?: RoundingMode): string; | ||
/** Returns a string representing the number in exponential notation. */ | ||
toExponential(digits: number): string; | ||
toExponential(digits: number, roundingMode?: RoundingMode): string; | ||
/** Returns a string representing the number using fixed-point notation, rounded to the specified number of significant digits. In contrary to JS Number.toPrecision(), this function never returns exponential notation. */ | ||
toPrecision(digits: number, roundingMode?: RoundingMode): string; | ||
/** Converts current value to a JavaScript Number */ | ||
toNumber(): number; | ||
/** Returns string representation of the current number in a fractional format like 1/2. It always simplifies the fraction before output. */ | ||
/** Returns string representation of the current number in a fractional format like "1/2". It always simplifies the fraction before output. */ | ||
toFraction(): string; | ||
@@ -119,0 +121,0 @@ /** Returns string representation in decimal format. |
@@ -0,3 +1,3 @@ | ||
/** Trims trailing zeros from numbers in fixed-point format (1.23000 -> 1.23) */ | ||
export declare const trimTrailingZeros: (num: string) => string; | ||
export declare const bigIntToStr: (num: bigint, pointRightPos: number, trimZeros: boolean) => string; | ||
export declare const modpow: (base: bigint, exp: bigint, mod: bigint) => bigint; |
{ | ||
"name": "exactnumber", | ||
"description": "Arbitrary-precision decimals. Enables making precise math calculations with rational numbers, without precision loss.", | ||
"version": "0.7.0", | ||
"version": "0.8.0", | ||
"main": "dist/index.umd.js", | ||
"module": "dist/index.esm.js", | ||
"types": "dist/types/index.d.ts", | ||
"types": "dist/src/index.d.ts", | ||
"scripts": { | ||
"build-rollup": "rollup -c", | ||
"build-types": "tsc --project tsconfig.json", | ||
"build": "npm run build-rollup && npm run build-types", | ||
"build": "npm run build-rollup", | ||
"eslint": "eslint ./src --ext .js,.ts", | ||
"test": "jest --", | ||
"test": "jest --coverage --", | ||
"typedoc": "typedoc", | ||
@@ -15,0 +14,0 @@ "typedoc-serve": "npm run typedoc && npx serve -n docs" |
@@ -109,4 +109,4 @@ # ExactNumber | ||
License = MIT | ||
License: MIT | ||
Copyright © 2022 Dani Biró |
@@ -25,3 +25,3 @@ import { RoundingMode } from '../types'; | ||
const jsResult = Math.exp(i).toString(); | ||
const jsRounded = ExactNumber(jsResult).round(RoundingMode.TO_ZERO, 10).toFixed(10); | ||
const jsRounded = ExactNumber(jsResult).round(10, RoundingMode.TO_ZERO).toFixed(10); | ||
const exactResult = exp(i.toString(), 10); | ||
@@ -28,0 +28,0 @@ expect(exactResult).toBe(jsRounded); |
@@ -10,3 +10,3 @@ import { RoundingMode } from '../types'; | ||
const jsResult = Math.sinh(i).toString(); | ||
const jsRounded = ExactNumber(jsResult).round(RoundingMode.TO_ZERO, 10).toFixed(10); | ||
const jsRounded = ExactNumber(jsResult).round(10, RoundingMode.TO_ZERO).toFixed(10); | ||
const exactResult = ExactNumber(sinh(i.toString(), 10)).toFixed(10); | ||
@@ -29,3 +29,3 @@ expect(exactResult).toBe(jsRounded); | ||
const jsResult = Math.cosh(i).toString(); | ||
const jsRounded = ExactNumber(jsResult).round(RoundingMode.TO_ZERO, 10).toFixed(10); | ||
const jsRounded = ExactNumber(jsResult).round(10, RoundingMode.TO_ZERO).toFixed(10); | ||
const exactResult = ExactNumber(cosh(i.toString(), 10)).toFixed(10); | ||
@@ -32,0 +32,0 @@ expect(exactResult).toBe(jsRounded); |
@@ -10,3 +10,3 @@ import { RoundingMode } from '../types'; | ||
const jsResult = Math.atan(i).toString(); | ||
const jsRounded = ExactNumber(jsResult).round(RoundingMode.TO_ZERO, 11).toFixed(11); | ||
const jsRounded = ExactNumber(jsResult).round(11, RoundingMode.TO_ZERO).toFixed(11); | ||
const exactResult = ExactNumber(atan(i.toString(), 11)).toFixed(11); | ||
@@ -29,3 +29,3 @@ expect(exactResult).toBe(jsRounded); | ||
const jsResult = Math.asin(i).toString(); | ||
const jsRounded = ExactNumber(jsResult).round(RoundingMode.TO_ZERO, 11).toFixed(11); | ||
const jsRounded = ExactNumber(jsResult).round(11, RoundingMode.TO_ZERO).toFixed(11); | ||
const exactResult = ExactNumber(asin(i.toString(), 11)).toFixed(11); | ||
@@ -48,3 +48,3 @@ expect(exactResult).toBe(jsRounded); | ||
const jsResult = Math.acos(i).toString(); | ||
const jsRounded = ExactNumber(jsResult).round(RoundingMode.TO_ZERO, 11).toFixed(11); | ||
const jsRounded = ExactNumber(jsResult).round(11, RoundingMode.TO_ZERO).toFixed(11); | ||
const exactResult = ExactNumber(acos(i.toString(), 11)).toFixed(11); | ||
@@ -51,0 +51,0 @@ expect(exactResult).toBe(jsRounded); |
@@ -11,3 +11,3 @@ import { RoundingMode } from '../types'; | ||
const jsResult = Math.log(i).toString(); | ||
const jsRounded = ExactNumber(jsResult).round(RoundingMode.TO_ZERO, 11).toFixed(11); | ||
const jsRounded = ExactNumber(jsResult).round(11, RoundingMode.TO_ZERO).toFixed(11); | ||
const exactResult = log(i.toString(), 11); | ||
@@ -21,3 +21,3 @@ expect(exactResult).toBe(jsRounded); | ||
const jsResult = Math.log(i).toString(); | ||
const jsRounded = ExactNumber(jsResult).round(RoundingMode.TO_ZERO, 10).toFixed(10); | ||
const jsRounded = ExactNumber(jsResult).round(10, RoundingMode.TO_ZERO).toFixed(10); | ||
const exactResult = log(i.toString(), 10); | ||
@@ -48,3 +48,3 @@ expect(exactResult).toBe(jsRounded); | ||
const jsResult = Math.log2(i).toString(); | ||
const jsRounded = ExactNumber(jsResult).round(RoundingMode.TO_ZERO, 11).toFixed(11); | ||
const jsRounded = ExactNumber(jsResult).round(11, RoundingMode.TO_ZERO).toFixed(11); | ||
const exactResult = log2(i.toString(), 11); | ||
@@ -58,3 +58,3 @@ expect(exactResult).toBe(jsRounded); | ||
const jsResult = Math.log10(i).toString(); | ||
const jsRounded = ExactNumber(jsResult).round(RoundingMode.TO_ZERO, 11).toFixed(11); | ||
const jsRounded = ExactNumber(jsResult).round(11, RoundingMode.TO_ZERO).toFixed(11); | ||
const exactResult = log10(i.toString(), 11); | ||
@@ -61,0 +61,0 @@ expect(exactResult).toBe(jsRounded); |
@@ -20,3 +20,3 @@ import { RoundingMode } from '../types'; | ||
const jsResult = Math.sqrt(i).toString(); | ||
const jsRounded = ExactNumber(jsResult).round(RoundingMode.TO_ZERO, 10).toFixed(10); | ||
const jsRounded = ExactNumber(jsResult).round(10, RoundingMode.TO_ZERO).toFixed(10); | ||
const exactResult = sqrt(i.toString(), 10); | ||
@@ -55,3 +55,3 @@ expect(exactResult).toBe(jsRounded); | ||
const jsResult = Math.cbrt(i).toString(); | ||
const jsRounded = ExactNumber(jsResult).round(RoundingMode.TO_ZERO, 10).toFixed(10); | ||
const jsRounded = ExactNumber(jsResult).round(10, RoundingMode.TO_ZERO).toFixed(10); | ||
const exactResult = cbrt(i.toString(), 10); | ||
@@ -58,0 +58,0 @@ expect(exactResult).toBe(jsRounded); |
@@ -19,3 +19,3 @@ import { RoundingMode } from '../types'; | ||
const jsResult = Math.sin(i).toString(); | ||
const jsRounded = ExactNumber(jsResult).round(RoundingMode.TO_ZERO, 11).toFixed(11); | ||
const jsRounded = ExactNumber(jsResult).round(11, RoundingMode.TO_ZERO).toFixed(11); | ||
const exactResult = sin(i.toString(), 11); | ||
@@ -53,3 +53,3 @@ expect(exactResult).toBe(jsRounded); | ||
const jsResult = Math.cos(i).toString(); | ||
const jsRounded = ExactNumber(jsResult).round(RoundingMode.TO_ZERO, 11).toFixed(11); | ||
const jsRounded = ExactNumber(jsResult).round(11, RoundingMode.TO_ZERO).toFixed(11); | ||
const exactResult = cos(i.toString(), 11); | ||
@@ -73,3 +73,3 @@ expect(exactResult).toBe(jsRounded); | ||
if (Math.abs(jsResult) > 10) continue; // TODO | ||
const jsRounded = ExactNumber(jsResult.toString()).round(RoundingMode.TO_ZERO, 11).toFixed(11); | ||
const jsRounded = ExactNumber(jsResult.toString()).round(11, RoundingMode.TO_ZERO).toFixed(11); | ||
const exactResult = tan(i.toString(), 11); | ||
@@ -76,0 +76,0 @@ expect(exactResult).toBe(jsRounded); |
@@ -71,3 +71,3 @@ import { FixedNumber } from '../FixedNumber'; | ||
const x2 = x.round(RoundingMode.NEAREST_AWAY_FROM_ZERO, EXTRA_DIGITS).pow(2n).normalize(); | ||
const x2 = x.round(EXTRA_DIGITS, RoundingMode.NEAREST_AWAY_FROM_ZERO).pow(2n).normalize(); | ||
@@ -119,3 +119,3 @@ // cos x = 1 - x^2/2! + x^4/4! - ... | ||
const res = quadrant === 1 || quadrant === 4 ? xk : xk.neg(); | ||
const strRes = res.round(RoundingMode.TO_ZERO, digits + 3).toFixed(digits); | ||
const strRes = res.round(digits + 3, RoundingMode.TO_ZERO).toFixed(digits); | ||
@@ -122,0 +122,0 @@ return strRes; |
@@ -36,2 +36,4 @@ import { FixedNumber } from './FixedNumber'; | ||
} | ||
expect(run('3', '4/2')).toBe('2'); | ||
}); | ||
@@ -61,2 +63,4 @@ | ||
} | ||
expect(run('3', '4/2')).toBe('3'); | ||
}); | ||
@@ -86,2 +90,3 @@ | ||
} | ||
expect(run('3', '4/2')).toBe('1'); | ||
}); | ||
@@ -88,0 +93,0 @@ |
@@ -151,2 +151,3 @@ import { FixedNumber } from './FixedNumber'; | ||
expect(run('2', '0')).toBe('1'); | ||
expect(run('-2', '0')).toBe('1'); | ||
expect(run('0', 2)).toBe('0'); | ||
@@ -159,4 +160,43 @@ expect(run('12.34', 1n)).toBe('12.34'); | ||
expect(run('0.1', '10')).toBe('0.0000000001'); | ||
expect(() => run('2', '-1')).toThrow('Unsupported parameter'); | ||
expect(() => run('2', '-2')).toThrow('Unsupported parameter'); | ||
expect(() => run('2', '0.5')).toThrow('Unsupported parameter'); | ||
expect(() => run('2', '10e500')).toThrow('Unsupported parameter'); | ||
}); | ||
it('div()', () => { | ||
const run = (a: ExactNumberParameter, b: ExactNumberParameter) => new FixedNumber(a).div(b).toString(); | ||
expect(run('1', '2')).toBe('0.5'); | ||
expect(run('-1', '2')).toBe('-0.5'); | ||
expect(run('1', '-2')).toBe('-0.5'); | ||
expect(run('-1', '-2')).toBe('0.5'); | ||
expect(run('0.5', '-3.2')).toBe('-0.15625'); | ||
expect(() => run('1', '0')).toThrow('Division by zero'); | ||
expect(() => run('0', '0')).toThrow('Division by zero'); | ||
}); | ||
it('divToInt()', () => { | ||
const run = (a: ExactNumberParameter, b: ExactNumberParameter) => new FixedNumber(a).divToInt(b).toString(); | ||
expect(run('1', '2')).toBe('0'); | ||
expect(run('2', '2')).toBe('1'); | ||
expect(run('33', '31')).toBe('1'); | ||
expect(run('256', '127')).toBe('2'); | ||
expect(run('99', '2')).toBe('49'); | ||
expect(run('-99', '2')).toBe('-49'); | ||
expect(run('99', '-2')).toBe('-49'); | ||
expect(run('-99', '-2')).toBe('49'); | ||
expect(run('1.5', '2')).toBe('0'); | ||
expect(run('2.5', '2')).toBe('1'); | ||
expect(run('1.5', '0.002')).toBe('750'); | ||
expect(run('1.5', '1/3')).toBe('4'); | ||
expect(() => run('1', '0')).toThrow('Division by zero'); | ||
expect(() => run('0', '0')).toThrow('Division by zero'); | ||
}); | ||
it('mod()', () => { | ||
@@ -199,2 +239,4 @@ const run = (a: ExactNumberParameter, b: ExactNumberParameter, type?: ModType) => | ||
} | ||
expect(() => run('1', '2', '3' as ModType)).toThrow('Invalid ModType'); | ||
}); | ||
@@ -304,3 +346,3 @@ | ||
values.forEach((num, i) => { | ||
const res = new FixedNumber(num).round(rndMode as RoundingMode, digits).toString(); | ||
const res = new FixedNumber(num).round(digits, rndMode as RoundingMode).toString(); | ||
expect(res).toBe(tableRow[i]); | ||
@@ -347,72 +389,69 @@ }); | ||
it('round() tie or not', () => { | ||
const run = (a: string, rndMode?: RoundingMode, digits?: number) => | ||
new FixedNumber(a).round(rndMode, digits).toFixed(digits ?? 0); | ||
const run = (a: string, decimals?: number, rndMode?: RoundingMode) => | ||
new FixedNumber(a).round(decimals, rndMode).toFixed(decimals ?? 0); | ||
expect(run('1.400', RoundingMode.NEAREST_TO_POSITIVE)).toBe('1'); | ||
expect(run('1.5', RoundingMode.NEAREST_TO_NEGATIVE)).toBe('1'); | ||
expect(run('1.50', RoundingMode.NEAREST_TO_NEGATIVE)).toBe('1'); | ||
expect(run('1.500', RoundingMode.NEAREST_TO_NEGATIVE)).toBe('1'); | ||
expect(run('-1.500', RoundingMode.NEAREST_TO_POSITIVE)).toBe('-1'); | ||
expect(run('-1.501', RoundingMode.NEAREST_TO_POSITIVE)).toBe('-2'); | ||
expect(run('1.51', RoundingMode.NEAREST_TO_NEGATIVE)).toBe('2'); | ||
expect(run('1.501', RoundingMode.NEAREST_TO_NEGATIVE)).toBe('2'); | ||
expect(run('1.5010', RoundingMode.NEAREST_TO_NEGATIVE)).toBe('2'); | ||
expect(run('1.400', 0, RoundingMode.NEAREST_TO_POSITIVE)).toBe('1'); | ||
expect(run('1.5', 0, RoundingMode.NEAREST_TO_NEGATIVE)).toBe('1'); | ||
expect(run('1.50', 0, RoundingMode.NEAREST_TO_NEGATIVE)).toBe('1'); | ||
expect(run('1.500', 0, RoundingMode.NEAREST_TO_NEGATIVE)).toBe('1'); | ||
expect(run('-1.500', 0, RoundingMode.NEAREST_TO_POSITIVE)).toBe('-1'); | ||
expect(run('-1.501', 0, RoundingMode.NEAREST_TO_POSITIVE)).toBe('-2'); | ||
expect(run('1.51', 0, RoundingMode.NEAREST_TO_NEGATIVE)).toBe('2'); | ||
expect(run('1.501', 0, RoundingMode.NEAREST_TO_NEGATIVE)).toBe('2'); | ||
expect(run('1.5010', 0, RoundingMode.NEAREST_TO_NEGATIVE)).toBe('2'); | ||
}); | ||
it('round() special cases', () => { | ||
const run = (a: string, rndMode?: RoundingMode, digits?: number) => | ||
new FixedNumber(a).round(rndMode, digits).toFixed(digits ?? 0); | ||
const run = (a: string, decimals?: number, rndMode?: RoundingMode) => | ||
new FixedNumber(a).round(decimals, rndMode).toFixed(decimals ?? 0); | ||
expect(run('0')).toBe('0'); | ||
expect(run('-0')).toBe('0'); | ||
expect(run('0', RoundingMode.TO_ZERO, 2)).toBe('0.00'); | ||
expect(run('0.1', RoundingMode.TO_ZERO, 2)).toBe('0.10'); | ||
expect(run('0.11', RoundingMode.TO_ZERO, 2)).toBe('0.11'); | ||
expect(run('0.111', RoundingMode.TO_ZERO, 2)).toBe('0.11'); | ||
expect(run('0.111', RoundingMode.TO_POSITIVE, 2)).toBe('0.12'); | ||
expect(run('1', RoundingMode.TO_ZERO, 2)).toBe('1.00'); | ||
expect(run('0', 2, RoundingMode.TO_ZERO)).toBe('0.00'); | ||
expect(run('0.1', 2, RoundingMode.TO_ZERO)).toBe('0.10'); | ||
expect(run('0.11', 2, RoundingMode.TO_ZERO)).toBe('0.11'); | ||
expect(run('0.111', 2, RoundingMode.TO_ZERO)).toBe('0.11'); | ||
expect(run('0.111', 2, RoundingMode.TO_POSITIVE)).toBe('0.12'); | ||
expect(run('1', 2, RoundingMode.TO_ZERO)).toBe('1.00'); | ||
expect(run('0.834631259841', RoundingMode.AWAY_FROM_ZERO, 2)).toBe('0.84'); | ||
expect(run('0.640652', RoundingMode.NEAREST_TO_ZERO, 2)).toBe('0.64'); | ||
expect(run('0.834631259841', 2, RoundingMode.AWAY_FROM_ZERO)).toBe('0.84'); | ||
expect(run('0.640652', 2, RoundingMode.NEAREST_TO_ZERO)).toBe('0.64'); | ||
expect(() => run('1.23', 0, '3' as RoundingMode)).toThrow( | ||
'Invalid rounding mode. Use the predefined values from the RoundingMode enum.', | ||
); | ||
}); | ||
it('roundToDigits()', () => { | ||
const run = (a: string, rndMode: RoundingMode, digits: number) => | ||
new FixedNumber(a).roundToDigits(rndMode, digits).toString(); | ||
const run = (a: string, digits: number, rndMode: RoundingMode) => | ||
new FixedNumber(a).roundToDigits(digits, rndMode).toString(); | ||
expect(run('0', RoundingMode.TO_ZERO, 2)).toBe('0'); | ||
expect(run('-0', RoundingMode.TO_ZERO, 3)).toBe('0'); | ||
expect(run('0', 2, RoundingMode.TO_ZERO)).toBe('0'); | ||
expect(run('-0', 3, RoundingMode.TO_ZERO)).toBe('0'); | ||
expect(run('-12345', RoundingMode.TO_ZERO, 1)).toBe('-10000'); | ||
expect(run('-12345', RoundingMode.TO_ZERO, 7)).toBe('-12345'); | ||
expect(run('-12345', 1, RoundingMode.TO_ZERO)).toBe('-10000'); | ||
expect(run('-12345', 7, RoundingMode.TO_ZERO)).toBe('-12345'); | ||
expect(run('123.45', RoundingMode.TO_ZERO, 1)).toBe('100'); | ||
expect(run('123.45', RoundingMode.TO_ZERO, 3)).toBe('123'); | ||
expect(run('-123.45', RoundingMode.TO_ZERO, 4)).toBe('-123.4'); | ||
expect(run('-123.45', RoundingMode.TO_ZERO, 5)).toBe('-123.45'); | ||
expect(run('123.45', RoundingMode.TO_ZERO, 6)).toBe('123.45'); | ||
expect(run('123.45', 1, RoundingMode.TO_ZERO)).toBe('100'); | ||
expect(run('123.45', 3, RoundingMode.TO_ZERO)).toBe('123'); | ||
expect(run('-123.45', 4, RoundingMode.TO_ZERO)).toBe('-123.4'); | ||
expect(run('-123.45', 5, RoundingMode.TO_ZERO)).toBe('-123.45'); | ||
expect(run('123.45', 6, RoundingMode.TO_ZERO)).toBe('123.45'); | ||
expect(run('129.000', RoundingMode.TO_ZERO, 2)).toBe('120'); | ||
expect(run('129.000', RoundingMode.TO_POSITIVE, 2)).toBe('130'); | ||
expect(run('129.000', RoundingMode.TO_ZERO, 6)).toBe('129'); | ||
expect(run('129.000', 2, RoundingMode.TO_ZERO)).toBe('120'); | ||
expect(run('129.000', 2, RoundingMode.TO_POSITIVE)).toBe('130'); | ||
expect(run('129.000', 6, RoundingMode.TO_ZERO)).toBe('129'); | ||
expect(run('0.0001234', RoundingMode.TO_ZERO, 1)).toBe('0.0001'); | ||
expect(run('-0.0001234', RoundingMode.TO_ZERO, 2)).toBe('-0.00012'); | ||
expect(run('0.0001234', 1, RoundingMode.TO_ZERO)).toBe('0.0001'); | ||
expect(run('-0.0001234', 2, RoundingMode.TO_ZERO)).toBe('-0.00012'); | ||
expect(run('45.452', RoundingMode.NEAREST_AWAY_FROM_ZERO, 1)).toBe('50'); | ||
expect(run('45.452', RoundingMode.NEAREST_AWAY_FROM_ZERO, 2)).toBe('45'); | ||
expect(run('45.452', RoundingMode.NEAREST_AWAY_FROM_ZERO, 3)).toBe('45.5'); | ||
expect(run('45.452', RoundingMode.NEAREST_AWAY_FROM_ZERO, 4)).toBe('45.45'); | ||
expect(run('45.452', RoundingMode.NEAREST_AWAY_FROM_ZERO, 5)).toBe('45.452'); | ||
expect(run('45.452', RoundingMode.NEAREST_AWAY_FROM_ZERO, 6)).toBe('45.452'); | ||
}); | ||
expect(run('45.452', 1, RoundingMode.NEAREST_AWAY_FROM_ZERO)).toBe('50'); | ||
expect(run('45.452', 2, RoundingMode.NEAREST_AWAY_FROM_ZERO)).toBe('45'); | ||
expect(run('45.452', 3, RoundingMode.NEAREST_AWAY_FROM_ZERO)).toBe('45.5'); | ||
expect(run('45.452', 4, RoundingMode.NEAREST_AWAY_FROM_ZERO)).toBe('45.45'); | ||
expect(run('45.452', 5, RoundingMode.NEAREST_AWAY_FROM_ZERO)).toBe('45.452'); | ||
expect(run('45.452', 6, RoundingMode.NEAREST_AWAY_FROM_ZERO)).toBe('45.452'); | ||
it('sign()', () => { | ||
const run = (a: string) => new FixedNumber(a).sign(); | ||
expect(run('0')).toBe(1); | ||
expect(run('-1.234')).toBe(-1); | ||
expect(run('1.234')).toBe(1); | ||
expect(run('-.234')).toBe(-1); | ||
expect(run('.234')).toBe(1); | ||
expect(() => run('1.23', 0, RoundingMode.TO_ZERO)).toThrow('Invalid value for digits'); | ||
expect(() => run('1.23', '1' as any, RoundingMode.TO_ZERO)).toThrow('Invalid value for digits'); | ||
}); | ||
@@ -444,2 +483,12 @@ | ||
it('sign()', () => { | ||
const run = (a: string) => new FixedNumber(a).sign(); | ||
expect(run('0')).toBe(1); | ||
expect(run('-1.234')).toBe(-1); | ||
expect(run('1.234')).toBe(1); | ||
expect(run('-.234')).toBe(-1); | ||
expect(run('.234')).toBe(1); | ||
}); | ||
it('cmp()', () => { | ||
@@ -523,18 +572,2 @@ const run = (a: string, b: string) => new FixedNumber(a).cmp(b); | ||
it('getFractionParts()', () => { | ||
const run = (a: ExactNumberParameter, normalize?: boolean) => { | ||
const res = new FixedNumber(a).getFractionParts(normalize); | ||
return { numerator: res.numerator.toString(), denominator: res.denominator.toString() }; | ||
}; | ||
expect(run('2')).toStrictEqual({ numerator: '2', denominator: '1' }); | ||
expect(run('0')).toStrictEqual({ numerator: '0', denominator: '1' }); | ||
expect(run('-5')).toStrictEqual({ numerator: '-5', denominator: '1' }); | ||
expect(run('0.4')).toStrictEqual({ numerator: '2', denominator: '5' }); // test normalization (4 / 10 = 2 / 5) | ||
expect(run('-0.4')).toStrictEqual({ numerator: '-2', denominator: '5' }); | ||
expect(run('0.4', true)).toStrictEqual({ numerator: '2', denominator: '5' }); | ||
expect(run('0.4', false)).toStrictEqual({ numerator: '4', denominator: '10' }); | ||
}); | ||
it('clamp()', () => { | ||
@@ -597,40 +630,19 @@ const run = (a: ExactNumberParameter, min: ExactNumberParameter, max: ExactNumberParameter) => | ||
it('toString() with radix', () => { | ||
const run = (a: string, radix: number) => new FixedNumber(a).toString(radix); | ||
it('getFractionParts()', () => { | ||
const run = (a: ExactNumberParameter, normalize?: boolean) => { | ||
const res = new FixedNumber(a).getFractionParts(normalize); | ||
const res2 = new FixedNumber(a).convertToFraction().getFractionParts(normalize); | ||
expect(res.numerator.toString()).toBe(res2.numerator.toString()); | ||
expect(res.denominator.toString()).toBe(res2.denominator.toString()); | ||
return { numerator: res.numerator.toString(), denominator: res.denominator.toString() }; | ||
}; | ||
expect(run('0', 2)).toBe('0'); | ||
expect(run('16', 2)).toBe('10000'); | ||
expect(run('-16', 2)).toBe('-10000'); | ||
expect(run('16.000', 2)).toBe('10000'); | ||
expect(run('0.125', 2)).toBe('0.001'); | ||
expect(run('0.5', 3)).toBe('0.(1)'); | ||
expect(run('-123.500', 10)).toBe('-123.5'); | ||
expect(run('0.4', 3)).toBe('0.(1012)'); | ||
expect(run('0.3', 16)).toBe('0.4(c)'); | ||
expect(run('0.013', 7)).toBe('0.(00431330261442015456)'); | ||
expect(run('0.012', 6)).toBe('0.0(0233151220401052455413443)'); | ||
expect(run('-0.012', 6)).toBe('-0.0(0233151220401052455413443)'); | ||
expect(run('-15.012', 6)).toBe('-23.0(0233151220401052455413443)'); | ||
}); | ||
expect(run('2')).toStrictEqual({ numerator: '2', denominator: '1' }); | ||
expect(run('0')).toStrictEqual({ numerator: '0', denominator: '1' }); | ||
expect(run('-5')).toStrictEqual({ numerator: '-5', denominator: '1' }); | ||
expect(run('0.4')).toStrictEqual({ numerator: '2', denominator: '5' }); // test normalization (4 / 10 = 2 / 5) | ||
expect(run('-0.4')).toStrictEqual({ numerator: '-2', denominator: '5' }); | ||
it('toString() with radix + maxDigits', () => { | ||
const run = (a: string, radix: number, maxDigits: number) => new FixedNumber(a).toString(radix, maxDigits); | ||
expect(run('0', 2, 0)).toBe('0'); | ||
expect(run('-0', 2, 10)).toBe('0'); | ||
expect(run('16.000', 2, 0)).toBe('10000'); | ||
expect(run('0.125', 2, 0)).toBe('0'); | ||
expect(run('0.125', 2, 2)).toBe('0.00'); | ||
expect(run('0.125', 2, 3)).toBe('0.001'); | ||
expect(run('0.125', 2, 4)).toBe('0.001'); | ||
expect(run('0.5', 3, 0)).toBe('0'); | ||
expect(run('0.5', 3, 1)).toBe('0.(1)'); | ||
expect(run('-123.500', 10, 2)).toBe('-123.5'); | ||
expect(run('-123.4567', 10, 2)).toBe('-123.45'); | ||
expect(run('0.4', 3, 3)).toBe('0.101'); | ||
expect(run('0.4', 3, 4)).toBe('0.(1012)'); | ||
expect(run('-15.012', 6, 0)).toBe('-23'); | ||
expect(run('-15.012', 6, 1)).toBe('-23.0'); | ||
expect(run('-15.012', 6, 6)).toBe('-23.002331'); | ||
expect(run('-15.012', 6, 100)).toBe('-23.0(0233151220401052455413443)'); | ||
expect(run('0.4', true)).toStrictEqual({ numerator: '2', denominator: '5' }); | ||
expect(run('0.4', false)).toStrictEqual({ numerator: '4', denominator: '10' }); | ||
}); | ||
@@ -651,2 +663,63 @@ | ||
it('toFixed()', () => { | ||
const run = (x: string, digits: number, rndMode?: RoundingMode) => new FixedNumber(x).toFixed(digits, rndMode); | ||
expect(run('0', 0)).toBe('0'); | ||
expect(run('0', 1)).toBe('0.0'); | ||
expect(run('2', 3)).toBe('2.000'); | ||
expect(run('-123', 2)).toBe('-123.00'); | ||
expect(run('0.45600', 0)).toBe('0'); | ||
expect(run('0.45600', 1)).toBe('0.4'); | ||
expect(run('0.45600', 2)).toBe('0.45'); | ||
expect(run('0.45600', 6)).toBe('0.456000'); | ||
expect(run('-123.45600', 0)).toBe('-123'); | ||
expect(run('-123.45600', 1)).toBe('-123.4'); | ||
expect(run('-123.45600', 6)).toBe('-123.456000'); | ||
expect(() => run('-1.45', -1)).toThrow('Invalid parameter'); | ||
expect(() => run('-1.45', 0.5)).toThrow('Invalid parameter'); | ||
}); | ||
it('toFixed() rounding modes', () => { | ||
for (const rndMode of Object.values(RoundingMode)) { | ||
for (let i = 0; i < 10; i++) { | ||
let num = new FixedNumber('123.45600'); | ||
expect(num.toFixed(i, rndMode)).toBe(num.round(i, rndMode).toFixed(i)); | ||
num = new FixedNumber('-123.45600'); | ||
expect(num.toFixed(i, rndMode)).toBe(num.round(i, rndMode).toFixed(i)); | ||
} | ||
} | ||
}); | ||
it('toPrecision()', () => { | ||
const run = (x: string, digits: number) => new FixedNumber(x).toPrecision(digits); | ||
expect(run('0', 1)).toBe('0'); | ||
expect(run('0', 2)).toBe('0.0'); | ||
expect(run('2', 3)).toBe('2.00'); | ||
expect(run('-123', 2)).toBe('-120'); | ||
expect(run('-123', 3)).toBe('-123'); | ||
expect(run('-123', 4)).toBe('-123.0'); | ||
expect(run('123', 5)).toBe('123.00'); | ||
expect(run('0.0045600', 1)).toBe('0.004'); | ||
expect(run('-0.0045600', 2)).toBe('-0.0045'); | ||
expect(run('0.0045600', 3)).toBe('0.00456'); | ||
expect(run('0.0045600', 6)).toBe('0.00456000'); | ||
expect(() => run('-1.45', -1)).toThrow('Invalid parameter'); | ||
expect(() => run('-1.45', 0)).toThrow('Invalid parameter'); | ||
expect(() => run('-1.45', 0.5)).toThrow('Invalid parameter'); | ||
}); | ||
// it('toPrecision() rounding modes', () => { | ||
// for (const rndMode of Object.values(RoundingMode)) { | ||
// for (let i = 0; i < 10; i++) { | ||
// let num = new FixedNumber('123.45600'); | ||
// expect(num.toPrecision(i, rndMode)).toBe(num.roundToDigits(rndMode, i).toPrecision(i)); | ||
// num = new FixedNumber('-123.45600'); | ||
// expect(num.toPrecision(i, rndMode)).toBe(num.roundToDigits(rndMode, i).toPrecision(i)); | ||
// } | ||
// } | ||
// }); | ||
it('toExponential()', () => { | ||
@@ -679,20 +752,81 @@ const run = (a: string, digits: number) => new FixedNumber(a).toExponential(digits); | ||
expect(run('-.0123', 3)).toBe('-1.230e-2'); | ||
expect(() => run('-1.45', -1)).toThrow('Invalid parameter'); | ||
expect(() => run('-1.45', 0.5)).toThrow('Invalid parameter'); | ||
}); | ||
it('toFixed()', () => { | ||
const run = (x: string, digits: number) => new FixedNumber(x).toFixed(digits); | ||
it('toString() with radix', () => { | ||
const run = (a: string, radix: number) => new FixedNumber(a).toString(radix); | ||
expect(run('0', 0)).toBe('0'); | ||
expect(run('0', 1)).toBe('0.0'); | ||
expect(run('2', 3)).toBe('2.000'); | ||
expect(run('-123', 2)).toBe('-123.00'); | ||
expect(run('0.45600', 0)).toBe('0'); | ||
expect(run('0.45600', 1)).toBe('0.4'); | ||
expect(run('0.45600', 2)).toBe('0.45'); | ||
expect(run('0.45600', 6)).toBe('0.456000'); | ||
expect(run('-123.45600', 0)).toBe('-123'); | ||
expect(run('-123.45600', 1)).toBe('-123.4'); | ||
expect(run('-123.45600', 6)).toBe('-123.456000'); | ||
expect(run('0', 2)).toBe('0'); | ||
expect(run('16', 2)).toBe('10000'); | ||
expect(run('-16', 2)).toBe('-10000'); | ||
expect(run('16.000', 2)).toBe('10000'); | ||
expect(run('0.125', 2)).toBe('0.001'); | ||
expect(run('0.5', 3)).toBe('0.(1)'); | ||
expect(run('-123.500', 10)).toBe('-123.5'); | ||
expect(run('0.4', 3)).toBe('0.(1012)'); | ||
expect(run('0.3', 16)).toBe('0.4(c)'); | ||
expect(run('0.013', 7)).toBe('0.(00431330261442015456)'); | ||
expect(run('0.012', 6)).toBe('0.0(0233151220401052455413443)'); | ||
expect(run('-0.012', 6)).toBe('-0.0(0233151220401052455413443)'); | ||
expect(run('-15.012', 6)).toBe('-23.0(0233151220401052455413443)'); | ||
expect(run('100', 5)).toBe('400'); | ||
expect(run('-123', 7)).toBe('-234'); | ||
expect(run('123.045', 15)).toBe('83.0a(1d)'); | ||
expect(() => run('1', '2' as any)).toThrow('Invalid radix'); | ||
expect(() => run('1', 1)).toThrow('Invalid radix'); | ||
expect(() => run('1', 17)).toThrow('Invalid radix'); | ||
}); | ||
it('toString() with radix + maxDigits', () => { | ||
const run = (a: string, radix: number, maxDigits: number) => new FixedNumber(a).toString(radix, maxDigits); | ||
expect(run('-12.000', 10, 2)).toBe('-12'); | ||
expect(run('-12.345', 10, 0)).toBe('-12'); | ||
expect(run('-12.345', 10, 1)).toBe('-12.3'); | ||
expect(run('-12.345', 10, 2)).toBe('-12.34'); | ||
expect(run('-12.345', 10, 3)).toBe('-12.345'); | ||
expect(run('-12.345', 10, 4)).toBe('-12.345'); | ||
expect(() => run('-12.345', 10, -1)).toThrow('Invalid value for decimals'); | ||
expect(run('0', 2, 0)).toBe('0'); | ||
expect(run('-0', 2, 10)).toBe('0'); | ||
expect(run('16.000', 2, 0)).toBe('10000'); | ||
expect(run('0.125', 2, 0)).toBe('0'); | ||
expect(run('0.125', 2, 2)).toBe('0.00'); | ||
expect(run('0.125', 2, 3)).toBe('0.001'); | ||
expect(run('0.125', 2, 4)).toBe('0.001'); | ||
expect(run('0.5', 3, 0)).toBe('0'); | ||
expect(run('0.5', 3, 1)).toBe('0.(1)'); | ||
expect(run('-123.500', 10, 2)).toBe('-123.5'); | ||
expect(run('-123.4567', 10, 2)).toBe('-123.45'); | ||
expect(run('0.4', 3, 3)).toBe('0.101'); | ||
expect(run('0.4', 3, 4)).toBe('0.(1012)'); | ||
expect(run('-15.012', 6, 0)).toBe('-23'); | ||
expect(run('-15.012', 6, 1)).toBe('-23.0'); | ||
expect(run('-15.012', 6, 6)).toBe('-23.002331'); | ||
expect(run('-15.012', 6, 100)).toBe('-23.0(0233151220401052455413443)'); | ||
expect(run('123.045', 15, 0)).toBe('83'); | ||
expect(run('123.045', 15, 1)).toBe('83.0'); | ||
expect(run('123.045', 15, 2)).toBe('83.0a'); | ||
expect(run('123.045', 15, 3)).toBe('83.0a1'); | ||
expect(run('123.045', 15, 4)).toBe('83.0a(1d)'); | ||
expect(run('-123.045', 15, 5)).toBe('-83.0a(1d)'); | ||
expect(() => run('1', 2, -1)).toThrow('Invalid parameter'); | ||
expect(() => run('1', 2, '1' as any)).toThrow('Invalid parameter'); | ||
}); | ||
it('toFraction()', () => { | ||
const run = (x: string) => new FixedNumber(x).toFraction(); | ||
expect(run('0')).toBe('0/1'); | ||
expect(run('0.0123')).toBe('123/10000'); | ||
expect(run('-0.0123')).toBe('-123/10000'); | ||
expect(run('3.6')).toBe('18/5'); | ||
}); | ||
it('toString()', () => { | ||
@@ -719,2 +853,9 @@ const run = (x: string) => new FixedNumber(x).toString(); | ||
}); | ||
it('valueOf()', () => { | ||
const run = (x: string) => new FixedNumber(x).valueOf(); | ||
expect(() => run('0')).toThrow('Unsafe conversion to Number type! Use toNumber() instead.'); | ||
expect(() => run('2')).toThrow('Unsafe conversion to Number type! Use toNumber() instead.'); | ||
}); | ||
}); |
@@ -114,9 +114,5 @@ import { bigIntToStr } from './util'; | ||
const operand = parseParameter(x); | ||
if (!operand.isInteger()) { | ||
throw new Error('Invalid parameter'); | ||
} | ||
const exp = operand.toNumber(); | ||
if (!Number.isSafeInteger(exp)) { | ||
throw new Error('Invalid parameter'); | ||
if (!Number.isSafeInteger(exp) || exp < 0) { | ||
throw new Error('Unsupported parameter'); | ||
} | ||
@@ -172,3 +168,3 @@ | ||
abs(): ExactNumberType { | ||
abs(): FixedNumber { | ||
const res = new FixedNumber(this.number < 0 ? -this.number : this.number, this.decimalPos); | ||
@@ -179,3 +175,3 @@ return res; | ||
neg() { | ||
return this.mul(-1n); | ||
return this.mul(-1n) as FixedNumber; | ||
} | ||
@@ -190,3 +186,3 @@ | ||
return this.round(RoundingMode.TO_NEGATIVE, decimals); | ||
return this.round(decimals, RoundingMode.TO_NEGATIVE); | ||
} | ||
@@ -197,3 +193,3 @@ | ||
return this.round(RoundingMode.TO_POSITIVE, decimals); | ||
return this.round(decimals, RoundingMode.TO_POSITIVE); | ||
} | ||
@@ -204,6 +200,6 @@ | ||
return this.round(RoundingMode.TO_ZERO, decimals); | ||
return this.round(decimals, RoundingMode.TO_ZERO); | ||
} | ||
round(roundingMode?: RoundingMode, decimals?: number) { | ||
round(decimals?: number, roundingMode?: RoundingMode) { | ||
decimals = decimals === undefined ? 0 : decimals; | ||
@@ -242,2 +238,15 @@ if (!Number.isSafeInteger(decimals) || decimals < 0) { | ||
if ( | ||
![ | ||
undefined, | ||
RoundingMode.NEAREST_TO_ZERO, | ||
RoundingMode.NEAREST_AWAY_FROM_ZERO, | ||
RoundingMode.NEAREST_TO_POSITIVE, | ||
RoundingMode.NEAREST_TO_NEGATIVE, | ||
RoundingMode.NEAREST_TO_EVEN, | ||
].includes(roundingMode) | ||
) { | ||
throw new Error('Invalid rounding mode. Use the predefined values from the RoundingMode enum.'); | ||
} | ||
let fracStr = (fracPart < 0n ? -fracPart : fracPart).toString(); | ||
@@ -289,22 +298,31 @@ | ||
if ( | ||
roundingMode === undefined || | ||
roundingMode === RoundingMode.NEAREST_TO_ZERO || | ||
roundingMode === RoundingMode.NEAREST_AWAY_FROM_ZERO || | ||
roundingMode === RoundingMode.NEAREST_TO_POSITIVE || | ||
roundingMode === RoundingMode.NEAREST_TO_NEGATIVE || | ||
roundingMode === RoundingMode.NEAREST_TO_EVEN | ||
) { | ||
if (Number(fracStr[0]) < 5) { | ||
return new FixedNumber(numberToZero, decimals); | ||
if (Number(fracStr[0]) < 5) { | ||
return new FixedNumber(numberToZero, decimals); | ||
} | ||
const res = this.number < 0 ? numberToZero - 1n : numberToZero + 1n; | ||
return new FixedNumber(res, decimals); | ||
} | ||
_incExponent(amount: number): FixedNumber { | ||
if (amount === 0) return this; | ||
let newNumber = this.number; | ||
let newDecimalPos = this.decimalPos; | ||
if (amount < 0) { | ||
newDecimalPos -= amount; | ||
} else { | ||
// amount >= 0 | ||
const maxChange = Math.min(amount, this.decimalPos); | ||
newDecimalPos -= maxChange; | ||
const rem = amount - maxChange; | ||
if (rem > 0) { | ||
newNumber *= 10n ** BigInt(rem); | ||
} | ||
const res = this.number < 0 ? numberToZero - 1n : numberToZero + 1n; | ||
return new FixedNumber(res, decimals); | ||
} | ||
throw new Error('Invalid rounding mode. Use the predefined values from the RoundingMode enum.'); | ||
return new FixedNumber(newNumber, newDecimalPos); | ||
} | ||
roundToDigits(roundingMode: RoundingMode, digits: number) { | ||
roundToDigits(digits: number, roundingMode: RoundingMode): FixedNumber { | ||
if (!Number.isSafeInteger(digits) || digits < 1) { | ||
@@ -319,13 +337,8 @@ throw new Error('Invalid value for digits'); | ||
const str = absNumber.toString(); | ||
const newNumber = new FixedNumber(`0.${str}`); | ||
let roundedNumber = newNumber.round(roundingMode, digits); | ||
const numberBetweenZeroAndOne = new FixedNumber(absNumber, str.length); | ||
let roundedNumber = numberBetweenZeroAndOne.round(digits, roundingMode); | ||
const totalDigits = str.length; | ||
const wholeDigits = totalDigits - this.decimalPos; | ||
const integerDigits = str.length - this.decimalPos; | ||
if (wholeDigits < 0) { | ||
roundedNumber = roundedNumber.div(10n ** BigInt(-wholeDigits)) as FixedNumber; | ||
} else { | ||
roundedNumber = roundedNumber.mul(10n ** BigInt(wholeDigits)) as FixedNumber; | ||
} | ||
roundedNumber = roundedNumber._incExponent(integerDigits); | ||
@@ -524,3 +537,3 @@ return isNegative ? roundedNumber.neg() : roundedNumber; | ||
serialize() { | ||
serialize(): [bigint, number] { | ||
return [this.number, this.decimalPos]; | ||
@@ -556,21 +569,18 @@ } | ||
toFixed(digits: number, trimTrailingZeros?: boolean): string { | ||
if (!Number.isSafeInteger(digits) || digits < 0) throw new Error('Invalid parameter'); | ||
toFixed(decimals: number, roundingMode = RoundingMode.TO_ZERO): string { | ||
if (!Number.isSafeInteger(decimals) || decimals < 0) throw new Error('Invalid parameter'); | ||
const extraDigitsNeeded = digits - this.decimalPos; | ||
const exp = 10n ** BigInt(Math.abs(extraDigitsNeeded)); | ||
const num = extraDigitsNeeded < 0 ? this.number / exp : this.number * exp; | ||
const res = bigIntToStr(num, digits, Boolean(trimTrailingZeros)); | ||
return res; | ||
const rounded = this.round(decimals, roundingMode); | ||
return bigIntToStr(rounded.number, decimals, false); | ||
} | ||
toExponential(digits: number): string { | ||
toExponential(digits: number, roundingMode = RoundingMode.TO_ZERO): string { | ||
if (!Number.isSafeInteger(digits) || digits < 0) throw new Error('Invalid parameter'); | ||
const isNegative = this.number < 0n; | ||
const absNumber = isNegative ? -this.number : this.number; | ||
const str = absNumber.toString(); | ||
const rounded = this.roundToDigits(digits + 1, roundingMode).normalize(); | ||
const isNegative = rounded.sign() === -1; | ||
const absNumber = rounded.abs(); | ||
const str = absNumber.number.toString(); | ||
const slicedString = | ||
@@ -582,6 +592,7 @@ str.length <= digits ? `${str}${'0'.repeat(digits - str.length + 1)}` : str.slice(0, digits + 1); | ||
const fractionalDigitsBefore = this.decimalPos; | ||
const fractionalDigitsBefore = absNumber.decimalPos; | ||
const fractionalDigitsAfter = str.length - 1; | ||
const exponent = fractionalDigitsAfter - fractionalDigitsBefore; | ||
return `${isNegative ? '-' : ''}${strWithPoint}e${exponent >= 0 ? '+' : ''}${exponent}`; | ||
const res = `${isNegative ? '-' : ''}${strWithPoint}e${exponent >= 0 ? '+' : ''}${exponent}`; | ||
return res; | ||
} | ||
@@ -596,10 +607,6 @@ | ||
if (radix === 10) { | ||
return maxDigits === undefined ? this.toString() : this.toFixed(maxDigits, true); | ||
} | ||
const num = this.normalize(); | ||
if (num.decimalPos === 0) return num.number.toString(radix); | ||
const loopEnd = maxDigits === undefined ? Number.MAX_SAFE_INTEGER : maxDigits + 1; | ||
const loopEnd = maxDigits === undefined ? Number.MAX_SAFE_INTEGER : maxDigits; | ||
@@ -619,4 +626,2 @@ let intPart = num.intPart() as FixedNumber; | ||
while (!fracPart.isZero()) { | ||
if (digits.length === loopEnd) break; | ||
const mul = fracPart.mul(radix); | ||
@@ -631,2 +636,6 @@ const mulStr = mul.toString(); | ||
if (digits.length === loopEnd) { | ||
break; | ||
} | ||
const q = Math.abs(mul.intPart().toNumber()); | ||
@@ -639,6 +648,2 @@ digits.push(q.toString(radix)); | ||
if (digits.length === loopEnd) { | ||
digits.pop(); | ||
} | ||
return [isNegative ? '-' : '', intPart.number.toString(radix), digits.length ? '.' : '', ...digits].join(''); | ||
@@ -660,2 +665,10 @@ } | ||
toPrecision(digits: number, roundingMode = RoundingMode.TO_ZERO): string { | ||
if (!Number.isSafeInteger(digits) || digits < 1) throw new Error('Invalid parameter'); | ||
const rounded = this.roundToDigits(digits, roundingMode); | ||
const res = bigIntToStr(rounded.number, rounded.decimalPos, false); | ||
return res; | ||
} | ||
valueOf(): number { | ||
@@ -662,0 +675,0 @@ throw new Error('Unsafe conversion to Number type! Use toNumber() instead.'); |
import { Fraction } from './Fraction'; | ||
import { ModType, RoundingMode } from './types'; | ||
import { ExactNumberParameter, ModType, RoundingMode } from './types'; | ||
@@ -12,2 +12,5 @@ describe('Fraction', () => { | ||
expect(run('3/4')).toStrictEqual([3n, 4n]); | ||
expect(() => run('2.((4))')).toThrow('Cannot parse string "2.((4))"'); | ||
expect(() => run('2.(4')).toThrow('Cannot parse string "2.(4"'); | ||
}); | ||
@@ -41,2 +44,16 @@ | ||
it('initializes with other types', () => { | ||
const run = (x: any) => new Fraction(x, 1n).toString(); | ||
const errorMsg = 'Unsupported parameter!'; | ||
expect(() => run(false)).toThrow(errorMsg); | ||
expect(() => run(true)).toThrow(errorMsg); | ||
expect(() => run(null)).toThrow(errorMsg); | ||
expect(() => run(undefined)).toThrow(errorMsg); | ||
expect(() => run([])).toThrow(errorMsg); | ||
expect(() => run({})).toThrow(errorMsg); | ||
expect(() => run(/1/)).toThrow(errorMsg); | ||
}); | ||
it('toBase()', () => { | ||
@@ -80,3 +97,3 @@ const run = (a: string, radix: number) => new Fraction(a, 1n).toString(radix); | ||
expect(run('0/1')).toBe('0/1'); | ||
expect(run('0/100')).toBe('0/1'); | ||
expect(run('0/-100')).toBe('0/1'); | ||
expect(run('0/0.02')).toBe('0/1'); | ||
@@ -94,2 +111,4 @@ expect(run('6/3')).toBe('2/1'); | ||
expect(run('2/1', '3/1')).toBe('5/1'); | ||
expect(run('4/2', '5/2')).toBe('9/2'); | ||
expect(run('9/-2', '5/2')).toBe('-2/1'); | ||
expect(run('4/3', '5/2')).toBe('23/6'); | ||
@@ -103,2 +122,4 @@ expect(run('4/3', '-5/2')).toBe('-7/6'); | ||
expect(run('5/1', '2/1')).toBe('3/1'); | ||
expect(run('4/2', '5/2')).toBe('-1/2'); | ||
expect(run('9/-2', '5/2')).toBe('-7/1'); | ||
expect(run('4/3', '-5/2')).toBe('23/6'); | ||
@@ -114,4 +135,34 @@ expect(run('4/3', '5/2')).toBe('-7/6'); | ||
expect(run('4/3', '-5/4')).toBe('-5/3'); | ||
expect(run('4/-3', '-5/4')).toBe('5/3'); | ||
expect(run('-4/-3', '-5/4')).toBe('-5/3'); | ||
expect(run('4/3', '0/4')).toBe('0/1'); | ||
}); | ||
it('div()', () => { | ||
const run = (a: string, b: string) => new Fraction(a, 1n).div(b).toFraction(); | ||
expect(run('5/1', '2/1')).toBe('5/2'); | ||
expect(run('4/3', '5/4')).toBe('16/15'); | ||
expect(run('4/3', '-5/4')).toBe('-16/15'); | ||
expect(run('4/-6', '-5/8')).toBe('16/15'); | ||
expect(run('-4/-6', '-5/8')).toBe('-16/15'); | ||
expect(() => run('1', '0/1')).toThrow('Division by zero'); | ||
}); | ||
it('divToInt()', () => { | ||
const run = (a: ExactNumberParameter, b: ExactNumberParameter) => new Fraction(a, 1n).divToInt(b).toString(); | ||
expect(run('2/4', '4/8')).toBe('1'); | ||
expect(run('5/7', '1/3')).toBe('2'); | ||
expect(run('5/7', '1/4')).toBe('2'); | ||
expect(run('1', '-1')).toBe('-1'); | ||
expect(run('-1', '1')).toBe('-1'); | ||
expect(run('-1', '-1')).toBe('1'); | ||
expect(() => run('1', '0')).toThrow('Division by zero'); | ||
expect(() => run('0', '0')).toThrow('Division by zero'); | ||
}); | ||
it('mod()', () => { | ||
@@ -149,61 +200,75 @@ const run = (a: string | number, b: string | number, type?: ModType) => | ||
it('pow()', () => { | ||
const run = (a: ExactNumberParameter, b: ExactNumberParameter) => new Fraction(a, 1n).pow(b).toFraction(); | ||
expect(run('5', '3')).toBe('125/1'); | ||
expect(run('5', '0')).toBe('1/1'); | ||
expect(run('-5/7', '0')).toBe('1/1'); | ||
expect(run('-5/7', '2/2')).toBe('-5/7'); | ||
expect(run('4/-10', '4/2')).toBe('4/25'); | ||
expect(run('-5/7', '4/2')).toBe('25/49'); | ||
expect(() => run('-5/7', '-1')).toThrow('Unsupported parameter'); | ||
expect(() => run('2', '1/7')).toThrow('Unsupported parameter'); | ||
}); | ||
it('round()', () => { | ||
const run = (a: string, rndMode?: RoundingMode, digits?: number) => | ||
new Fraction(a, 1n).round(rndMode, digits).toFixed(digits ?? 0); | ||
const run = (a: string, decimals?: number, rndMode?: RoundingMode) => | ||
new Fraction(a, 1n).round(decimals, rndMode).toFixed(decimals ?? 0); | ||
expect(run('1/2', RoundingMode.NEAREST_AWAY_FROM_ZERO)).toBe('1'); | ||
expect(run('3/2', RoundingMode.NEAREST_AWAY_FROM_ZERO)).toBe('2'); | ||
expect(run('3/2', RoundingMode.NEAREST_TO_ZERO)).toBe('1'); | ||
expect(run('1/3', RoundingMode.NEAREST_AWAY_FROM_ZERO)).toBe('0'); | ||
expect(run('1/2', 0, RoundingMode.NEAREST_AWAY_FROM_ZERO)).toBe('1'); | ||
expect(run('3/2', 0, RoundingMode.NEAREST_AWAY_FROM_ZERO)).toBe('2'); | ||
expect(run('3/2', 0, RoundingMode.NEAREST_TO_ZERO)).toBe('1'); | ||
expect(run('1/3', 0, RoundingMode.NEAREST_AWAY_FROM_ZERO)).toBe('0'); | ||
expect(run('4/2', RoundingMode.TO_POSITIVE)).toBe('2'); | ||
expect(run('4/2', RoundingMode.TO_POSITIVE, 3)).toBe('2.000'); | ||
expect(run('4/2', 0, RoundingMode.TO_POSITIVE)).toBe('2'); | ||
expect(run('4/2', 3, RoundingMode.TO_POSITIVE)).toBe('2.000'); | ||
expect(run('40/20', RoundingMode.TO_POSITIVE)).toBe('2'); | ||
expect(run('41/20', RoundingMode.TO_POSITIVE)).toBe('3'); | ||
expect(run('41/20', RoundingMode.TO_POSITIVE, 1)).toBe('2.1'); | ||
expect(run('40/20', 0, RoundingMode.TO_POSITIVE)).toBe('2'); | ||
expect(run('41/20', 0, RoundingMode.TO_POSITIVE)).toBe('3'); | ||
expect(run('41/20', 1, RoundingMode.TO_POSITIVE)).toBe('2.1'); | ||
expect(run('2499/1000', RoundingMode.NEAREST_TO_POSITIVE)).toBe('2'); | ||
expect(run('2500/1000', RoundingMode.NEAREST_TO_POSITIVE)).toBe('3'); | ||
expect(run('2501/1000', RoundingMode.NEAREST_TO_NEGATIVE)).toBe('3'); | ||
expect(run('2499/1000', 0, RoundingMode.NEAREST_TO_POSITIVE)).toBe('2'); | ||
expect(run('2500/1000', 0, RoundingMode.NEAREST_TO_POSITIVE)).toBe('3'); | ||
expect(run('2501/1000', 0, RoundingMode.NEAREST_TO_NEGATIVE)).toBe('3'); | ||
expect(run('2499/1000', RoundingMode.NEAREST_TO_POSITIVE, 1)).toBe('2.5'); | ||
expect(run('2500/1000', RoundingMode.NEAREST_TO_POSITIVE, 1)).toBe('2.5'); | ||
expect(run('2501/1000', RoundingMode.NEAREST_TO_POSITIVE, 1)).toBe('2.5'); | ||
expect(run('2550/1000', RoundingMode.NEAREST_TO_NEGATIVE, 1)).toBe('2.5'); | ||
expect(run('2550/1000', RoundingMode.NEAREST_TO_POSITIVE, 1)).toBe('2.6'); | ||
expect(run('2555/1000', RoundingMode.NEAREST_TO_NEGATIVE, 1)).toBe('2.6'); | ||
expect(run('2499/1000', 1, RoundingMode.NEAREST_TO_POSITIVE)).toBe('2.5'); | ||
expect(run('2500/1000', 1, RoundingMode.NEAREST_TO_POSITIVE)).toBe('2.5'); | ||
expect(run('2501/1000', 1, RoundingMode.NEAREST_TO_POSITIVE)).toBe('2.5'); | ||
expect(run('2550/1000', 1, RoundingMode.NEAREST_TO_NEGATIVE)).toBe('2.5'); | ||
expect(run('2550/1000', 1, RoundingMode.NEAREST_TO_POSITIVE)).toBe('2.6'); | ||
expect(run('2555/1000', 1, RoundingMode.NEAREST_TO_NEGATIVE)).toBe('2.6'); | ||
}); | ||
it('roundToDigits()', () => { | ||
const run = (a: string, rndMode: RoundingMode, digits: number) => | ||
new Fraction(a, 1n).roundToDigits(rndMode, digits).toString(); | ||
const run = (a: string, digits: number, rndMode: RoundingMode) => | ||
new Fraction(a, 1n).roundToDigits(digits, rndMode).toString(); | ||
expect(run('0/1', RoundingMode.TO_ZERO, 2)).toBe('0'); | ||
expect(run('-0/1', RoundingMode.TO_ZERO, 3)).toBe('0'); | ||
expect(run('0/1', 2, RoundingMode.TO_ZERO)).toBe('0'); | ||
expect(run('-0/1', 3, RoundingMode.TO_ZERO)).toBe('0'); | ||
expect(run('1/1', RoundingMode.TO_POSITIVE, 1)).toBe('1'); | ||
expect(run('1/1', 1, RoundingMode.TO_POSITIVE)).toBe('1'); | ||
expect(run('-12345/1', RoundingMode.TO_ZERO, 1)).toBe('-10000'); | ||
expect(run('-12345/1', RoundingMode.TO_ZERO, 7)).toBe('-12345'); | ||
expect(run('-12345/1', 1, RoundingMode.TO_ZERO)).toBe('-10000'); | ||
expect(run('-12345/1', 7, RoundingMode.TO_ZERO)).toBe('-12345'); | ||
expect(run('123.45/1', RoundingMode.TO_ZERO, 1)).toBe('100'); | ||
expect(run('123.45/1', RoundingMode.TO_ZERO, 3)).toBe('123'); | ||
expect(run('-123.45/1', RoundingMode.TO_ZERO, 4)).toBe('-123.4'); | ||
expect(run('-123.45/1', RoundingMode.TO_ZERO, 5)).toBe('-123.45'); | ||
expect(run('123.45/1', RoundingMode.TO_ZERO, 6)).toBe('123.45'); | ||
expect(run('123.45/1', 1, RoundingMode.TO_ZERO)).toBe('100'); | ||
expect(run('123.45/1', 3, RoundingMode.TO_ZERO)).toBe('123'); | ||
expect(run('-123.45/1', 4, RoundingMode.TO_ZERO)).toBe('-123.4'); | ||
expect(run('-123.45/1', 5, RoundingMode.TO_ZERO)).toBe('-123.45'); | ||
expect(run('123.45/1', 6, RoundingMode.TO_ZERO)).toBe('123.45'); | ||
expect(run('129.000/1', RoundingMode.TO_ZERO, 2)).toBe('120'); | ||
expect(run('129.000/1', RoundingMode.TO_POSITIVE, 2)).toBe('130'); | ||
expect(run('129.000/1', RoundingMode.TO_ZERO, 6)).toBe('129'); | ||
expect(run('129.000/1', 2, RoundingMode.TO_ZERO)).toBe('120'); | ||
expect(run('129.000/1', 2, RoundingMode.TO_POSITIVE)).toBe('130'); | ||
expect(run('129.000/1', 6, RoundingMode.TO_ZERO)).toBe('129'); | ||
expect(run('0.0001234/1', RoundingMode.TO_ZERO, 1)).toBe('0.0001'); | ||
expect(run('-0.0001234/1', RoundingMode.TO_ZERO, 2)).toBe('-0.00012'); | ||
expect(run('0.0001234/1', 1, RoundingMode.TO_ZERO)).toBe('0.0001'); | ||
expect(run('-0.0001234/1', 2, RoundingMode.TO_ZERO)).toBe('-0.00012'); | ||
expect(run('45.452/1', RoundingMode.NEAREST_AWAY_FROM_ZERO, 1)).toBe('50'); | ||
expect(run('45.452/1', RoundingMode.NEAREST_AWAY_FROM_ZERO, 2)).toBe('45'); | ||
expect(run('45.452/1', RoundingMode.NEAREST_AWAY_FROM_ZERO, 3)).toBe('45.5'); | ||
expect(run('45.452/1', RoundingMode.NEAREST_AWAY_FROM_ZERO, 4)).toBe('45.45'); | ||
expect(run('45.452/1', RoundingMode.NEAREST_AWAY_FROM_ZERO, 5)).toBe('45.452'); | ||
expect(run('45.452/1', RoundingMode.NEAREST_AWAY_FROM_ZERO, 6)).toBe('45.452'); | ||
expect(run('45.452/1', 1, RoundingMode.NEAREST_AWAY_FROM_ZERO)).toBe('50'); | ||
expect(run('45.452/1', 2, RoundingMode.NEAREST_AWAY_FROM_ZERO)).toBe('45'); | ||
expect(run('45.452/1', 3, RoundingMode.NEAREST_AWAY_FROM_ZERO)).toBe('45.5'); | ||
expect(run('45.452/1', 4, RoundingMode.NEAREST_AWAY_FROM_ZERO)).toBe('45.45'); | ||
expect(run('45.452/1', 5, RoundingMode.NEAREST_AWAY_FROM_ZERO)).toBe('45.452'); | ||
expect(run('45.452/1', 6, RoundingMode.NEAREST_AWAY_FROM_ZERO)).toBe('45.452'); | ||
}); | ||
@@ -289,2 +354,9 @@ | ||
}); | ||
it('valueOf()', () => { | ||
const run = (x: string) => new Fraction(x, 1n).valueOf(); | ||
expect(() => run('0')).toThrow('Unsafe conversion to Number type! Use toNumber() instead.'); | ||
expect(() => run('2')).toThrow('Unsafe conversion to Number type! Use toNumber() instead.'); | ||
}); | ||
}); |
@@ -20,3 +20,3 @@ import { CommonNumberFields, ExactNumberType, ModType, RoundingMode } from './types'; | ||
if (!m) { | ||
throw new Error(`Cannot parse number "${x}"`); | ||
throw new Error(`Cannot parse string "${x}"`); | ||
} | ||
@@ -105,9 +105,9 @@ | ||
if (false) { | ||
const commonDenominator = this.lcm(this.denominator, denominator); | ||
const lMultiplier = commonDenominator / this.denominator; | ||
const rMultiplier = commonDenominator / denominator; | ||
// if (false) { | ||
// const commonDenominator = this.lcm(this.denominator, denominator); | ||
// const lMultiplier = commonDenominator / this.denominator; | ||
// const rMultiplier = commonDenominator / denominator; | ||
return new Fraction(this.numerator * lMultiplier + numerator * rMultiplier, commonDenominator); | ||
} | ||
// return new Fraction(this.numerator * lMultiplier + numerator * rMultiplier, commonDenominator); | ||
// } | ||
@@ -136,3 +136,3 @@ return new Fraction(this.numerator * denominator + numerator * this.denominator, denominator * this.denominator); | ||
const num = this.div(x); | ||
return num.round(); | ||
return num.trunc(); | ||
} | ||
@@ -167,5 +167,8 @@ | ||
pow(x: number | bigint | string | ExactNumberType): ExactNumberType { | ||
const { numerator, denominator } = this.parseParameter(x); | ||
if (denominator !== 1n) throw new Error('Unsupported parameter'); | ||
const res = new Fraction(this.numerator ** numerator, this.denominator ** numerator); | ||
const param = this.parseParameter(x); | ||
if (!param.isInteger() || param.sign() === -1) { | ||
throw new Error('Unsupported parameter'); | ||
} | ||
const intNum = param.numerator / param.denominator; | ||
const res = new Fraction(this.numerator ** intNum, this.denominator ** intNum); | ||
return res; | ||
@@ -182,3 +185,3 @@ } | ||
return this.round(RoundingMode.TO_NEGATIVE, decimals); | ||
return this.round(decimals, RoundingMode.TO_NEGATIVE); | ||
} | ||
@@ -189,3 +192,3 @@ | ||
return this.round(RoundingMode.TO_POSITIVE, decimals); | ||
return this.round(decimals, RoundingMode.TO_POSITIVE); | ||
} | ||
@@ -196,6 +199,6 @@ | ||
return this.round(RoundingMode.TO_ZERO, decimals); | ||
return this.round(decimals, RoundingMode.TO_ZERO); | ||
} | ||
round(roundingMode?: RoundingMode, decimals?: number) { | ||
round(decimals?: number, roundingMode?: RoundingMode): FixedNumber { | ||
decimals = decimals === undefined ? 0 : decimals; | ||
@@ -215,3 +218,3 @@ | ||
// nothing is lost | ||
return fixedPart.round(roundingMode, decimals); | ||
return fixedPart.round(decimals, roundingMode); | ||
} | ||
@@ -224,7 +227,7 @@ | ||
const res = correctedFixedNum.round(roundingMode, decimals); | ||
const res = correctedFixedNum.round(decimals, roundingMode); | ||
return res; | ||
} | ||
roundToDigits(roundingMode: RoundingMode, digits: number) { | ||
roundToDigits(digits: number, roundingMode: RoundingMode): FixedNumber { | ||
if (!Number.isSafeInteger(digits) || digits < 1) { | ||
@@ -234,3 +237,3 @@ throw new Error('Invalid value for digits'); | ||
if (this.isZero()) return this; | ||
if (this.isZero()) return new FixedNumber(0n); | ||
@@ -253,9 +256,5 @@ let x = this.abs(); | ||
let roundedNumber = x.round(roundingMode, digits); | ||
let roundedNumber = x.round(digits, roundingMode) as FixedNumber; | ||
if (divisions < 0) { | ||
roundedNumber = roundedNumber.div(10n ** BigInt(-divisions)) as FixedNumber; | ||
} else { | ||
roundedNumber = roundedNumber.mul(10n ** BigInt(divisions)) as FixedNumber; | ||
} | ||
roundedNumber = roundedNumber._incExponent(divisions); | ||
@@ -331,7 +330,7 @@ return this.sign() === -1 ? roundedNumber.neg() : roundedNumber; | ||
intPart(): ExactNumberType { | ||
intPart() { | ||
return this.trunc(); | ||
} | ||
fracPart(): ExactNumberType { | ||
fracPart() { | ||
return this.sub(this.trunc()); | ||
@@ -396,3 +395,3 @@ } | ||
serialize() { | ||
serialize(): [bigint, bigint] { | ||
return [this.numerator, this.denominator]; | ||
@@ -478,15 +477,7 @@ } | ||
// eslint-disable-next-line @typescript-eslint/no-shadow | ||
toFixed(digits: number, trimTrailingZeros?: boolean): string { | ||
if (!Number.isSafeInteger(digits) || digits < 0) throw new Error('Invalid parameter'); | ||
toFixed(decimals: number, roundingMode = RoundingMode.TO_ZERO): string { | ||
if (!Number.isSafeInteger(decimals) || decimals < 0) throw new Error('Invalid parameter'); | ||
let { numerator } = this; | ||
if (digits > 0) { | ||
numerator *= 10n ** BigInt(digits); | ||
} | ||
const n = numerator / this.denominator; | ||
const res = bigIntToStr(n, digits, Boolean(trimTrailingZeros)); | ||
return res; | ||
const [number, decimalPos] = this.round(decimals, roundingMode).serialize(); | ||
return bigIntToStr(number, decimalPos, false); | ||
} | ||
@@ -531,7 +522,7 @@ | ||
toExponential(digits: number): string { | ||
toExponential(digits: number, roundingMode = RoundingMode.TO_ZERO): string { | ||
if (!Number.isSafeInteger(digits) || digits < 0) throw new Error('Invalid parameters'); | ||
const fixedNum = this.toFixedNumber(digits); | ||
return fixedNum.toExponential(digits); | ||
return fixedNum.toExponential(digits, roundingMode); | ||
} | ||
@@ -559,3 +550,3 @@ | ||
if (radix === 10) { | ||
return maxDigits === undefined ? this.toRepeatingDigits(maxDigits) : this.toFixed(maxDigits, true); | ||
return maxDigits === undefined ? this.toRepeatingDigits(maxDigits) : trimTrailingZeros(this.toFixed(maxDigits)); | ||
} | ||
@@ -567,3 +558,3 @@ | ||
let intPart = num.intPart() as FixedNumber; | ||
let intPart = num.intPart(); | ||
let fracPart = num.sub(intPart); | ||
@@ -614,2 +605,9 @@ | ||
toPrecision(digits: number, roundingMode = RoundingMode.TO_ZERO): string { | ||
if (!Number.isSafeInteger(digits) || digits < 1) throw new Error('Invalid parameter'); | ||
const [number, decimalPos] = this.roundToDigits(digits, roundingMode).serialize(); | ||
return bigIntToStr(number, decimalPos, false); | ||
} | ||
valueOf(): number { | ||
@@ -616,0 +614,0 @@ throw new Error('Unsafe conversion to Number type! Use toNumber() instead.'); |
@@ -11,2 +11,3 @@ import * as API from '.'; | ||
'ExactNumberParameter', | ||
'trimTrailingZeros', | ||
'nthroot', | ||
@@ -13,0 +14,0 @@ 'sqrt', |
@@ -5,2 +5,4 @@ export { ExactNumber } from './ExactNumber'; | ||
export { trimTrailingZeros } from './util'; | ||
export * from './approx'; |
@@ -91,7 +91,7 @@ import { Fraction } from './Fraction'; | ||
/** Rounds current number to the specified amount of decimals. */ | ||
round(roundingMode?: RoundingMode, decimals?: number): ExactNumberType; | ||
/** Rounds current number to the specified amount of decimals. RoundingMode.NEAREST_TO_POSITIVE is the default */ | ||
round(decimals?: number, roundingMode?: RoundingMode): ExactNumberType; | ||
/** Rounds current number to the specified amount of significant digits. */ | ||
roundToDigits(roundingMode: RoundingMode, digits: number): ExactNumberType; | ||
roundToDigits(digits: number, roundingMode: RoundingMode): ExactNumberType; | ||
@@ -143,3 +143,3 @@ /** Returns the integer bitwise-and combined with another integer. */ | ||
* By default it simplifies the fraction */ | ||
getFractionParts(normalize: boolean): { numerator: ExactNumberType; denominator: ExactNumberType }; | ||
getFractionParts(normalize?: boolean): { numerator: ExactNumberType; denominator: ExactNumberType }; | ||
@@ -150,12 +150,15 @@ /** Returns opimized internal representation of the current number (e.g. it simplifies fractions using GCD) | ||
/** Returns a string representing the number using fixed-point notation. */ | ||
toFixed(digits: number, trimTrailingZeros?: boolean): string; | ||
/** Returns a string representing the number using fixed-point notation, rounded to the specified number of decimals. */ | ||
toFixed(decimals: number, roundingMode?: RoundingMode): string; | ||
/** Returns a string representing the number in exponential notation. */ | ||
toExponential(digits: number): string; | ||
toExponential(digits: number, roundingMode?: RoundingMode): string; | ||
/** Returns a string representing the number using fixed-point notation, rounded to the specified number of significant digits. In contrary to JS Number.toPrecision(), this function never returns exponential notation. */ | ||
toPrecision(digits: number, roundingMode?: RoundingMode): string; | ||
/** Converts current value to a JavaScript Number */ | ||
toNumber(): number; | ||
/** Returns string representation of the current number in a fractional format like 1/2. It always simplifies the fraction before output. */ | ||
/** Returns string representation of the current number in a fractional format like "1/2". It always simplifies the fraction before output. */ | ||
toFraction(): string; | ||
@@ -162,0 +165,0 @@ |
@@ -0,1 +1,2 @@ | ||
/** Trims trailing zeros from numbers in fixed-point format (1.23000 -> 1.23) */ | ||
export const trimTrailingZeros = (num: string): string => { | ||
@@ -37,12 +38,12 @@ let zeropos = num.length; | ||
export const modpow = (base: bigint, exp: bigint, mod: bigint) => { | ||
let res = 1n; | ||
while (exp > 0n) { | ||
if (exp % 2n) { | ||
res = (res * base) % mod; | ||
} | ||
base = base ** 2n % mod; | ||
exp /= 2n; | ||
} | ||
return res; | ||
}; | ||
// export const modpow = (base: bigint, exp: bigint, mod: bigint) => { | ||
// let res = 1n; | ||
// while (exp > 0n) { | ||
// if (exp % 2n) { | ||
// res = (res * base) % mod; | ||
// } | ||
// base = base ** 2n % mod; | ||
// exp /= 2n; | ||
// } | ||
// return res; | ||
// }; |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
335575
70
7082