exactnumber
Advanced tools
Comparing version 0.11.0 to 1.0.0
@@ -0,1 +1,10 @@ | ||
## 1.0.0 (November 05, 2022) | ||
- Add modular exponentiation - `powm()` | ||
- Do not expose `trimTrailingZeros()` anymore. Zero trimming is still available through the third parameter at toFixed(), toExponential() and toPrecision() | ||
- Radian angles handled more precisely. Trigonometric functions now provide exact results for expressions like `sin(PI/6)=0.5` | ||
- Not using BigInt literals anymore, because they are not compatible with some FE frameworks | ||
- Performance improvements by memoizing common BigInt values | ||
- Fixed bug with zeros not being trimmed corectly | ||
## 0.11.0 (October 29, 2022) | ||
@@ -2,0 +11,0 @@ |
/*! | ||
* exactnumber v0.11.0 (https://www.npmjs.com/package/exactnumber) | ||
* exactnumber v1.0.0 (https://www.npmjs.com/package/exactnumber) | ||
* (c) Dani Biro | ||
@@ -7,2 +7,2 @@ * @license MIT | ||
var t,n;!function(t){t[t.NEAREST_TO_POSITIVE=201008]="NEAREST_TO_POSITIVE",t[t.NEAREST_TO_NEGATIVE=201009]="NEAREST_TO_NEGATIVE",t[t.NEAREST_TO_EVEN=201010]="NEAREST_TO_EVEN",t[t.NEAREST_TO_ZERO=201011]="NEAREST_TO_ZERO",t[t.NEAREST_AWAY_FROM_ZERO=201012]="NEAREST_AWAY_FROM_ZERO",t[t.TO_POSITIVE=201001]="TO_POSITIVE",t[t.TO_NEGATIVE=201002]="TO_NEGATIVE",t[t.TO_ZERO=201003]="TO_ZERO",t[t.AWAY_FROM_ZERO=201004]="AWAY_FROM_ZERO"}(t||(t={})),function(t){t.TRUNCATED="T",t.FLOORED="F",t.EUCLIDEAN="E"}(n||(n={}));const r=t=>{const n=t.indexOf(".");if(-1===n)return t;let r=t.length;for(;r>n&&"0"===t.charAt(r-1);)r--;const e=n===r-1?n:r;return 0===e?"0":t.slice(0,e)},e=(t,n,e,i)=>{let o=t.toString();if(0===n&&0===e)return o;const s=o.startsWith("-");if(s&&(o=o.slice(1)),n>=o.length&&(o="0".repeat(n-o.length+1)+o),n>0){const t=o.slice(0,-n),s=o.slice(-n),u=e<=n?s.slice(0,e):`${s}${"0".repeat(e-n)}`;0!==u.length?(o=`${t}.${u}`,i&&(o=r(o))):o=t}else e>0&&(o=`${o}.${"0".repeat(e)}`);return s?`-${o}`:o},i=(n,r)=>(n=n.normalize())instanceof o?n.round(r,t.NEAREST_AWAY_FROM_ZERO):n;class o{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 o)return{number:t.number,decimalPos:t.decimalPos};if(t instanceof s){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=u(t);if(n instanceof s)return n.add(this);const r=n,{a:e,b:i,decimalPos:a}=this.scaleNumber(r.number,r.decimalPos);return new o(e+i,a)}sub(t){const n=u(t);return this.add(n.neg())}mul(t){const n=u(t);if(n instanceof s)return n.mul(this);const r=n,e=this.number*r.number;return new o(e,this.decimalPos+r.decimalPos)}pow(t){const n=u(t).toNumber();if(!Number.isSafeInteger(n))throw new Error("Unsupported parameter");const r=Math.abs(n),e=new o(this.number**BigInt(r),this.decimalPos*r);return n<0?e.inv():e}div(t){return this.convertToFraction().div(t)}divToInt(t){const n=u(t);if(n instanceof s)return this.convertToFraction().divToInt(n);const r=n,{a:e,b:i}=this.scaleNumber(r.number,r.decimalPos);return new o(e/i)}mod(t,r=n.TRUNCATED){const e=u(t);if(e instanceof s)return this.convertToFraction().mod(e);const i=e,{a:a,b:c,decimalPos:m}=this.scaleNumber(i.number,i.decimalPos),h=a%c,l=new o(h,m);if(r===n.TRUNCATED)return l;if(r===n.FLOORED)return Number(a<0)^Number(c<0)?l.add(c):l;if(r===n.EUCLIDEAN)return h<0?l.add(c<0?-c:c):l;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(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)}isTieStr(t){if("5"!==t[0])return!1;for(let n=1;n<t.length;n++)if("0"!==t[n])return!1;return!0}_round(n,r){const e=this.decimalPos-n;if(e<=0)return this;const i=10n**BigInt(e),s=this.number/i;if(r===t.TO_ZERO)return new o(s,n);const u=this.number%i;if(0n===u)return new o(s,n);if(r===t.AWAY_FROM_ZERO){const t=this.number<0n?s-1n:s+1n;return new o(t,n)}if(r===t.TO_POSITIVE){const t=this.number<0n?s:s+1n;return new o(t,n)}if(r===t.TO_NEGATIVE){const t=this.number>=0n?s:s-1n;return new o(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 a=(u<0n?-u:u).toString();if(a.length<e&&(a="0"),this.isTieStr(a)){if(r===t.NEAREST_TO_ZERO)return new o(s,n);if(r===t.NEAREST_AWAY_FROM_ZERO){const t=this.number<0n?s-1n:s+1n;return new o(t,n)}if(void 0===r||r===t.NEAREST_TO_POSITIVE){const t=this.number<0n?s:s+1n;return new o(t,n)}if(r===t.NEAREST_TO_NEGATIVE){const t=this.number>=0n?s:s-1n;return new o(t,n)}if(r===t.NEAREST_TO_EVEN){if(s%2n===0n)return new o(s,n);return new o(s<0n?s-1n:s+1n,n)}}if(Number(a[0])<5)return new o(s,n);const c=this.number<0?s-1n:s+1n;return new o(c,n)}round(t,n){if(t=void 0===t?0:t,!Number.isSafeInteger(t)||t<0)throw new Error("Invalid value for decimals");return this._round(t,n).normalize()}_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 o(n,r)}countDigits(){if(0n===this.number)return 1;let t=0,n=this.number<0?-this.number:this.number;for(;n>0n;)n/=10n,t++;return t}toSubZeroNum(){const t=this.countDigits();return{subZeroNum:new o(this.number,t),exponentDiff:t-this.decimalPos}}roundToDigits(t,n){if(!Number.isSafeInteger(t)||t<1)throw new Error("Invalid value for digits");const{subZeroNum:r,exponentDiff:e}=this.toSubZeroNum();let i=r.round(t,n);return i=i._incExponent(e),i}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 s&&(t=t.trunc());const n=2n**24n;let r=this.normalize().number,e=t.trunc().normalize().number,i=0n,u=1n;for(;r>0&&e>0;){const t=BigInt.asUintN(24,r),o=BigInt.asUintN(24,e);i+=BigInt(Number(t)&Number(o))*u,u*=n,r/=n,e/=n}return new o(i)}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 s&&(t=t.trunc());const n=2n**24n;let r=this.normalize().number,e=t.trunc().normalize().number,i=0n,u=1n;for(;r>0||e>0;){const t=BigInt.asUintN(24,r),o=BigInt.asUintN(24,e);i+=BigInt(Number(t)|Number(o))*u,u*=n,r/=n,e/=n}return new o(i)}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 s&&(t=t.trunc());const n=2n**24n;let r=this.normalize().number,e=t.trunc().normalize().number,i=0n,u=1n;for(;r>0||e>0;){const t=BigInt.asUintN(24,r),o=BigInt.asUintN(24,e);i+=BigInt(Number(t)^Number(o))*u,u*=n,r/=n,e/=n}return new o(i)}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 o(this.normalize().number/n)}cmp(t){const n=u(t);if(n instanceof s)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 o(n,t)}convertToFraction(){if(0===this.decimalPos)return new s(this.number,1n);const t=10n**BigInt(this.decimalPos);return new s(this.number,t)}toNumber(){return Number(this.toPrecision(20))}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,i.decimalPos,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(),u=s.length<=n?`${s}${"0".repeat(n-s.length+1)}`:s.slice(0,n+1),a=u.length>1?`${u.slice(0,1)}.${u.slice(1)}`:u,c=o.decimalPos,m=s.length-1-c;return`${i?"-":""}${a}e${m>=0?"+":""}${m}`}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 u=new Map;let a=[];for(;!o.isZero();){const n=o.mul(t),r=n.toString(),i=u.get(r);if(void 0!==i){a=[...a.slice(0,i-1),"(",...a.slice(i-1),")"];break}if(a.length===e)break;const s=Math.abs(n.intPart().toNumber());a.push(s.toString(t)),o=n.fracPart(),u.set(r,a.length)}return[s?"-":"",i.number.toString(t),a.length?".":"",...a].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,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),{subZeroNum:o,exponentDiff:s}=i.toSubZeroNum(),u=-1===o.sign();let a=e(o.number,o.decimalPos,o.decimalPos,!1);a=a.slice(u?3:2),a=a.slice(0,Math.max(n,s));const c=a.slice(0,Math.max(0,s)),m=a.slice(Math.max(0,s)),h=Math.max(0,n-c.length-m.length),l="0".repeat(h),d="0".repeat(s<0?-s:0);let f=c||"0";return m.length+d.length+h>0&&(f+=`.${d}${m}${l}`),u?`-${f}`:f}valueOf(){throw new Error("Unsafe conversion to Number type! Use toNumber() instead.")}}class s{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),i=r.div(e),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(t){if(!t.includes("("))return new o(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]??"",i=n[3],u=n[4],a=BigInt(r+e+i)-BigInt(r+e),c=BigInt("9".repeat(i.length)+"0".repeat(e.length)),m=new s(a,c);if(void 0!==u){const t=u.startsWith("-"),n=10n**BigInt(t?u.slice(1):u);return t?m.div(n).normalize():m.mul(n).normalize()}return m.simplify()}parseParameter(t){if(t instanceof s)return t;if(t instanceof o)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 s(BigInt(t),1n)}if("bigint"==typeof t)return new s(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 s(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 s(this.numerator+n,this.denominator):new s(this.numerator*r+n*this.denominator,r*this.denominator)}sub(t){const{numerator:n,denominator:r}=this.parseParameter(t);return this.add(new s(-n,r))}mul(t){const{numerator:n,denominator:r}=this.parseParameter(t);return new s(this.numerator*n,this.denominator*r)}div(t){const{numerator:n,denominator:r}=this.parseParameter(t);return this.mul(new s(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),o=this.denominator*e.denominator,u=new s(i,o);if(r===n.TRUNCATED)return u;if(r===n.FLOORED)return Number(-1===this.sign())^Number(-1===e.sign())?u.add(e):u;if(r===n.EUCLIDEAN)return u.sign()<0?u.add(e.sign()<0?e.neg():e):u;throw new Error("Invalid ModType")}pow(t){const n=this.parseParameter(t);if(!n.isInteger())throw new Error("Unsupported parameter");const r=n.numerator/n.denominator,e=r<0?-r:r,i=new s(this.numerator**e,this.denominator**e);return r<0?i.inv():i}inv(){return new s(this.denominator,this.numerator)}floor(n){return 1n===this.denominator?new o(this.numerator):this.round(n,t.TO_NEGATIVE)}ceil(n){return 1n===this.denominator?new o(this.numerator):this.round(n,t.TO_POSITIVE)}trunc(n){return 1n===this.denominator?new o(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 o(`${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 o(0n);let r=this.abs(),e=0;for(;r.gte(1n);)r=r.div(10n),e++;const i=new s(1n,10n);for(;r.lt(i);)r=r.mul(10n),e--;let u=r.round(t,n);return u=u._incExponent(e),-1===this.sign()?u.neg():u}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}}simplify(){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 s(t,n)}normalize(){const{numerator:n,denominator:r}=this.simplify();if(1n===r)return new o(n,0);const e=new s(n,r),{cycleLen:i,cycleStart:u}=e.getDecimalFormat(0);return 0!==i?e:e.round(u,t.TO_ZERO)}getFractionParts(t=!0){const n=t?this.simplify():this;return{numerator:new o(n.numerator),denominator:new o(n.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(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.toPrecision(20))}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,u=1;for(;1n!==s;){if(u===o)return{cycleLen:null,cycleStart:i};s=10n*s%n,u++}return{cycleLen:u,cycleStart:i}}toFixed(n,r=t.TO_ZERO){if(!Number.isSafeInteger(n)||n<0)throw new Error("Invalid parameter");return this.round(n,r).toFixed(n)}toRepeatingParts(t){if(this.isZero())return["0","",""];const{cycleLen:n,cycleStart:e}=this.simplify().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.getFractionParts(!0);return`${t.toString()}/${n.toString()}`}toFixedNumber(t){const n=this.numerator*10n**BigInt(t);return new o(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 u=-1===e.sign();u&&(o=o.neg(),s=s.neg());const a=new Map;let c=[];for(;!s.isZero()&&c.length!==i;){const n=s.mul(t),r=n.normalize().toFraction(),e=a.get(r);if(void 0!==e){c=[...c.slice(0,e-1),"(",...c.slice(e-1),")"];break}const i=Math.abs(n.intPart().toNumber());c.push(i.toString(t)),s=n.fracPart(),a.set(r,c.length)}return c.length===i&&c.pop(),[u?"-":"",o.toString(t),c.length?".":"",...c].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");return this.roundToDigits(n,r).toPrecision(n)}valueOf(){throw new Error("Unsafe conversion to Number type! Use toNumber() instead.")}}function u(t){if(t instanceof o||t instanceof s)return t;if("bigint"==typeof t)return new o(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 o(t)}if("string"==typeof t)return t.includes("/")||t.includes("(")?new s(t,1n):new o(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=u(t);if(void 0===n)return r;const e=u(n);return new s(r,1n).div(new s(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 c=(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]??"",o=e[2]??"",u=e[3]??"";if(u.length>0){const t=c([i,o,u].join(""),n)-c([i,o].join(""),n),e=c((n-1).toString(n).repeat(u.length)+"0".repeat(o.length),n),a=new s(t,e).normalize();return r?a.neg():a}const m=c(i,n),h=c(o,n),l=new s(h,BigInt(n)**BigInt(o.length)),d=new s(m,1n).add(l).normalize();return r?d.neg():d},a.range=function*(t,n,r){const e=a(n),i=a(r??1);let o=a(t);for(;o.lt(e);)yield o,o=o.add(i)},a.gcd=(t,n)=>{const r=a(t).abs(),e=a(n).abs();let i=e.gt(r)?e:r,o=i.eq(r)?e:r;for(;;){if(o.isZero())return i;if(i=i.mod(o),i.isZero())return o;o=o.mod(i)}},a.lcm=(t,n)=>{const r=a(t).abs(),e=a(n).abs(),i=r.mul(e);if(i.isZero())throw new Error("LCM of zero is undefined");const o=a.gcd(r,e);return i.div(o)};const m=(t,n,r)=>{const e=((t,n)=>{let r=n.toNumber();if(Number.isFinite(r)){const n=r<0;n&&(r=-r);let e=r**(1/t);return n&&(e=-e),e.toString()}const e=n.abs().toFixed(0).length,i=Math.ceil(e/t);return`${1===n.sign()?"":"-"}5e${i}`})(t,n);let i=new o("0"!==e?e:"1");const u=new s(t-1,t),a=new s(n,t),c=BigInt(t-1);let m=i.trunc(r+5);for(;i=u.mul(i).add(a.mul(i.pow(c).inv())),i=i.trunc(r+5),!i.isZero()&&!m.eq(i);)m=i;return i.trunc(r)},h=(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");const e=i(a(n),r);if(1===t)return e.trunc(r);if(t%2==0&&-1===e.sign())throw new Error("Complex numbers are not supported");if(e.isZero())return new o(0n).trunc(r);if(e.isOne())return new o(1n).trunc(r);return m(t,e,r)},l=(t,n)=>h(2,t,n),d=(t,n)=>h(3,t,n);class f{constructor(t,n){this.cachedDecimals=0,this.fn=t,this.max=n}get(t){if(t<=this.cachedDecimals)return this.cache.trunc(t);const n=new o(this.fn(t)),r=Math.min(this.max,t);return this.cachedDecimals!==r&&(this.cache=n.trunc(r),this.cachedDecimals=r),n}}const g=(t,n)=>{let r=i(a(t),n);if(r.isOne())return new o(0).trunc(n);if(r.lte(0n))throw new Error("Invalid parameter");let e=0;const s=a("0.1");for(;r.sub(1n).abs().gt(s);)r=new o(l(r,n+10)),e++;const u=function*(t,n){const r=t.pow(2n).normalize();let e=t,i=1n,o=a(t);for(;;){e=e.mul(r),i+=2n;const t=e.div(i).trunc(n+10);o=o.add(t),yield{term:t,sum:o}}}(r.sub(1n).div(r.add(1n)),n);for(const{term:t,sum:r}of u)if(t.isZero()){return r.mul(2n**BigInt(e+1)).trunc(n)}return a(0)},w=(t,n,r)=>{if(!Number.isSafeInteger(t)||t<2)throw new Error("Invalid parameter for N");const e=g(n,r+10),i=g(t,r+10);return new o(e).div(i).trunc(r)},b=new f((t=>g(2n,t)),200),E=(t,n)=>new o(g(t,n+10)).div(b.get(n+10)).trunc(n),p=new f((t=>g(10n,t)),200),N=(t,n)=>new o(g(t,n+10)).div(p.get(n+10)).trunc(n);const I=(t,n)=>{const r=i(a(t),n),e=a(`1e-${n+5}`),o=function*(t,n){let r=t.add(1n),e=6n,i=4n;const o=t.pow(2n);let s=o;for(;;){const u=s.mul(t.add(i-1n)).div(e);e*=i*(i+1n),i+=2n,s=s.mul(o),r=r.add(u).trunc(n+5),yield{term:u,sum:r}}}(r,n);for(const{term:t,sum:r}of o)if(t.abs().lt(e))return r.trunc(n);return a(0)},v=(t,n,r)=>{const e=i(a(t),r),o=i(a(n),r);if(o.isInteger()&&Number.isSafeInteger(o.toNumber()))return e.pow(o).trunc(r);if(-1===e.sign()&&!o.isInteger())throw new Error("Complex numbers are not supported");const s=g(e,r+5),u=o.mul(s);return I(u,r+5).trunc(r)},O=new f((t=>{if(0===t)return a(3n);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 a(`3.${e.toString().slice(1,t+1)}`)}),1e3),T=t=>0===t?a(3):O.get(t).trunc(t),P=(n,r)=>{const e=new o(T(r+5)),i=e.mul(2n);let s=n.round(r+5,t.NEAREST_AWAY_FROM_ZERO).div(i).fracPart();s.lt(0n)&&(s=s.add(1n)),s=s.round(r+5);const u=s.div("0.25").floor().toNumber()+1;let c=i.mul(s),m=s.mul(360n);return 4===u?(c=i.sub(c),m=a(360).sub(m)):3===u?(c=c.sub(e),m=m.sub(180)):2===u&&(c=e.sub(c),m=a(180).sub(m)),{quadrantDegrees:m.round(r),quadrant:u,subHalfPiAngle:c}};const _=(t,n,r)=>{let e=a(t);return n&&(e=e.neg()),e.trunc(r)},S=(n,r)=>{const e=r+10,o=i(a(n),r+5),{quadrantDegrees:s,subHalfPiAngle:u,quadrant:c}=P(o,r),m=2===c||3===c;if(s.isZero())return _("1",m,r);if(s.eq(30n))return _(a(l(3n,r+5)).div(2n),m,r);if(s.eq(45n))return _(a(l(2n,r+5)).div(2n),m,r);if(s.eq(60n))return _("0.5",m,r);if(s.eq(90n))return _("0",m,r);const h=a(`1e-${e}`),d=function*(n,r){const e=n.round(r+10,t.NEAREST_AWAY_FROM_ZERO).pow(2n);let i=e,o=2n,s=a(1n).sub(i.div(o).trunc(r+10)),u=3n;for(;;){o*=u*(u+1n),u+=2n;const t=u*(u+1n);u+=2n,i=i.mul(e),o*=t;let n=i.mul(t);i=i.mul(e),n=n.sub(i);const a=n.div(o).trunc(r+10);s=s.add(a),yield{term:a,sum:s}}}(u,r);for(const{term:t,sum:n}of d)if(t.lt(h))return _(n,m,r);return a(0)},R=(t,n)=>{const r=new o(T(n+10)),e=i(a(t),n+5);return S(r.div(2n).sub(e),n+5).trunc(n)},A=(t,n)=>{const r=i(a(t),n+5),{quadrantDegrees:e,quadrant:o,subHalfPiAngle:s}=P(r,n+5),u=1===o||3===o;if(e.isZero())return _("0",u,n);if(e.eq(30n))return _(a(1n).div(l(3n,n+5)),u,n);if(e.eq(45n))return _("1",u,n);if(e.eq(60n))return _(l(3n,n+5),u,n);if(e.eq(90n))throw new Error("Out of range");const c=a(S(s.mul(2n),n+5)),m=a(1n).sub(c).div(a(1n).add(c)).round(n+5),h=l(m,n+5).trunc(n);return u?h:h.neg()};const F=(t,n)=>{let r=i(a(t),n);if(r.isZero())return a(0);if(r.abs().isOne())return a(T(n)).div(4*r.sign()).trunc(n);let e=0;const o=a("0.42");for(;r.abs().gt(o);){const t=a(l(r.pow(2n).add(1n),n+10));r=r.div(t.add(1n)),e++}const s=a(`1e-${n+10}`),u=function*(t,n){const r=t.pow(2n).normalize(),e=r.pow(2n).normalize();let i=3n,o=t.sub(t.mul(r).div(i)),s=t.mul(e);for(;;){i+=2n;const t=i+2n,u=s.mul(r.mul(-i).add(t)).div(i*t);i=t,s=s.mul(e),o=o.add(u).trunc(n+10),yield{term:u,sum:o}}}(r,n);for(const{term:t,sum:r}of u)if(t.abs().lt(s)){return r.mul(2n**BigInt(e)).trunc(n)}return a(0)},y=(t,n)=>{const r=i(a(t),n);if(r.isZero())return a(0);if(r.abs().isOne())return a(T(n)).mul(r.sign()).div(2n).trunc(n);if(r.abs().eq("1/2"))return a(T(n)).mul(r.sign()).div(6n).trunc(n);if(r.gt(1n)||r.lt(-1n))throw new Error("Out of range");const e=a(l(r.pow(2n).neg().add(1),n+10));return a(F(r.div(e.add(1n)),n+10)).mul(2).trunc(n)},Z=(t,n)=>{const r=i(a(t),n);if(r.isZero())return a(T(n)).div(2n).trunc(n);if(r.isOne())return a(0);if(r.abs().isOne())return T(n);if(r.abs().eq("1/2")){const t=a(T(n)).div(3n);return-1===r.sign()?t.mul(2n).trunc(n):t.trunc(n)}if(r.gt(1n)||r.lt(-1n))throw new Error("Out of range");return a(T(n+10)).div(2n).sub(y(r,n+10)).trunc(n)};const B=(t,n)=>{const r=i(a(t),n),e=new o(`1e-${n+5}`),s=function*(t,n){let r=t,e=1n;const i=t.pow(2n).normalize();let o=t.trunc(n+5),s=2n;for(;;){r=r.mul(i),e*=s*(s+1n),s+=2n;const t=r.div(e);o=o.add(t).trunc(n+5),yield{term:t,sum:o}}}(r,n);for(const{term:t,sum:r}of s)if(t.abs().lt(e))return r.trunc(n);return a(0)};const x=(t,n)=>{const r=i(a(t),n),e=new o(`1e-${n+5}`),s=function*(t,n){const r=t.pow(2n).normalize();let e=r,i=2n,o=e.div(i).add(1n).trunc(n+5),s=3n;for(;;){e=e.mul(r),i*=s*(s+1n),s+=2n;const t=e.div(i);o=o.add(t).trunc(n+5),yield{term:t,sum:o}}}(r,n);for(const{term:t,sum:r}of s)if(t.abs().lt(e))return r.trunc(n);return a(0)},$=(t,n)=>{const r=i(a(t),n);if(r.isZero())return a(0);const e=x(r,n+10).abs();return l(e.pow(2).sub(1),n+10).div(e).mul(r.sign()).trunc(n)},D=(t,n)=>{const r=i(a(t),n);if(r.isZero())return a(0);const e=l(r.pow(2).add(1n),n+5);return g(r.add(e),n+5).trunc(n)},M=(t,n)=>{const r=i(a(t),n);if(r.isOne())return a(0);if(r.lt(1n))throw new Error("Out of range");const e=l(r.pow(2).sub(1n),n+5);return g(r.add(e),n+5).trunc(n)},z=(t,n)=>{const r=i(a(t),n);if(r.abs().gte(1n))throw new Error("Out of range");if(r.isZero())return a(0);const e=g(r.add(1n).div(r.neg().add(1n)),n+5);return a(e).div(2n).trunc(n)};export{a as ExactNumber,n as ModType,T as PI,t as RoundingMode,Z as acos,M as acosh,y as asin,D as asinh,F as atan,z as atanh,d as cbrt,S as cos,x as cosh,I as exp,g as log,N as log10,E as log2,w as logn,h as nthroot,v as pow,R as sin,B as sinh,l as sqrt,A as tan,$ as tanh,r as trimTrailingZeros}; | ||
var t,r;!function(t){t[t.NEAREST_TO_POSITIVE=201008]="NEAREST_TO_POSITIVE",t[t.NEAREST_TO_NEGATIVE=201009]="NEAREST_TO_NEGATIVE",t[t.NEAREST_TO_EVEN=201010]="NEAREST_TO_EVEN",t[t.NEAREST_TO_ZERO=201011]="NEAREST_TO_ZERO",t[t.NEAREST_AWAY_FROM_ZERO=201012]="NEAREST_AWAY_FROM_ZERO",t[t.TO_POSITIVE=201001]="TO_POSITIVE",t[t.TO_NEGATIVE=201002]="TO_NEGATIVE",t[t.TO_ZERO=201003]="TO_ZERO",t[t.AWAY_FROM_ZERO=201004]="AWAY_FROM_ZERO"}(t||(t={})),function(t){t.TRUNCATED="T",t.FLOORED="F",t.EUCLIDEAN="E"}(r||(r={}));const e=t=>{const r=t.indexOf(".");if(-1===r)return t;let e=t.length;for(;e>r&&"0"===t.charAt(e-1);)e--;const n=r===e-1?r:e;return 0===n?"0":t.slice(0,n)},n=(t,r,n,i)=>{let o=t.toString();if(0===r&&0===n)return o;const s=o.startsWith("-");if(s&&(o=o.slice(1)),r>=o.length&&(o="0".repeat(r-o.length+1)+o),r>0){const t=o.slice(0,-r),s=o.slice(-r),u=n<=r?s.slice(0,n):`${s}${"0".repeat(n-r)}`;0!==u.length?(o=`${t}.${u}`,i&&(o=e(o))):o=t}else n>0&&!i&&(o=`${o}.${"0".repeat(n)}`);return s?`-${o}`:o},i=(r,e)=>(r=r.normalize())instanceof d?r.round(e,t.NEAREST_AWAY_FROM_ZERO):r,o=BigInt(0),s=BigInt(1),u=BigInt(2),a=BigInt(3),c=BigInt(4),m=BigInt(5),h=BigInt(10),l=BigInt(24);class d{constructor(t,r=0){if(this.type="fixed","bigint"==typeof t)this.number=t,this.decimalPos=r;else{const r=this.parseConstructorParameter(t);this.number=r.number,this.decimalPos=r.decimalPos}}parseConstructorParameter(t){if(t instanceof d)return{number:t.number,decimalPos:t.decimalPos};if(t instanceof f){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 r=t.match(/^(-?[0-9]*)(?:\.([0-9]*))?(?:[eE]([+-]?[0-9]+))?$/);if(!r)throw new Error(`Cannot parse number "${t}"`);let e=0,n=r[1]??"0";if(void 0!==r[2]&&(n+=r[2],e+=r[2].length),void 0!==r[3]){const t=Number(r[3]);t>0?n+="0".repeat(t):e-=t}return{number:BigInt(n),decimalPos:e}}throw new Error("Unsupported parameter!")}scaleNumber(t,r){const e=Math.max(this.decimalPos,r);return{a:e===this.decimalPos?this.number:this.number*h**BigInt(e-this.decimalPos),b:e===r?t:t*h**BigInt(e-r),decimalPos:e}}add(t){const r=g(t);if(r instanceof f)return r.add(this);const e=r,{a:n,b:i,decimalPos:o}=this.scaleNumber(e.number,e.decimalPos);return new d(n+i,o)}sub(t){const r=g(t);return this.add(r.neg())}mul(t){const r=g(t);if(r instanceof f)return r.mul(this);const e=r,n=this.number*e.number;return new d(n,this.decimalPos+e.decimalPos)}pow(t){const r=g(t).toNumber();if(!Number.isSafeInteger(r))throw new Error("Unsupported parameter");const e=Math.abs(r),n=new d(this.number**BigInt(e),this.decimalPos*e);return r<0?n.inv():n}powm(t,r,e){let n=g(t).toNumber();if(!Number.isSafeInteger(n))throw new Error("Unsupported parameter");const i=g(r);let o=this,a=new d(s);for(;0!==n;)n%2!=0&&(a=a.mul(o).mod(i,e)),o=o.pow(u).mod(i,e),n=Math.floor(n/2);return a}div(t){return this.convertToFraction().div(t)}divToInt(t){const r=g(t);if(r instanceof f)return this.convertToFraction().divToInt(r);const e=r,{a:n,b:i}=this.scaleNumber(e.number,e.decimalPos);return new d(n/i)}mod(t,e=r.TRUNCATED){const n=g(t);if(n instanceof f)return this.convertToFraction().mod(n);const i=n,{a:s,b:u,decimalPos:a}=this.scaleNumber(i.number,i.decimalPos),c=s%u,m=new d(c,a);if(e===r.TRUNCATED)return m;if(e===r.FLOORED)return Number(s<o)^Number(u<o)?m.add(u):m;if(e===r.EUCLIDEAN)return c<o?m.add(u<o?-u:u):m;throw new Error("Invalid ModType")}abs(){return new d(this.number<o?-this.number:this.number,this.decimalPos)}neg(){return this.mul(-s)}inv(){return this.convertToFraction().inv()}floor(r){return 0===this.decimalPos?this:this.round(r,t.TO_NEGATIVE)}ceil(r){return 0===this.decimalPos?this:this.round(r,t.TO_POSITIVE)}trunc(r){return 0===this.decimalPos?this:this.round(r,t.TO_ZERO)}isTieStr(t){if("5"!==t[0])return!1;for(let r=1;r<t.length;r++)if("0"!==t[r])return!1;return!0}_round(r,e){const n=this.decimalPos-r;if(n<=0)return this;const i=h**BigInt(n),a=this.number/i;if(e===t.TO_ZERO)return new d(a,r);const c=this.number%i;if(c===o)return new d(a,r);if(e===t.AWAY_FROM_ZERO){const t=this.number<o?a-s:a+s;return new d(t,r)}if(e===t.TO_POSITIVE){const t=this.number<o?a:a+s;return new d(t,r)}if(e===t.TO_NEGATIVE){const t=this.number>=o?a:a-s;return new d(t,r)}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(e))throw new Error("Invalid rounding mode. Use the predefined values from the RoundingMode enum.");let m=(c<o?-c:c).toString();if(m.length<n&&(m="0"),this.isTieStr(m)){if(e===t.NEAREST_TO_ZERO)return new d(a,r);if(e===t.NEAREST_AWAY_FROM_ZERO){const t=this.number<o?a-s:a+s;return new d(t,r)}if(void 0===e||e===t.NEAREST_TO_POSITIVE){const t=this.number<o?a:a+s;return new d(t,r)}if(e===t.NEAREST_TO_NEGATIVE){const t=this.number>=o?a:a-s;return new d(t,r)}if(e===t.NEAREST_TO_EVEN){if(a%u===o)return new d(a,r);return new d(a<o?a-s:a+s,r)}}if(Number(m[0])<5)return new d(a,r);const l=this.number<o?a-s:a+s;return new d(l,r)}round(t,r){if(t=void 0===t?0:t,!Number.isSafeInteger(t)||t<0)throw new Error("Invalid value for decimals");return this._round(t,r).normalize()}_incExponent(t){if(0===t)return this;let r=this.number,e=this.decimalPos;if(t<0)e-=t;else{const n=Math.min(t,this.decimalPos);e-=n;const i=t-n;i>0&&(r*=h**BigInt(i))}return new d(r,e)}countDigits(){if(this.number===o)return 1;let t=0,r=this.number<o?-this.number:this.number;for(;r>o;)r/=h,t++;return t}toSubZeroNum(){const t=this.countDigits();return{subZeroNum:new d(this.number,t),exponentDiff:t-this.decimalPos}}roundToDigits(t,r){if(!Number.isSafeInteger(t)||t<1)throw new Error("Invalid value for digits");const{subZeroNum:e,exponentDiff:n}=this.toSubZeroNum();let i=e.round(t,r);return i=i._incExponent(n),i}intPart(){return this.trunc()}fracPart(){return this.sub(this.trunc())}sign(){return this.number<o?-1:1}bitwiseAnd(t){if(t=w(t),!this.isInteger()||-1===this.sign()||!t.isInteger()||-1===t.sign())throw new Error("Only positive integers are supported");t instanceof f&&(t=t.trunc());const r=u**l;let e=this.normalize().number,n=t.trunc().normalize().number,i=o,a=s;for(;e>o&&n>o;){const t=BigInt.asUintN(24,e),o=BigInt.asUintN(24,n);i+=BigInt(Number(t)&Number(o))*a,a*=r,e/=r,n/=r}return new d(i)}bitwiseOr(t){if(t=w(t),!this.isInteger()||-1===this.sign()||!t.isInteger()||-1===t.sign())throw new Error("Only positive integers are supported");t instanceof f&&(t=t.trunc());const r=u**l;let e=this.normalize().number,n=t.trunc().normalize().number,i=o,a=s;for(;e>o||n>o;){const t=BigInt.asUintN(24,e),o=BigInt.asUintN(24,n);i+=BigInt(Number(t)|Number(o))*a,a*=r,e/=r,n/=r}return new d(i)}bitwiseXor(t){if(t=w(t),!this.isInteger()||-1===this.sign()||!t.isInteger()||-1===t.sign())throw new Error("Only positive integers are supported");t instanceof f&&(t=t.trunc());const r=u**l;let e=this.normalize().number,n=t.trunc().normalize().number,i=o,a=s;for(;e>o||n>o;){const t=BigInt.asUintN(24,e),o=BigInt.asUintN(24,n);i+=BigInt(Number(t)^Number(o))*a,a*=r,e/=r,n/=r}return new d(i)}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 r=u**BigInt(t);return this.mul(r)}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 r=u**BigInt(t);return new d(this.normalize().number/r)}cmp(t){const r=g(t);if(r instanceof f)return-r.cmp(this);const e=r,{a:n,b:i}=this.scaleNumber(e.number,e.decimalPos);return n===i?0:n>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,r){const e=w(t),n=w(r);if(e.gt(n))throw new Error("Min parameter has to be smaller than max");return this.lt(e)?e:this.gt(n)?n:this}isZero(){return this.number===o}isOne(){if(0===this.decimalPos)return this.number===s;const t=h**BigInt(this.decimalPos),r=this.number/t;return r===s&&r*t===this.number}isInteger(){return 0===this.decimalPos||this.number%h**BigInt(this.decimalPos)===o}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,r=this.number;for(;t>0&&r%h===o;)t--,r/=h;return new d(r,t)}convertToFraction(){if(0===this.decimalPos)return new f(this.number,s);const t=h**BigInt(this.decimalPos);return new f(this.number,t)}toNumber(){return Number(this.toPrecision(20))}toFixed(r,e=t.TO_ZERO,i=!1){if(!Number.isSafeInteger(r)||r<0)throw new Error("Invalid parameter");const o=this._round(r,e);return n(o.number,o.decimalPos,r,i)}toExponential(r,n=t.TO_ZERO,i=!1){if(!Number.isSafeInteger(r)||r<0)throw new Error("Invalid parameter");const o=this.roundToDigits(r+1,n).normalize(),s=-1===o.sign(),u=o.abs(),a=u.number.toString(),c=a.length<=r?`${a}${"0".repeat(r-a.length+1)}`:a.slice(0,r+1);let m=c;c.length>1&&(m=`${c.slice(0,1)}.${c.slice(1)}`,i&&(m=e(m)));const h=u.decimalPos,l=a.length-1-h;return`${s?"-":""}${m}e${l>=0?"+":""}${l}`}toBase(t,r){if(!Number.isSafeInteger(t)||t<2||t>16)throw new Error("Invalid radix");if(void 0!==r&&(!Number.isSafeInteger(r)||r<0))throw new Error("Invalid parameter");const e=this.normalize();if(0===e.decimalPos)return e.number.toString(t);const n=void 0===r?Number.MAX_SAFE_INTEGER:r;let i=e.intPart(),o=e.sub(i);const s=-1===e.sign();s&&(i=i.neg(),o=o.neg());const u=new Map;let a=[];for(;!o.isZero();){const r=o.mul(t),e=r.toString(),i=u.get(e);if(void 0!==i){a=[...a.slice(0,i-1),"(",...a.slice(i-1),")"];break}if(a.length===n)break;const s=Math.abs(r.intPart().toNumber());a.push(s.toString(t)),o=r.fracPart(),u.set(e,a.length)}const c=a.join("");return`${s?"-":""}${i.number.toString(t)}${a.length?".":""}${c}`}toFraction(){return this.convertToFraction().toFraction()}toString(t,r){if(void 0===t||10===t){const t=void 0!==r?this.trunc(r):this;return n(t.number,t.decimalPos,t.decimalPos,!0)}return this.toBase(t,r)}toPrecision(r,i=t.TO_ZERO,o=!1){if(!Number.isSafeInteger(r)||r<1)throw new Error("Invalid parameter");const s=this.roundToDigits(r,i),{subZeroNum:u,exponentDiff:a}=s.toSubZeroNum(),c=-1===u.sign();let m=n(u.number,u.decimalPos,u.decimalPos,!1);m=m.slice(c?3:2),m=m.slice(0,Math.max(r,a));const h=m.slice(0,Math.max(0,a)),l=m.slice(Math.max(0,a)),d=Math.max(0,r-h.length-l.length),f="0".repeat(a<0?-a:0);let g=h||"0";if(l.length+f.length+d>0){g+=`.${f}${l}${"0".repeat(d)}`,o&&(g=e(g))}return c?`-${g}`:g}valueOf(){throw new Error("Unsafe conversion to Number type! Use toNumber() instead.")}}class f{constructor(t,r){if(this.type="fraction","bigint"==typeof t&&"bigint"==typeof r)this.numerator=t,this.denominator=r;else{const e=this.parseParameter(t),n=this.parseParameter(r),i=e.div(n),o=i instanceof d?i.convertToFraction():i;this.numerator=o.numerator,this.denominator=o.denominator}if(this.denominator===o)throw new Error("Division by zero")}parseRepeatingDecimal(t){if(!t.includes("("))return new d(t).convertToFraction();const r=(t=t.trim()).match(/^(-?[0-9]*)\.([0-9]+)?\(([0-9]+)\)(?:[eE]([+-]?[0-9]+))?$/);if(!r)throw new Error(`Cannot parse string "${t}"`);const e="-"===r[1]?"-0":r[1],n=r[2]??"",i=r[3],o=r[4],s=BigInt(e+n+i)-BigInt(e+n),u=BigInt("9".repeat(i.length)+"0".repeat(n.length)),a=new f(s,u);if(void 0!==o){const t=o.startsWith("-"),r=h**BigInt(t?o.slice(1):o);return t?a.div(r).normalize():a.mul(r).normalize()}return a.simplify()}parseParameter(t){if(t instanceof f)return t;if(t instanceof d)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 f(BigInt(t),s)}if("bigint"==typeof t)return new f(t,s);if("string"==typeof t){const r=t.split("/");if(r.length>2)throw new Error(`Cannot parse string '${t}'`);const e=this.parseRepeatingDecimal(r[0]),n=r[1]?this.parseRepeatingDecimal(r[1]):new f(s,s);return e.div(n).convertToFraction()}throw new Error("Unsupported parameter!")}add(t){const{numerator:r,denominator:e}=this.parseParameter(t);return this.denominator===e?new f(this.numerator+r,this.denominator):new f(this.numerator*e+r*this.denominator,e*this.denominator)}sub(t){const{numerator:r,denominator:e}=this.parseParameter(t);return this.add(new f(-r,e))}mul(t){const{numerator:r,denominator:e}=this.parseParameter(t);return new f(this.numerator*r,this.denominator*e)}div(t){const{numerator:r,denominator:e}=this.parseParameter(t);return this.mul(new f(e,r))}divToInt(t){return this.div(t).trunc()}mod(t,e=r.TRUNCATED){const n=this.parseParameter(t),i=n.denominator*this.numerator%(n.numerator*this.denominator),o=this.denominator*n.denominator,s=new f(i,o);if(e===r.TRUNCATED)return s;if(e===r.FLOORED)return Number(-1===this.sign())^Number(-1===n.sign())?s.add(n):s;if(e===r.EUCLIDEAN)return-1===s.sign()?s.add(-1===n.sign()?n.neg():n):s;throw new Error("Invalid ModType")}pow(t){const r=this.parseParameter(t);if(!r.isInteger())throw new Error("Unsupported parameter");const e=r.numerator/r.denominator,n=e<o?-e:e,i=new f(this.numerator**n,this.denominator**n);return e<o?i.inv():i}powm(t,r,e){const n=this.parseParameter(t);if(!n.isInteger())throw new Error("Unsupported parameter");let i=n.toNumber();const o=this.parseParameter(r);let a=this,c=new f(s,s);for(;0!==i;)i%2!=0&&(c=c.mul(a).mod(o,e)),a=a.pow(u).mod(o,e),i=Math.floor(i/2);return c}inv(){return new f(this.denominator,this.numerator)}floor(r){return this.denominator===s?new d(this.numerator):this.round(r,t.TO_NEGATIVE)}ceil(r){return this.denominator===s?new d(this.numerator):this.round(r,t.TO_POSITIVE)}trunc(r){return this.denominator===s?new d(this.numerator):this.round(r,t.TO_ZERO)}round(t,r){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(t,r);return new d(`${e.toFixed(t+1)}1`).round(t,r)}roundToDigits(t,r){if(!Number.isSafeInteger(t)||t<1)throw new Error("Invalid value for digits");if(this.isZero())return new d(o);let e=this.abs(),n=0;for(;e.gte(s);)e=e.div(h),n++;const i=new f(s,h);for(;e.lt(i);)e=e.mul(h),n--;let u=e.round(t,r);return u=u._incExponent(n),-1===this.sign()?u.neg():u}gcd(t,r){let e=t<o?-t:t,n=r<o?-r:r;if(n>e){const t=e;e=n,n=t}for(;;){if(n===o)return e;if(e%=n,e===o)return n;n%=e}}simplify(){let{numerator:t,denominator:r}=this;const e=this.gcd(t,r);return e>s&&(t/=e,r/=e),r<o&&(t=-t,r=-r),new f(t,r)}normalize(){const{numerator:r,denominator:e}=this.simplify();if(e===s)return new d(r,0);const n=new f(r,e),{cycleLen:i,cycleStart:o}=n.getDecimalFormat(0);return 0!==i?n:n.round(o,t.TO_ZERO)}getFractionParts(t=!0){const r=t?this.simplify():this;return{numerator:new d(r.numerator),denominator:new d(r.denominator)}}sign(){return(this.numerator<o?-1:1)*(this.denominator<o?-1:1)}abs(){return new f(this.numerator<o?-this.numerator:this.numerator,this.denominator<o?-this.denominator:this.denominator)}neg(){return this.mul(-s)}intPart(){return this.trunc()}fracPart(){return this.sub(this.trunc())}cmp(t){const r=this.parseParameter(t),e=this.denominator===r.denominator,n=e?this.numerator:this.numerator*r.denominator,i=e?r.numerator:r.numerator*this.denominator;return n===i?0:n>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,r){const e=w(t),n=w(r);if(e.gt(n))throw new Error("Min parameter has to be smaller than max");return this.lt(e)?e:this.gt(n)?n:this}isZero(){return this.numerator===o}isOne(){return this.numerator===this.denominator}isInteger(){return this.numerator%this.denominator===o}serialize(){return[this.numerator,this.denominator]}toNumber(){return Number(this.toPrecision(20))}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 r=this.denominator<o?-this.denominator:this.denominator,e=0;for(;r%u===o;)r/=u,e++;let n=0;for(;r%m===o;)r/=m,n++;const i=Math.max(e,n);if(r===s)return{cycleLen:0,cycleStart:i};const a=Math.max(1,t-i);let c=h%r,l=1;for(;c!==s;){if(l===a)return{cycleLen:null,cycleStart:i};c=c*h%r,l++}return{cycleLen:l,cycleStart:i}}toFixed(r,e=t.TO_ZERO,n=!1){if(!Number.isSafeInteger(r)||r<0)throw new Error("Invalid parameter");return this.round(r,e).toFixed(r,t.TO_ZERO,n)}toRepeatingParts(t){if(this.isZero())return["0","",""];const{cycleLen:r,cycleStart:n}=this.simplify().getDecimalFormat(t);if(null===r||0===r){const r=t??n,i=this.toFixed(r),o=e(i).split(".");return[o[0],o[1]??"",""]}const i=n+r,o=this.toFixed(i).split(".");return[o[0],o[1].slice(0,n),o[1].slice(n)]}toRepeatingDigits(t){const r=this.toRepeatingParts(t);let e=r[0];return(r[1]||r[2])&&(e+=`.${r[1]}`),r[2]&&(e+=`(${r[2]})`),e}toExponential(r,e=t.TO_ZERO,n=!1){if(!Number.isSafeInteger(r)||r<0)throw new Error("Invalid parameters");return this.toFixedNumber(r).toExponential(r,e,n)}toFraction(){const{numerator:t,denominator:r}=this.getFractionParts(!0);return`${t.toString()}/${r.toString()}`}toFixedNumber(t){const r=this.numerator*h**BigInt(t);return new d(r/this.denominator,t)}toBase(t,r){if(!Number.isSafeInteger(t)||t<2||t>16)throw new Error("Invalid radix");if(void 0!==r&&(!Number.isSafeInteger(r)||r<0))throw new Error("Invalid parameter");if(10===t)return void 0===r?this.toRepeatingDigits(r):e(this.toFixed(r));const n=this.normalize(),i=void 0===r?Number.MAX_SAFE_INTEGER:r+1;let o=n.intPart(),s=n.sub(o);const u=-1===n.sign();u&&(o=o.neg(),s=s.neg());const a=new Map;let c=[];for(;!s.isZero()&&c.length!==i;){const r=s.mul(t),e=r.normalize().toFraction(),n=a.get(e);if(void 0!==n){c=[...c.slice(0,n-1),"(",...c.slice(n-1),")"];break}const i=Math.abs(r.intPart().toNumber());c.push(i.toString(t)),s=r.fracPart(),a.set(e,c.length)}c.length===i&&c.pop();const m=c.join("");return`${u?"-":""}${o.toString(t)}${c.length?".":""}${m}`}toString(t,r){return void 0===t||10===t?this.toRepeatingDigits(r):this.toBase(t,r)}toPrecision(r,e=t.TO_ZERO,n=!1){if(!Number.isSafeInteger(r)||r<1)throw new Error("Invalid parameter");return this.roundToDigits(r,e).toPrecision(r,t.TO_ZERO,n)}valueOf(){throw new Error("Unsafe conversion to Number type! Use toNumber() instead.")}}function g(t){if(t instanceof d||t instanceof f)return t;if("bigint"==typeof t)return new d(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 d(t)}if("string"==typeof t)return t.includes("/")||t.includes("(")?new f(t,s):new d(t);throw new Error("Unsupported parameter type")}const w=(t,r)=>{if(void 0===t)throw new Error("First parameter cannot be undefined");const e=g(t);if(void 0===r)return e;const n=g(r);return new f(e,s).div(new f(n,s))};w.min=(...t)=>{if(0===t.length)throw new Error("Got empty array");let r=w(t[0]);for(let e=1;e<t.length;e++){const n=w(t[e]);n.lt(r)&&(r=n)}return r},w.max=(...t)=>{if(0===t.length)throw new Error("Got empty array");let r=w(t[0]);for(let e=1;e<t.length;e++){const n=w(t[e]);n.gt(r)&&(r=n)}return r};const b=(t,r)=>{let e=o;for(let n=0;n<t.length;n++){const i=t.charAt(n),o=parseInt(i,r);if(Number.isNaN(o))throw new Error(`Invalid digit "${i}"`);e*=BigInt(r),e+=BigInt(o)}return e};w.fromBase=(t,r)=>{if("string"!=typeof t)throw new Error("First parameter must be string");if(!Number.isSafeInteger(r)||r<2||r>16)throw new Error("Invalid radix");if(10===r)return w(t);if(0===(t=t.trim()).length)throw new Error("Empty string is not allowed");const e=t.startsWith("-");e&&(t=t.slice(1));const n=t.match(/^([0-9a-f]*)(?:\.([0-9a-f]*)(?:\(([0-9a-f]+)\))?)?$/i);if(!n)throw new Error(`Cannot parse number "${t}"`);const i=n[1]??"",o=n[2]??"",u=n[3]??"";if(u.length>0){const t=b(`${i}${o}${u}`,r)-b(`${i}${o}`,r),n=b((r-1).toString(r).repeat(u.length)+"0".repeat(o.length),r),s=new f(t,n).normalize();return e?s.neg():s}const a=b(i,r),c=b(o,r),m=new f(c,BigInt(r)**BigInt(o.length)),h=new f(a,s).add(m).normalize();return e?h.neg():h},w.range=function*(t,r,e){const n=w(r),i=w(e??1);let o=w(t);for(;o.lt(n);)yield o,o=o.add(i)},w.gcd=(t,r)=>{const e=w(t).abs(),n=w(r).abs();let i=n.gt(e)?n:e,o=i.eq(e)?n:e;for(;;){if(o.isZero())return i;if(i=i.mod(o),i.isZero())return o;o=o.mod(i)}},w.lcm=(t,r)=>{const e=w(t).abs(),n=w(r).abs(),i=e.mul(n);if(i.isZero())throw new Error("LCM of zero is undefined");const o=w.gcd(e,n);return i.div(o)};const E=(t,r,e)=>{const n=((t,r)=>{let e=r.toNumber();if(Number.isFinite(e)){const r=e<0;r&&(e=-e);let n=e**(1/t);return r&&(n=-n),n.toString()}const n=r.abs().toFixed(0).length,i=Math.ceil(n/t);return`${1===r.sign()?"":"-"}5e${i}`})(t,r);let i=new d("0"!==n?n:"1");const o=new f(t-1,t),s=new f(r,t),u=BigInt(t-1);let a=i.trunc(e+5);for(;i=o.mul(i).add(s.mul(i.pow(u).inv())),i=i.trunc(e+5),!i.isZero()&&!a.eq(i);)a=i;return i.trunc(e)},p=(t,r,e)=>{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");const n=i(w(r),e);if(1===t)return n.trunc(e);if(t%2==0&&-1===n.sign())throw new Error("Complex numbers are not supported");if(n.isZero())return new d(o).trunc(e);if(n.isOne())return new d(s).trunc(e);return E(t,n,e)},I=(t,r)=>p(2,t,r),N=(t,r)=>p(3,t,r);class v{constructor(t,r){this.cachedDecimals=0,this.fn=t,this.max=r}get(t){if(t<=this.cachedDecimals)return this.cache.trunc(t);const r=new d(this.fn(t)),e=Math.min(this.max,t);return this.cachedDecimals!==e&&(this.cache=r.trunc(e),this.cachedDecimals=e),r}}const O=(t,r)=>{let e=i(w(t),r);if(e.isOne())return new d(0).trunc(r);if(e.lte(0))throw new Error("Invalid parameter");let n=0;const a=w("0.1");for(;e.sub(s).abs().gt(a);)e=new d(I(e,r+10)),n++;const c=function*(t,r){const e=t.pow(u).normalize();let n=t,i=s,o=w(t);for(;;){n=n.mul(e),i+=u;const t=n.div(i).trunc(r+10);o=o.add(t),yield{term:t,sum:o}}}(e.sub(s).div(e.add(s)),r);for(const{term:t,sum:e}of c)if(t.isZero()){return e.mul(u**BigInt(n+1)).trunc(r)}return w(o)},T=(t,r,e)=>{if(!Number.isSafeInteger(t)||t<2)throw new Error("Invalid parameter for N");const n=O(r,e+10),i=O(t,e+10);return new d(n).div(i).trunc(e)},P=new v((t=>O(u,t)),200),_=(t,r)=>new d(O(t,r+10)).div(P.get(r+10)).trunc(r),S=new v((t=>O(h,t)),200),R=(t,r)=>new d(O(t,r+10)).div(S.get(r+10)).trunc(r);const A=(t,r)=>{const e=i(w(t),r),n=w(`1e-${r+5}`),a=function*(t,r){let e=t.add(1),n=BigInt(6),i=c;const o=t.pow(u);let a=o;for(;;){const c=a.mul(t.add(i-s)).div(n);n*=i*(i+s),i+=u,a=a.mul(o),e=e.add(c).trunc(r+5),yield{term:c,sum:e}}}(e,r);for(const{term:t,sum:e}of a)if(t.abs().lt(n))return e.trunc(r);return w(o)},F=(t,r,e)=>{const n=i(w(t),e),o=i(w(r),e);if(o.isInteger()&&Number.isSafeInteger(o.toNumber()))return n.pow(o).trunc(e);if(-1===n.sign()&&!o.isInteger())throw new Error("Complex numbers are not supported");const s=O(n,e+5),u=o.mul(s);return A(u,e+5).trunc(e)},y=new v((t=>{if(0===t)return w(a);let r=s,e=a*h**BigInt(t+20),n=e;for(;e!==o;)e=e*r/((r+s)*c),r+=u,n+=e/r;return w(`3.${n.toString().slice(1,t+1)}`)}),1e3),B=t=>0===t?w(a):y.get(t).trunc(t),Z=(r,e)=>{let n=r.round(e+5,t.NEAREST_AWAY_FROM_ZERO);const i=B(e+5),o=((t,r,e)=>{const n=Math.max(3,e),i=t.trunc(n),o=i.div(r).round();return r.mul(o).trunc(n).eq(i)?o:null})(n,i.div(12),e);if(null!==o)return(t=>{let r=t.mod(l).toNumber();r<0&&(r+=24);const e=Math.floor(r/6)+1;let n=15*r;return 4===e?n=360-n:3===e?n-=180:2===e&&(n=180-n),{specialCaseDeg:n,quadrant:e,subHalfPiAngle:null}})(o);const s=i.mul(u);n=n.mod(s),-1===n.sign()&&(n=n.add(s));const a=n.mul(u).div(i).floor().toNumber()+1;let c=n;return 4===a?c=s.sub(c):3===a?c=c.sub(i):2===a&&(c=i.sub(c)),{specialCaseDeg:null,quadrant:a,subHalfPiAngle:c}};const $=(t,r,e)=>{let n=w(t);return r&&(n=n.neg()),n.trunc(e)},x=(r,e)=>{const n=e+10,c=i(w(r),e+5),{specialCaseDeg:m,subHalfPiAngle:h,quadrant:l}=Z(c,e),d=2===l||3===l;if(null!==m){if(0===m)return $(s,d,e);if(30===m)return $(w(I(a,e+5)).div(u),d,e);if(45===m)return $(w(I(u,e+5)).div(u),d,e);if(60===m)return $("0.5",d,e);if(90===m)return $(o,d,e);throw new Error}const f=w(`1e-${n}`),g=function*(r,e){const n=r.round(e+10,t.NEAREST_AWAY_FROM_ZERO).pow(u);let i=n,o=u,c=w(s).sub(i.div(o).trunc(e+10)),m=a;for(;;){o*=m*(m+s),m+=u;const t=m*(m+s);m+=u,i=i.mul(n),o*=t;let r=i.mul(t);i=i.mul(n),r=r.sub(i);const a=r.div(o).trunc(e+10);c=c.add(a),yield{term:a,sum:c}}}(h,e);for(const{term:t,sum:r}of g)if(t.lt(f))return $(r,d,e);return w(0)},D=(t,r)=>{const e=new d(B(r+10)),n=i(w(t),r+5);return x(e.div(u).sub(n),r+5).trunc(r)},M=(t,r)=>{const e=i(w(t),r+5),{specialCaseDeg:n,quadrant:o,subHalfPiAngle:c}=Z(e,r),m=1===o||3===o;if(null!==n){if(0===n)return $("0",m,r);if(30===n)return $(w(s).div(I(a,r+5)),m,r);if(4===n)return $("1",m,r);if(60===n)return $(I(a,r+5),m,r);if(90===n)throw new Error("Out of range");throw new Error}const h=w(x(c.mul(u),r+5)),l=w(s).sub(h).div(w(s).add(h)).round(r+5),d=I(l,r+5).trunc(r);return m?d:d.neg()};const z=(t,r)=>{let e=i(w(t),r);if(e.isZero())return w(0);if(e.abs().isOne())return w(B(r)).div(4*e.sign()).trunc(r);let n=0;const o=w("0.42");for(;e.abs().gt(o);){const t=w(I(e.pow(u).add(s),r+10));e=e.div(t.add(s)),n++}const c=w(`1e-${r+10}`),m=function*(t,r){const e=t.pow(u).normalize(),n=e.pow(u).normalize();let i=a,o=t.sub(t.mul(e).div(i)),s=t.mul(n);for(;;){i+=u;const t=i+u,a=s.mul(e.mul(-i).add(t)).div(i*t);i=t,s=s.mul(n),o=o.add(a).trunc(r+10),yield{term:a,sum:o}}}(e,r);for(const{term:t,sum:e}of m)if(t.abs().lt(c)){return e.mul(u**BigInt(n)).trunc(r)}return w(0)},U=(t,r)=>{const e=i(w(t),r);if(e.isZero())return w(o);if(e.abs().isOne())return w(B(r)).mul(e.sign()).div(u).trunc(r);if(e.abs().eq("1/2"))return w(B(r)).mul(e.sign()).div(6).trunc(r);if(e.gt(s)||e.lt(-s))throw new Error("Out of range");const n=w(I(e.pow(u).neg().add(s),r+10));return w(z(e.div(n.add(s)),r+10)).mul(u).trunc(r)},C=(t,r)=>{const e=i(w(t),r);if(e.isZero())return w(B(r)).div(u).trunc(r);if(e.isOne())return w(o);if(e.abs().isOne())return B(r);if(e.abs().eq("1/2")){const t=w(B(r)).div(a);return-1===e.sign()?t.mul(u).trunc(r):t.trunc(r)}if(e.gt(s)||e.lt(-s))throw new Error("Out of range");return w(B(r+10)).div(u).sub(U(e,r+10)).trunc(r)};const V=(t,r)=>{const e=i(w(t),r),n=new d(`1e-${r+5}`),a=function*(t,r){let e=t,n=s;const i=t.pow(u).normalize();let o=t.trunc(r+5),a=u;for(;;){e=e.mul(i),n*=a*(a+s),a+=u;const t=e.div(n);o=o.add(t).trunc(r+5),yield{term:t,sum:o}}}(e,r);for(const{term:t,sum:e}of a)if(t.abs().lt(n))return e.trunc(r);return w(o)};const L=(t,r)=>{const e=i(w(t),r),n=new d(`1e-${r+5}`),c=function*(t,r){const e=t.pow(u).normalize();let n=e,i=u,o=n.div(i).add(s).trunc(r+5),c=a;for(;;){n=n.mul(e),i*=c*(c+s),c+=u;const t=n.div(i);o=o.add(t).trunc(r+5),yield{term:t,sum:o}}}(e,r);for(const{term:t,sum:e}of c)if(t.abs().lt(n))return e.trunc(r);return w(o)},G=(t,r)=>{const e=i(w(t),r);if(e.isZero())return w(o);const n=L(e,r+10).abs();return I(n.pow(u).sub(s),r+10).div(n).mul(e.sign()).trunc(r)},W=(t,r)=>{const e=i(w(t),r);if(e.isZero())return w(o);const n=I(e.pow(u).add(s),r+5);return O(e.add(n),r+5).trunc(r)},q=(t,r)=>{const e=i(w(t),r);if(e.isOne())return w(o);if(e.lt(s))throw new Error("Out of range");const n=I(e.pow(u).sub(s),r+5);return O(e.add(n),r+5).trunc(r)},Y=(t,r)=>{const e=i(w(t),r);if(e.abs().gte(s))throw new Error("Out of range");if(e.isZero())return w(o);const n=O(e.add(s).div(e.neg().add(s)),r+5);return w(n).div(u).trunc(r)};export{w as ExactNumber,r as ModType,B as PI,t as RoundingMode,C as acos,q as acosh,U as asin,W as asinh,z as atan,Y as atanh,N as cbrt,x as cos,L as cosh,A as exp,O as log,R as log10,_ as log2,T as logn,p as nthroot,F as pow,D as sin,V as sinh,I as sqrt,M as tan,G as tanh}; |
/*! | ||
* exactnumber v0.11.0 (https://www.npmjs.com/package/exactnumber) | ||
* exactnumber v1.0.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,r;n.RoundingMode=void 0,(t=n.RoundingMode||(n.RoundingMode={}))[t.NEAREST_TO_POSITIVE=201008]="NEAREST_TO_POSITIVE",t[t.NEAREST_TO_NEGATIVE=201009]="NEAREST_TO_NEGATIVE",t[t.NEAREST_TO_EVEN=201010]="NEAREST_TO_EVEN",t[t.NEAREST_TO_ZERO=201011]="NEAREST_TO_ZERO",t[t.NEAREST_AWAY_FROM_ZERO=201012]="NEAREST_AWAY_FROM_ZERO",t[t.TO_POSITIVE=201001]="TO_POSITIVE",t[t.TO_NEGATIVE=201002]="TO_NEGATIVE",t[t.TO_ZERO=201003]="TO_ZERO",t[t.AWAY_FROM_ZERO=201004]="AWAY_FROM_ZERO",n.ModType=void 0,(r=n.ModType||(n.ModType={})).TRUNCATED="T",r.FLOORED="F",r.EUCLIDEAN="E";const e=n=>{const t=n.indexOf(".");if(-1===t)return n;let r=n.length;for(;r>t&&"0"===n.charAt(r-1);)r--;const e=t===r-1?t:r;return 0===e?"0":n.slice(0,e)},i=(n,t,r,i)=>{let o=n.toString();if(0===t&&0===r)return o;const s=o.startsWith("-");if(s&&(o=o.slice(1)),t>=o.length&&(o="0".repeat(t-o.length+1)+o),t>0){const n=o.slice(0,-t),s=o.slice(-t),u=r<=t?s.slice(0,r):`${s}${"0".repeat(r-t)}`;0!==u.length?(o=`${n}.${u}`,i&&(o=e(o))):o=n}else r>0&&(o=`${o}.${"0".repeat(r)}`);return s?`-${o}`:o},o=(t,r)=>(t=t.normalize())instanceof s?t.round(r,n.RoundingMode.NEAREST_AWAY_FROM_ZERO):t;class s{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 s)return{number:n.number,decimalPos:n.decimalPos};if(n instanceof u){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 r=0,e=t[1]??"0";if(void 0!==t[2]&&(e+=t[2],r+=t[2].length),void 0!==t[3]){const n=Number(t[3]);n>0?e+="0".repeat(n):r-=n}return{number:BigInt(e),decimalPos:r}}throw new Error("Unsupported parameter!")}scaleNumber(n,t){const r=Math.max(this.decimalPos,t);return{a:r===this.decimalPos?this.number:this.number*10n**BigInt(r-this.decimalPos),b:r===t?n:n*10n**BigInt(r-t),decimalPos:r}}add(n){const t=a(n);if(t instanceof u)return t.add(this);const r=t,{a:e,b:i,decimalPos:o}=this.scaleNumber(r.number,r.decimalPos);return new s(e+i,o)}sub(n){const t=a(n);return this.add(t.neg())}mul(n){const t=a(n);if(t instanceof u)return t.mul(this);const r=t,e=this.number*r.number;return new s(e,this.decimalPos+r.decimalPos)}pow(n){const t=a(n).toNumber();if(!Number.isSafeInteger(t))throw new Error("Unsupported parameter");const r=Math.abs(t),e=new s(this.number**BigInt(r),this.decimalPos*r);return t<0?e.inv():e}div(n){return this.convertToFraction().div(n)}divToInt(n){const t=a(n);if(t instanceof u)return this.convertToFraction().divToInt(t);const r=t,{a:e,b:i}=this.scaleNumber(r.number,r.decimalPos);return new s(e/i)}mod(t,r=n.ModType.TRUNCATED){const e=a(t);if(e instanceof u)return this.convertToFraction().mod(e);const i=e,{a:o,b:c,decimalPos:m}=this.scaleNumber(i.number,i.decimalPos),d=o%c,h=new s(d,m);if(r===n.ModType.TRUNCATED)return h;if(r===n.ModType.FLOORED)return Number(o<0)^Number(c<0)?h.add(c):h;if(r===n.ModType.EUCLIDEAN)return d<0?h.add(c<0?-c:c):h;throw new Error("Invalid ModType")}abs(){return new s(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)}isTieStr(n){if("5"!==n[0])return!1;for(let t=1;t<n.length;t++)if("0"!==n[t])return!1;return!0}_round(t,r){const e=this.decimalPos-t;if(e<=0)return this;const i=10n**BigInt(e),o=this.number/i;if(r===n.RoundingMode.TO_ZERO)return new s(o,t);const u=this.number%i;if(0n===u)return new s(o,t);if(r===n.RoundingMode.AWAY_FROM_ZERO){const n=this.number<0n?o-1n:o+1n;return new s(n,t)}if(r===n.RoundingMode.TO_POSITIVE){const n=this.number<0n?o:o+1n;return new s(n,t)}if(r===n.RoundingMode.TO_NEGATIVE){const n=this.number>=0n?o:o-1n;return new s(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(r))throw new Error("Invalid rounding mode. Use the predefined values from the RoundingMode enum.");let a=(u<0n?-u:u).toString();if(a.length<e&&(a="0"),this.isTieStr(a)){if(r===n.RoundingMode.NEAREST_TO_ZERO)return new s(o,t);if(r===n.RoundingMode.NEAREST_AWAY_FROM_ZERO){const n=this.number<0n?o-1n:o+1n;return new s(n,t)}if(void 0===r||r===n.RoundingMode.NEAREST_TO_POSITIVE){const n=this.number<0n?o:o+1n;return new s(n,t)}if(r===n.RoundingMode.NEAREST_TO_NEGATIVE){const n=this.number>=0n?o:o-1n;return new s(n,t)}if(r===n.RoundingMode.NEAREST_TO_EVEN){if(o%2n===0n)return new s(o,t);return new s(o<0n?o-1n:o+1n,t)}}if(Number(a[0])<5)return new s(o,t);const c=this.number<0?o-1n:o+1n;return new s(c,t)}round(n,t){if(n=void 0===n?0:n,!Number.isSafeInteger(n)||n<0)throw new Error("Invalid value for decimals");return this._round(n,t).normalize()}_incExponent(n){if(0===n)return this;let t=this.number,r=this.decimalPos;if(n<0)r-=n;else{const e=Math.min(n,this.decimalPos);r-=e;const i=n-e;i>0&&(t*=10n**BigInt(i))}return new s(t,r)}countDigits(){if(0n===this.number)return 1;let n=0,t=this.number<0?-this.number:this.number;for(;t>0n;)t/=10n,n++;return n}toSubZeroNum(){const n=this.countDigits();return{subZeroNum:new s(this.number,n),exponentDiff:n-this.decimalPos}}roundToDigits(n,t){if(!Number.isSafeInteger(n)||n<1)throw new Error("Invalid value for digits");const{subZeroNum:r,exponentDiff:e}=this.toSubZeroNum();let i=r.round(n,t);return i=i._incExponent(e),i}intPart(){return this.trunc()}fracPart(){return this.sub(this.trunc())}sign(){return this.number<0n?-1:1}bitwiseAnd(n){if(n=c(n),!this.isInteger()||-1===this.sign()||!n.isInteger()||-1===n.sign())throw new Error("Only positive integers are supported");n instanceof u&&(n=n.trunc());const t=2n**24n;let r=this.normalize().number,e=n.trunc().normalize().number,i=0n,o=1n;for(;r>0&&e>0;){const n=BigInt.asUintN(24,r),s=BigInt.asUintN(24,e);i+=BigInt(Number(n)&Number(s))*o,o*=t,r/=t,e/=t}return new s(i)}bitwiseOr(n){if(n=c(n),!this.isInteger()||-1===this.sign()||!n.isInteger()||-1===n.sign())throw new Error("Only positive integers are supported");n instanceof u&&(n=n.trunc());const t=2n**24n;let r=this.normalize().number,e=n.trunc().normalize().number,i=0n,o=1n;for(;r>0||e>0;){const n=BigInt.asUintN(24,r),s=BigInt.asUintN(24,e);i+=BigInt(Number(n)|Number(s))*o,o*=t,r/=t,e/=t}return new s(i)}bitwiseXor(n){if(n=c(n),!this.isInteger()||-1===this.sign()||!n.isInteger()||-1===n.sign())throw new Error("Only positive integers are supported");n instanceof u&&(n=n.trunc());const t=2n**24n;let r=this.normalize().number,e=n.trunc().normalize().number,i=0n,o=1n;for(;r>0||e>0;){const n=BigInt.asUintN(24,r),s=BigInt.asUintN(24,e);i+=BigInt(Number(n)^Number(s))*o,o*=t,r/=t,e/=t}return new s(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 s(this.normalize().number/t)}cmp(n){const t=a(n);if(t instanceof u)return-t.cmp(this);const r=t,{a:e,b:i}=this.scaleNumber(r.number,r.decimalPos);return e===i?0:e>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 r=c(n),e=c(t);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 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 s(t,n)}convertToFraction(){if(0===this.decimalPos)return new u(this.number,1n);const n=10n**BigInt(this.decimalPos);return new u(this.number,n)}toNumber(){return Number(this.toPrecision(20))}toFixed(t,r=n.RoundingMode.TO_ZERO){if(!Number.isSafeInteger(t)||t<0)throw new Error("Invalid parameter");const e=this._round(t,r);return i(e.number,e.decimalPos,t,!1)}toExponential(t,r=n.RoundingMode.TO_ZERO){if(!Number.isSafeInteger(t)||t<0)throw new Error("Invalid parameter");const e=this.roundToDigits(t+1,r).normalize(),i=-1===e.sign(),o=e.abs(),s=o.number.toString(),u=s.length<=t?`${s}${"0".repeat(t-s.length+1)}`:s.slice(0,t+1),a=u.length>1?`${u.slice(0,1)}.${u.slice(1)}`:u,c=o.decimalPos,m=s.length-1-c;return`${i?"-":""}${a}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 r=this.normalize();if(0===r.decimalPos)return r.number.toString(n);const e=void 0===t?Number.MAX_SAFE_INTEGER:t;let i=r.intPart(),o=r.sub(i);const s=-1===r.sign();s&&(i=i.neg(),o=o.neg());const u=new Map;let a=[];for(;!o.isZero();){const t=o.mul(n),r=t.toString(),i=u.get(r);if(void 0!==i){a=[...a.slice(0,i-1),"(",...a.slice(i-1),")"];break}if(a.length===e)break;const s=Math.abs(t.intPart().toNumber());a.push(s.toString(n)),o=t.fracPart(),u.set(r,a.length)}return[s?"-":"",i.number.toString(n),a.length?".":"",...a].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,n.decimalPos,!0)}return this.toBase(n,t)}toPrecision(t,r=n.RoundingMode.TO_ZERO){if(!Number.isSafeInteger(t)||t<1)throw new Error("Invalid parameter");const e=this.roundToDigits(t,r),{subZeroNum:o,exponentDiff:s}=e.toSubZeroNum(),u=-1===o.sign();let a=i(o.number,o.decimalPos,o.decimalPos,!1);a=a.slice(u?3:2),a=a.slice(0,Math.max(t,s));const c=a.slice(0,Math.max(0,s)),m=a.slice(Math.max(0,s)),d=Math.max(0,t-c.length-m.length),h="0".repeat(d),l="0".repeat(s<0?-s:0);let f=c||"0";return m.length+l.length+d>0&&(f+=`.${l}${m}${h}`),u?`-${f}`:f}valueOf(){throw new Error("Unsafe conversion to Number type! Use toNumber() instead.")}}class u{constructor(n,t){if(this.type="fraction","bigint"==typeof n&&"bigint"==typeof t)this.numerator=n,this.denominator=t;else{const r=this.parseParameter(n),e=this.parseParameter(t),i=r.div(e),o=i instanceof s?i.convertToFraction():i;this.numerator=o.numerator,this.denominator=o.denominator}if(0n===this.denominator)throw new Error("Division by zero")}parseRepeatingDecimal(n){if(!n.includes("("))return new s(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 r="-"===t[1]?"-0":t[1],e=t[2]??"",i=t[3],o=t[4],a=BigInt(r+e+i)-BigInt(r+e),c=BigInt("9".repeat(i.length)+"0".repeat(e.length)),m=new u(a,c);if(void 0!==o){const n=o.startsWith("-"),t=10n**BigInt(n?o.slice(1):o);return n?m.div(t).normalize():m.mul(t).normalize()}return m.simplify()}parseParameter(n){if(n instanceof u)return n;if(n instanceof s)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 u(BigInt(n),1n)}if("bigint"==typeof n)return new u(n,1n);if("string"==typeof n){const t=n.split("/");if(t.length>2)throw new Error(`Cannot parse string '${n}'`);const r=this.parseRepeatingDecimal(t[0]),e=t[1]?this.parseRepeatingDecimal(t[1]):new u(1n,1n);return r.div(e).convertToFraction()}throw new Error("Unsupported parameter!")}add(n){const{numerator:t,denominator:r}=this.parseParameter(n);return this.denominator===r?new u(this.numerator+t,this.denominator):new u(this.numerator*r+t*this.denominator,r*this.denominator)}sub(n){const{numerator:t,denominator:r}=this.parseParameter(n);return this.add(new u(-t,r))}mul(n){const{numerator:t,denominator:r}=this.parseParameter(n);return new u(this.numerator*t,this.denominator*r)}div(n){const{numerator:t,denominator:r}=this.parseParameter(n);return this.mul(new u(r,t))}divToInt(n){return this.div(n).trunc()}mod(t,r=n.ModType.TRUNCATED){const e=this.parseParameter(t),i=e.denominator*this.numerator%(e.numerator*this.denominator),o=this.denominator*e.denominator,s=new u(i,o);if(r===n.ModType.TRUNCATED)return s;if(r===n.ModType.FLOORED)return Number(-1===this.sign())^Number(-1===e.sign())?s.add(e):s;if(r===n.ModType.EUCLIDEAN)return s.sign()<0?s.add(e.sign()<0?e.neg():e):s;throw new Error("Invalid ModType")}pow(n){const t=this.parseParameter(n);if(!t.isInteger())throw new Error("Unsupported parameter");const r=t.numerator/t.denominator,e=r<0?-r:r,i=new u(this.numerator**e,this.denominator**e);return r<0?i.inv():i}inv(){return new u(this.denominator,this.numerator)}floor(t){return 1n===this.denominator?new s(this.numerator):this.round(t,n.RoundingMode.TO_NEGATIVE)}ceil(t){return 1n===this.denominator?new s(this.numerator):this.round(t,n.RoundingMode.TO_POSITIVE)}trunc(t){return 1n===this.denominator?new s(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 r=this.toFixedNumber(n+1);if(this.sub(r).isZero())return r.round(n,t);return new s(`${r.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 s(0n);let r=this.abs(),e=0;for(;r.gte(1n);)r=r.div(10n),e++;const i=new u(1n,10n);for(;r.lt(i);)r=r.mul(10n),e--;let o=r.round(n,t);return o=o._incExponent(e),-1===this.sign()?o.neg():o}gcd(n,t){let r=n<0?-n:n,e=t<0?-t:t;if(e>r){const n=r;r=e,e=n}for(;;){if(0n===e)return r;if(r%=e,0n===r)return e;e%=r}}simplify(){let{numerator:n,denominator:t}=this;const r=this.gcd(n,t);return r>1n&&(n/=r,t/=r),t<0n&&(n=-n,t=-t),new u(n,t)}normalize(){const{numerator:t,denominator:r}=this.simplify();if(1n===r)return new s(t,0);const e=new u(t,r),{cycleLen:i,cycleStart:o}=e.getDecimalFormat(0);return 0!==i?e:e.round(o,n.RoundingMode.TO_ZERO)}getFractionParts(n=!0){const t=n?this.simplify():this;return{numerator:new s(t.numerator),denominator:new s(t.denominator)}}sign(){return(this.numerator<0n?-1:1)*(this.denominator<0n?-1:1)}abs(){return new u(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),r=this.denominator===t.denominator,e=r?this.numerator:this.numerator*t.denominator,i=r?t.numerator:t.numerator*this.denominator;return e===i?0:e>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 r=c(n),e=c(t);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.toPrecision(20))}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,r=0;for(;t%2n===0n;)t/=2n,r++;let e=0;for(;t%5n===0n;)t/=5n,e++;const i=Math.max(r,e);if(1n===t)return{cycleLen:0,cycleStart:i};const o=Math.max(1,n-i);let s=10n%t,u=1;for(;1n!==s;){if(u===o)return{cycleLen:null,cycleStart:i};s=10n*s%t,u++}return{cycleLen:u,cycleStart:i}}toFixed(t,r=n.RoundingMode.TO_ZERO){if(!Number.isSafeInteger(t)||t<0)throw new Error("Invalid parameter");return this.round(t,r).toFixed(t)}toRepeatingParts(n){if(this.isZero())return["0","",""];const{cycleLen:t,cycleStart:r}=this.simplify().getDecimalFormat(n);if(null===t||0===t){const t=n??r,i=this.toFixed(t),o=e(i).split(".");return[o[0],o[1]??"",""]}const i=r+t,o=this.toFixed(i).split(".");return[o[0],o[1].slice(0,r),o[1].slice(r)]}toRepeatingDigits(n){const t=this.toRepeatingParts(n);let r=t[0];return(t[1]||t[2])&&(r+=`.${t[1]}`),t[2]&&(r+=`(${t[2]})`),r}toExponential(t,r=n.RoundingMode.TO_ZERO){if(!Number.isSafeInteger(t)||t<0)throw new Error("Invalid parameters");return this.toFixedNumber(t).toExponential(t,r)}toFraction(){const{numerator:n,denominator:t}=this.getFractionParts(!0);return`${n.toString()}/${t.toString()}`}toFixedNumber(n){const t=this.numerator*10n**BigInt(n);return new s(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):e(this.toFixed(t));const r=this.normalize(),i=void 0===t?Number.MAX_SAFE_INTEGER:t+1;let o=r.intPart(),s=r.sub(o);const u=-1===r.sign();u&&(o=o.neg(),s=s.neg());const a=new Map;let c=[];for(;!s.isZero()&&c.length!==i;){const t=s.mul(n),r=t.normalize().toFraction(),e=a.get(r);if(void 0!==e){c=[...c.slice(0,e-1),"(",...c.slice(e-1),")"];break}const i=Math.abs(t.intPart().toNumber());c.push(i.toString(n)),s=t.fracPart(),a.set(r,c.length)}return c.length===i&&c.pop(),[u?"-":"",o.toString(n),c.length?".":"",...c].join("")}toString(n,t){return void 0===n||10===n?this.toRepeatingDigits(t):this.toBase(n,t)}toPrecision(t,r=n.RoundingMode.TO_ZERO){if(!Number.isSafeInteger(t)||t<1)throw new Error("Invalid parameter");return this.roundToDigits(t,r).toPrecision(t)}valueOf(){throw new Error("Unsafe conversion to Number type! Use toNumber() instead.")}}function a(n){if(n instanceof s||n instanceof u)return n;if("bigint"==typeof n)return new s(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 s(n)}if("string"==typeof n)return n.includes("/")||n.includes("(")?new u(n,1n):new s(n);throw new Error("Unsupported parameter type")}const c=(n,t)=>{if(void 0===n)throw new Error("First parameter cannot be undefined");const r=a(n);if(void 0===t)return r;const e=a(t);return new u(r,1n).div(new u(e,1n))};c.min=(...n)=>{if(0===n.length)throw new Error("Got empty array");let t=c(n[0]);for(let r=1;r<n.length;r++){const e=c(n[r]);e.lt(t)&&(t=e)}return t},c.max=(...n)=>{if(0===n.length)throw new Error("Got empty array");let t=c(n[0]);for(let r=1;r<n.length;r++){const e=c(n[r]);e.gt(t)&&(t=e)}return t};const m=(n,t)=>{let r=0n;for(let e=0;e<n.length;e++){const i=n.charAt(e),o=parseInt(i,t);if(Number.isNaN(o))throw new Error(`Invalid digit "${i}"`);r*=BigInt(t),r+=BigInt(o)}return r};c.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 c(n);if(0===(n=n.trim()).length)throw new Error("Empty string is not allowed");const r=n.startsWith("-");r&&(n=n.slice(1));const e=n.match(/^([0-9a-f]*)(?:\.([0-9a-f]*)(?:\(([0-9a-f]+)\))?)?$/i);if(!e)throw new Error(`Cannot parse number "${n}"`);const i=e[1]??"",o=e[2]??"",s=e[3]??"";if(s.length>0){const n=m([i,o,s].join(""),t)-m([i,o].join(""),t),e=m((t-1).toString(t).repeat(s.length)+"0".repeat(o.length),t),a=new u(n,e).normalize();return r?a.neg():a}const a=m(i,t),d=m(o,t),h=new u(d,BigInt(t)**BigInt(o.length)),l=new u(a,1n).add(h).normalize();return r?l.neg():l},c.range=function*(n,t,r){const e=c(t),i=c(r??1);let o=c(n);for(;o.lt(e);)yield o,o=o.add(i)},c.gcd=(n,t)=>{const r=c(n).abs(),e=c(t).abs();let i=e.gt(r)?e:r,o=i.eq(r)?e:r;for(;;){if(o.isZero())return i;if(i=i.mod(o),i.isZero())return o;o=o.mod(i)}},c.lcm=(n,t)=>{const r=c(n).abs(),e=c(t).abs(),i=r.mul(e);if(i.isZero())throw new Error("LCM of zero is undefined");const o=c.gcd(r,e);return i.div(o)};const d=(n,t,r)=>{const e=((n,t)=>{let r=t.toNumber();if(Number.isFinite(r)){const t=r<0;t&&(r=-r);let e=r**(1/n);return t&&(e=-e),e.toString()}const e=t.abs().toFixed(0).length,i=Math.ceil(e/n);return`${1===t.sign()?"":"-"}5e${i}`})(n,t);let i=new s("0"!==e?e:"1");const o=new u(n-1,n),a=new u(t,n),c=BigInt(n-1);let m=i.trunc(r+5);for(;i=o.mul(i).add(a.mul(i.pow(c).inv())),i=i.trunc(r+5),!i.isZero()&&!m.eq(i);)m=i;return i.trunc(r)},h=(n,t,r)=>{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");const e=o(c(t),r);if(1===n)return e.trunc(r);if(n%2==0&&-1===e.sign())throw new Error("Complex numbers are not supported");if(e.isZero())return new s(0n).trunc(r);if(e.isOne())return new s(1n).trunc(r);return d(n,e,r)},l=(n,t)=>h(2,n,t);class f{constructor(n,t){this.cachedDecimals=0,this.fn=n,this.max=t}get(n){if(n<=this.cachedDecimals)return this.cache.trunc(n);const t=new s(this.fn(n)),r=Math.min(this.max,n);return this.cachedDecimals!==r&&(this.cache=t.trunc(r),this.cachedDecimals=r),t}}const g=(n,t)=>{let r=o(c(n),t);if(r.isOne())return new s(0).trunc(t);if(r.lte(0n))throw new Error("Invalid parameter");let e=0;const i=c("0.1");for(;r.sub(1n).abs().gt(i);)r=new s(l(r,t+10)),e++;const u=function*(n,t){const r=n.pow(2n).normalize();let e=n,i=1n,o=c(n);for(;;){e=e.mul(r),i+=2n;const n=e.div(i).trunc(t+10);o=o.add(n),yield{term:n,sum:o}}}(r.sub(1n).div(r.add(1n)),t);for(const{term:n,sum:r}of u)if(n.isZero()){return r.mul(2n**BigInt(e+1)).trunc(t)}return c(0)},w=new f((n=>g(2n,n)),200),b=new f((n=>g(10n,n)),200);const p=(n,t)=>{const r=o(c(n),t),e=c(`1e-${t+5}`),i=function*(n,t){let r=n.add(1n),e=6n,i=4n;const o=n.pow(2n);let s=o;for(;;){const u=s.mul(n.add(i-1n)).div(e);e*=i*(i+1n),i+=2n,s=s.mul(o),r=r.add(u).trunc(t+5),yield{term:u,sum:r}}}(r,t);for(const{term:n,sum:r}of i)if(n.abs().lt(e))return r.trunc(t);return c(0)},E=new f((n=>{if(0===n)return c(3n);let t=1n,r=3n*10n**BigInt(n+20),e=r;for(;0n!==r;)r=r*t/(4n*(t+1n)),t+=2n,e+=r/t;return c(`3.${e.toString().slice(1,n+1)}`)}),1e3),N=n=>0===n?c(3):E.get(n).trunc(n),I=(t,r)=>{const e=new s(N(r+5)),i=e.mul(2n);let o=t.round(r+5,n.RoundingMode.NEAREST_AWAY_FROM_ZERO).div(i).fracPart();o.lt(0n)&&(o=o.add(1n)),o=o.round(r+5);const u=o.div("0.25").floor().toNumber()+1;let a=i.mul(o),m=o.mul(360n);return 4===u?(a=i.sub(a),m=c(360).sub(m)):3===u?(a=a.sub(e),m=m.sub(180)):2===u&&(a=e.sub(a),m=c(180).sub(m)),{quadrantDegrees:m.round(r),quadrant:u,subHalfPiAngle:a}};const v=(n,t,r)=>{let e=c(n);return t&&(e=e.neg()),e.trunc(r)},T=(t,r)=>{const e=r+10,i=o(c(t),r+5),{quadrantDegrees:s,subHalfPiAngle:u,quadrant:a}=I(i,r),m=2===a||3===a;if(s.isZero())return v("1",m,r);if(s.eq(30n))return v(c(l(3n,r+5)).div(2n),m,r);if(s.eq(45n))return v(c(l(2n,r+5)).div(2n),m,r);if(s.eq(60n))return v("0.5",m,r);if(s.eq(90n))return v("0",m,r);const d=c(`1e-${e}`),h=function*(t,r){const e=t.round(r+10,n.RoundingMode.NEAREST_AWAY_FROM_ZERO).pow(2n);let i=e,o=2n,s=c(1n).sub(i.div(o).trunc(r+10)),u=3n;for(;;){o*=u*(u+1n),u+=2n;const n=u*(u+1n);u+=2n,i=i.mul(e),o*=n;let t=i.mul(n);i=i.mul(e),t=t.sub(i);const a=t.div(o).trunc(r+10);s=s.add(a),yield{term:a,sum:s}}}(u,r);for(const{term:n,sum:t}of h)if(n.lt(d))return v(t,m,r);return c(0)};const O=(n,t)=>{let r=o(c(n),t);if(r.isZero())return c(0);if(r.abs().isOne())return c(N(t)).div(4*r.sign()).trunc(t);let e=0;const i=c("0.42");for(;r.abs().gt(i);){const n=c(l(r.pow(2n).add(1n),t+10));r=r.div(n.add(1n)),e++}const s=c(`1e-${t+10}`),u=function*(n,t){const r=n.pow(2n).normalize(),e=r.pow(2n).normalize();let i=3n,o=n.sub(n.mul(r).div(i)),s=n.mul(e);for(;;){i+=2n;const n=i+2n,u=s.mul(r.mul(-i).add(n)).div(i*n);i=n,s=s.mul(e),o=o.add(u).trunc(t+10),yield{term:u,sum:o}}}(r,t);for(const{term:n,sum:r}of u)if(n.abs().lt(s)){return r.mul(2n**BigInt(e)).trunc(t)}return c(0)},R=(n,t)=>{const r=o(c(n),t);if(r.isZero())return c(0);if(r.abs().isOne())return c(N(t)).mul(r.sign()).div(2n).trunc(t);if(r.abs().eq("1/2"))return c(N(t)).mul(r.sign()).div(6n).trunc(t);if(r.gt(1n)||r.lt(-1n))throw new Error("Out of range");const e=c(l(r.pow(2n).neg().add(1),t+10));return c(O(r.div(e.add(1n)),t+10)).mul(2).trunc(t)};const P=(n,t)=>{const r=o(c(n),t),e=new s(`1e-${t+5}`),i=function*(n,t){const r=n.pow(2n).normalize();let e=r,i=2n,o=e.div(i).add(1n).trunc(t+5),s=3n;for(;;){e=e.mul(r),i*=s*(s+1n),s+=2n;const n=e.div(i);o=o.add(n).trunc(t+5),yield{term:n,sum:o}}}(r,t);for(const{term:n,sum:r}of i)if(n.abs().lt(e))return r.trunc(t);return c(0)};n.ExactNumber=c,n.PI=N,n.acos=(n,t)=>{const r=o(c(n),t);if(r.isZero())return c(N(t)).div(2n).trunc(t);if(r.isOne())return c(0);if(r.abs().isOne())return N(t);if(r.abs().eq("1/2")){const n=c(N(t)).div(3n);return-1===r.sign()?n.mul(2n).trunc(t):n.trunc(t)}if(r.gt(1n)||r.lt(-1n))throw new Error("Out of range");return c(N(t+10)).div(2n).sub(R(r,t+10)).trunc(t)},n.acosh=(n,t)=>{const r=o(c(n),t);if(r.isOne())return c(0);if(r.lt(1n))throw new Error("Out of range");const e=l(r.pow(2).sub(1n),t+5);return g(r.add(e),t+5).trunc(t)},n.asin=R,n.asinh=(n,t)=>{const r=o(c(n),t);if(r.isZero())return c(0);const e=l(r.pow(2).add(1n),t+5);return g(r.add(e),t+5).trunc(t)},n.atan=O,n.atanh=(n,t)=>{const r=o(c(n),t);if(r.abs().gte(1n))throw new Error("Out of range");if(r.isZero())return c(0);const e=g(r.add(1n).div(r.neg().add(1n)),t+5);return c(e).div(2n).trunc(t)},n.cbrt=(n,t)=>h(3,n,t),n.cos=T,n.cosh=P,n.exp=p,n.log=g,n.log10=(n,t)=>new s(g(n,t+10)).div(b.get(t+10)).trunc(t),n.log2=(n,t)=>new s(g(n,t+10)).div(w.get(t+10)).trunc(t),n.logn=(n,t,r)=>{if(!Number.isSafeInteger(n)||n<2)throw new Error("Invalid parameter for N");const e=g(t,r+10),i=g(n,r+10);return new s(e).div(i).trunc(r)},n.nthroot=h,n.pow=(n,t,r)=>{const e=o(c(n),r),i=o(c(t),r);if(i.isInteger()&&Number.isSafeInteger(i.toNumber()))return e.pow(i).trunc(r);if(-1===e.sign()&&!i.isInteger())throw new Error("Complex numbers are not supported");const s=g(e,r+5),u=i.mul(s);return p(u,r+5).trunc(r)},n.sin=(n,t)=>{const r=new s(N(t+10)),e=o(c(n),t+5);return T(r.div(2n).sub(e),t+5).trunc(t)},n.sinh=(n,t)=>{const r=o(c(n),t),e=new s(`1e-${t+5}`),i=function*(n,t){let r=n,e=1n;const i=n.pow(2n).normalize();let o=n.trunc(t+5),s=2n;for(;;){r=r.mul(i),e*=s*(s+1n),s+=2n;const n=r.div(e);o=o.add(n).trunc(t+5),yield{term:n,sum:o}}}(r,t);for(const{term:n,sum:r}of i)if(n.abs().lt(e))return r.trunc(t);return c(0)},n.sqrt=l,n.tan=(n,t)=>{const r=o(c(n),t+5),{quadrantDegrees:e,quadrant:i,subHalfPiAngle:s}=I(r,t+5),u=1===i||3===i;if(e.isZero())return v("0",u,t);if(e.eq(30n))return v(c(1n).div(l(3n,t+5)),u,t);if(e.eq(45n))return v("1",u,t);if(e.eq(60n))return v(l(3n,t+5),u,t);if(e.eq(90n))throw new Error("Out of range");const a=c(T(s.mul(2n),t+5)),m=c(1n).sub(a).div(c(1n).add(a)).round(t+5),d=l(m,t+5).trunc(t);return u?d:d.neg()},n.tanh=(n,t)=>{const r=o(c(n),t);if(r.isZero())return c(0);const e=P(r,t+10).abs();return l(e.pow(2).sub(1),t+10).div(e).mul(r.sign()).trunc(t)},n.trimTrailingZeros=e,Object.defineProperty(n,"__esModule",{value:!0})})); | ||
!function(t,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports):"function"==typeof define&&define.amd?define(["exports"],r):r((t="undefined"!=typeof globalThis?globalThis:t||self).exactnumber={})}(this,(function(t){"use strict";var r,e;t.RoundingMode=void 0,(r=t.RoundingMode||(t.RoundingMode={}))[r.NEAREST_TO_POSITIVE=201008]="NEAREST_TO_POSITIVE",r[r.NEAREST_TO_NEGATIVE=201009]="NEAREST_TO_NEGATIVE",r[r.NEAREST_TO_EVEN=201010]="NEAREST_TO_EVEN",r[r.NEAREST_TO_ZERO=201011]="NEAREST_TO_ZERO",r[r.NEAREST_AWAY_FROM_ZERO=201012]="NEAREST_AWAY_FROM_ZERO",r[r.TO_POSITIVE=201001]="TO_POSITIVE",r[r.TO_NEGATIVE=201002]="TO_NEGATIVE",r[r.TO_ZERO=201003]="TO_ZERO",r[r.AWAY_FROM_ZERO=201004]="AWAY_FROM_ZERO",t.ModType=void 0,(e=t.ModType||(t.ModType={})).TRUNCATED="T",e.FLOORED="F",e.EUCLIDEAN="E";const n=t=>{const r=t.indexOf(".");if(-1===r)return t;let e=t.length;for(;e>r&&"0"===t.charAt(e-1);)e--;const n=r===e-1?r:e;return 0===n?"0":t.slice(0,n)},i=(t,r,e,i)=>{let o=t.toString();if(0===r&&0===e)return o;const s=o.startsWith("-");if(s&&(o=o.slice(1)),r>=o.length&&(o="0".repeat(r-o.length+1)+o),r>0){const t=o.slice(0,-r),s=o.slice(-r),u=e<=r?s.slice(0,e):`${s}${"0".repeat(e-r)}`;0!==u.length?(o=`${t}.${u}`,i&&(o=n(o))):o=t}else e>0&&!i&&(o=`${o}.${"0".repeat(e)}`);return s?`-${o}`:o},o=(r,e)=>(r=r.normalize())instanceof f?r.round(e,t.RoundingMode.NEAREST_AWAY_FROM_ZERO):r,s=BigInt(0),u=BigInt(1),a=BigInt(2),c=BigInt(3),m=BigInt(4),d=BigInt(5),h=BigInt(10),l=BigInt(24);class f{constructor(t,r=0){if(this.type="fixed","bigint"==typeof t)this.number=t,this.decimalPos=r;else{const r=this.parseConstructorParameter(t);this.number=r.number,this.decimalPos=r.decimalPos}}parseConstructorParameter(t){if(t instanceof f)return{number:t.number,decimalPos:t.decimalPos};if(t instanceof g){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 r=t.match(/^(-?[0-9]*)(?:\.([0-9]*))?(?:[eE]([+-]?[0-9]+))?$/);if(!r)throw new Error(`Cannot parse number "${t}"`);let e=0,n=r[1]??"0";if(void 0!==r[2]&&(n+=r[2],e+=r[2].length),void 0!==r[3]){const t=Number(r[3]);t>0?n+="0".repeat(t):e-=t}return{number:BigInt(n),decimalPos:e}}throw new Error("Unsupported parameter!")}scaleNumber(t,r){const e=Math.max(this.decimalPos,r);return{a:e===this.decimalPos?this.number:this.number*h**BigInt(e-this.decimalPos),b:e===r?t:t*h**BigInt(e-r),decimalPos:e}}add(t){const r=w(t);if(r instanceof g)return r.add(this);const e=r,{a:n,b:i,decimalPos:o}=this.scaleNumber(e.number,e.decimalPos);return new f(n+i,o)}sub(t){const r=w(t);return this.add(r.neg())}mul(t){const r=w(t);if(r instanceof g)return r.mul(this);const e=r,n=this.number*e.number;return new f(n,this.decimalPos+e.decimalPos)}pow(t){const r=w(t).toNumber();if(!Number.isSafeInteger(r))throw new Error("Unsupported parameter");const e=Math.abs(r),n=new f(this.number**BigInt(e),this.decimalPos*e);return r<0?n.inv():n}powm(t,r,e){let n=w(t).toNumber();if(!Number.isSafeInteger(n))throw new Error("Unsupported parameter");const i=w(r);let o=this,s=new f(u);for(;0!==n;)n%2!=0&&(s=s.mul(o).mod(i,e)),o=o.pow(a).mod(i,e),n=Math.floor(n/2);return s}div(t){return this.convertToFraction().div(t)}divToInt(t){const r=w(t);if(r instanceof g)return this.convertToFraction().divToInt(r);const e=r,{a:n,b:i}=this.scaleNumber(e.number,e.decimalPos);return new f(n/i)}mod(r,e=t.ModType.TRUNCATED){const n=w(r);if(n instanceof g)return this.convertToFraction().mod(n);const i=n,{a:o,b:u,decimalPos:a}=this.scaleNumber(i.number,i.decimalPos),c=o%u,m=new f(c,a);if(e===t.ModType.TRUNCATED)return m;if(e===t.ModType.FLOORED)return Number(o<s)^Number(u<s)?m.add(u):m;if(e===t.ModType.EUCLIDEAN)return c<s?m.add(u<s?-u:u):m;throw new Error("Invalid ModType")}abs(){return new f(this.number<s?-this.number:this.number,this.decimalPos)}neg(){return this.mul(-u)}inv(){return this.convertToFraction().inv()}floor(r){return 0===this.decimalPos?this:this.round(r,t.RoundingMode.TO_NEGATIVE)}ceil(r){return 0===this.decimalPos?this:this.round(r,t.RoundingMode.TO_POSITIVE)}trunc(r){return 0===this.decimalPos?this:this.round(r,t.RoundingMode.TO_ZERO)}isTieStr(t){if("5"!==t[0])return!1;for(let r=1;r<t.length;r++)if("0"!==t[r])return!1;return!0}_round(r,e){const n=this.decimalPos-r;if(n<=0)return this;const i=h**BigInt(n),o=this.number/i;if(e===t.RoundingMode.TO_ZERO)return new f(o,r);const c=this.number%i;if(c===s)return new f(o,r);if(e===t.RoundingMode.AWAY_FROM_ZERO){const t=this.number<s?o-u:o+u;return new f(t,r)}if(e===t.RoundingMode.TO_POSITIVE){const t=this.number<s?o:o+u;return new f(t,r)}if(e===t.RoundingMode.TO_NEGATIVE){const t=this.number>=s?o:o-u;return new f(t,r)}if(![void 0,t.RoundingMode.NEAREST_TO_ZERO,t.RoundingMode.NEAREST_AWAY_FROM_ZERO,t.RoundingMode.NEAREST_TO_POSITIVE,t.RoundingMode.NEAREST_TO_NEGATIVE,t.RoundingMode.NEAREST_TO_EVEN].includes(e))throw new Error("Invalid rounding mode. Use the predefined values from the RoundingMode enum.");let m=(c<s?-c:c).toString();if(m.length<n&&(m="0"),this.isTieStr(m)){if(e===t.RoundingMode.NEAREST_TO_ZERO)return new f(o,r);if(e===t.RoundingMode.NEAREST_AWAY_FROM_ZERO){const t=this.number<s?o-u:o+u;return new f(t,r)}if(void 0===e||e===t.RoundingMode.NEAREST_TO_POSITIVE){const t=this.number<s?o:o+u;return new f(t,r)}if(e===t.RoundingMode.NEAREST_TO_NEGATIVE){const t=this.number>=s?o:o-u;return new f(t,r)}if(e===t.RoundingMode.NEAREST_TO_EVEN){if(o%a===s)return new f(o,r);return new f(o<s?o-u:o+u,r)}}if(Number(m[0])<5)return new f(o,r);const d=this.number<s?o-u:o+u;return new f(d,r)}round(t,r){if(t=void 0===t?0:t,!Number.isSafeInteger(t)||t<0)throw new Error("Invalid value for decimals");return this._round(t,r).normalize()}_incExponent(t){if(0===t)return this;let r=this.number,e=this.decimalPos;if(t<0)e-=t;else{const n=Math.min(t,this.decimalPos);e-=n;const i=t-n;i>0&&(r*=h**BigInt(i))}return new f(r,e)}countDigits(){if(this.number===s)return 1;let t=0,r=this.number<s?-this.number:this.number;for(;r>s;)r/=h,t++;return t}toSubZeroNum(){const t=this.countDigits();return{subZeroNum:new f(this.number,t),exponentDiff:t-this.decimalPos}}roundToDigits(t,r){if(!Number.isSafeInteger(t)||t<1)throw new Error("Invalid value for digits");const{subZeroNum:e,exponentDiff:n}=this.toSubZeroNum();let i=e.round(t,r);return i=i._incExponent(n),i}intPart(){return this.trunc()}fracPart(){return this.sub(this.trunc())}sign(){return this.number<s?-1:1}bitwiseAnd(t){if(t=b(t),!this.isInteger()||-1===this.sign()||!t.isInteger()||-1===t.sign())throw new Error("Only positive integers are supported");t instanceof g&&(t=t.trunc());const r=a**l;let e=this.normalize().number,n=t.trunc().normalize().number,i=s,o=u;for(;e>s&&n>s;){const t=BigInt.asUintN(24,e),s=BigInt.asUintN(24,n);i+=BigInt(Number(t)&Number(s))*o,o*=r,e/=r,n/=r}return new f(i)}bitwiseOr(t){if(t=b(t),!this.isInteger()||-1===this.sign()||!t.isInteger()||-1===t.sign())throw new Error("Only positive integers are supported");t instanceof g&&(t=t.trunc());const r=a**l;let e=this.normalize().number,n=t.trunc().normalize().number,i=s,o=u;for(;e>s||n>s;){const t=BigInt.asUintN(24,e),s=BigInt.asUintN(24,n);i+=BigInt(Number(t)|Number(s))*o,o*=r,e/=r,n/=r}return new f(i)}bitwiseXor(t){if(t=b(t),!this.isInteger()||-1===this.sign()||!t.isInteger()||-1===t.sign())throw new Error("Only positive integers are supported");t instanceof g&&(t=t.trunc());const r=a**l;let e=this.normalize().number,n=t.trunc().normalize().number,i=s,o=u;for(;e>s||n>s;){const t=BigInt.asUintN(24,e),s=BigInt.asUintN(24,n);i+=BigInt(Number(t)^Number(s))*o,o*=r,e/=r,n/=r}return new f(i)}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 r=a**BigInt(t);return this.mul(r)}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 r=a**BigInt(t);return new f(this.normalize().number/r)}cmp(t){const r=w(t);if(r instanceof g)return-r.cmp(this);const e=r,{a:n,b:i}=this.scaleNumber(e.number,e.decimalPos);return n===i?0:n>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,r){const e=b(t),n=b(r);if(e.gt(n))throw new Error("Min parameter has to be smaller than max");return this.lt(e)?e:this.gt(n)?n:this}isZero(){return this.number===s}isOne(){if(0===this.decimalPos)return this.number===u;const t=h**BigInt(this.decimalPos),r=this.number/t;return r===u&&r*t===this.number}isInteger(){return 0===this.decimalPos||this.number%h**BigInt(this.decimalPos)===s}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,r=this.number;for(;t>0&&r%h===s;)t--,r/=h;return new f(r,t)}convertToFraction(){if(0===this.decimalPos)return new g(this.number,u);const t=h**BigInt(this.decimalPos);return new g(this.number,t)}toNumber(){return Number(this.toPrecision(20))}toFixed(r,e=t.RoundingMode.TO_ZERO,n=!1){if(!Number.isSafeInteger(r)||r<0)throw new Error("Invalid parameter");const o=this._round(r,e);return i(o.number,o.decimalPos,r,n)}toExponential(r,e=t.RoundingMode.TO_ZERO,i=!1){if(!Number.isSafeInteger(r)||r<0)throw new Error("Invalid parameter");const o=this.roundToDigits(r+1,e).normalize(),s=-1===o.sign(),u=o.abs(),a=u.number.toString(),c=a.length<=r?`${a}${"0".repeat(r-a.length+1)}`:a.slice(0,r+1);let m=c;c.length>1&&(m=`${c.slice(0,1)}.${c.slice(1)}`,i&&(m=n(m)));const d=u.decimalPos,h=a.length-1-d;return`${s?"-":""}${m}e${h>=0?"+":""}${h}`}toBase(t,r){if(!Number.isSafeInteger(t)||t<2||t>16)throw new Error("Invalid radix");if(void 0!==r&&(!Number.isSafeInteger(r)||r<0))throw new Error("Invalid parameter");const e=this.normalize();if(0===e.decimalPos)return e.number.toString(t);const n=void 0===r?Number.MAX_SAFE_INTEGER:r;let i=e.intPart(),o=e.sub(i);const s=-1===e.sign();s&&(i=i.neg(),o=o.neg());const u=new Map;let a=[];for(;!o.isZero();){const r=o.mul(t),e=r.toString(),i=u.get(e);if(void 0!==i){a=[...a.slice(0,i-1),"(",...a.slice(i-1),")"];break}if(a.length===n)break;const s=Math.abs(r.intPart().toNumber());a.push(s.toString(t)),o=r.fracPart(),u.set(e,a.length)}const c=a.join("");return`${s?"-":""}${i.number.toString(t)}${a.length?".":""}${c}`}toFraction(){return this.convertToFraction().toFraction()}toString(t,r){if(void 0===t||10===t){const t=void 0!==r?this.trunc(r):this;return i(t.number,t.decimalPos,t.decimalPos,!0)}return this.toBase(t,r)}toPrecision(r,e=t.RoundingMode.TO_ZERO,o=!1){if(!Number.isSafeInteger(r)||r<1)throw new Error("Invalid parameter");const s=this.roundToDigits(r,e),{subZeroNum:u,exponentDiff:a}=s.toSubZeroNum(),c=-1===u.sign();let m=i(u.number,u.decimalPos,u.decimalPos,!1);m=m.slice(c?3:2),m=m.slice(0,Math.max(r,a));const d=m.slice(0,Math.max(0,a)),h=m.slice(Math.max(0,a)),l=Math.max(0,r-d.length-h.length),f="0".repeat(a<0?-a:0);let g=d||"0";if(h.length+f.length+l>0){g+=`.${f}${h}${"0".repeat(l)}`,o&&(g=n(g))}return c?`-${g}`:g}valueOf(){throw new Error("Unsafe conversion to Number type! Use toNumber() instead.")}}class g{constructor(t,r){if(this.type="fraction","bigint"==typeof t&&"bigint"==typeof r)this.numerator=t,this.denominator=r;else{const e=this.parseParameter(t),n=this.parseParameter(r),i=e.div(n),o=i instanceof f?i.convertToFraction():i;this.numerator=o.numerator,this.denominator=o.denominator}if(this.denominator===s)throw new Error("Division by zero")}parseRepeatingDecimal(t){if(!t.includes("("))return new f(t).convertToFraction();const r=(t=t.trim()).match(/^(-?[0-9]*)\.([0-9]+)?\(([0-9]+)\)(?:[eE]([+-]?[0-9]+))?$/);if(!r)throw new Error(`Cannot parse string "${t}"`);const e="-"===r[1]?"-0":r[1],n=r[2]??"",i=r[3],o=r[4],s=BigInt(e+n+i)-BigInt(e+n),u=BigInt("9".repeat(i.length)+"0".repeat(n.length)),a=new g(s,u);if(void 0!==o){const t=o.startsWith("-"),r=h**BigInt(t?o.slice(1):o);return t?a.div(r).normalize():a.mul(r).normalize()}return a.simplify()}parseParameter(t){if(t instanceof g)return t;if(t instanceof f)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 g(BigInt(t),u)}if("bigint"==typeof t)return new g(t,u);if("string"==typeof t){const r=t.split("/");if(r.length>2)throw new Error(`Cannot parse string '${t}'`);const e=this.parseRepeatingDecimal(r[0]),n=r[1]?this.parseRepeatingDecimal(r[1]):new g(u,u);return e.div(n).convertToFraction()}throw new Error("Unsupported parameter!")}add(t){const{numerator:r,denominator:e}=this.parseParameter(t);return this.denominator===e?new g(this.numerator+r,this.denominator):new g(this.numerator*e+r*this.denominator,e*this.denominator)}sub(t){const{numerator:r,denominator:e}=this.parseParameter(t);return this.add(new g(-r,e))}mul(t){const{numerator:r,denominator:e}=this.parseParameter(t);return new g(this.numerator*r,this.denominator*e)}div(t){const{numerator:r,denominator:e}=this.parseParameter(t);return this.mul(new g(e,r))}divToInt(t){return this.div(t).trunc()}mod(r,e=t.ModType.TRUNCATED){const n=this.parseParameter(r),i=n.denominator*this.numerator%(n.numerator*this.denominator),o=this.denominator*n.denominator,s=new g(i,o);if(e===t.ModType.TRUNCATED)return s;if(e===t.ModType.FLOORED)return Number(-1===this.sign())^Number(-1===n.sign())?s.add(n):s;if(e===t.ModType.EUCLIDEAN)return-1===s.sign()?s.add(-1===n.sign()?n.neg():n):s;throw new Error("Invalid ModType")}pow(t){const r=this.parseParameter(t);if(!r.isInteger())throw new Error("Unsupported parameter");const e=r.numerator/r.denominator,n=e<s?-e:e,i=new g(this.numerator**n,this.denominator**n);return e<s?i.inv():i}powm(t,r,e){const n=this.parseParameter(t);if(!n.isInteger())throw new Error("Unsupported parameter");let i=n.toNumber();const o=this.parseParameter(r);let s=this,c=new g(u,u);for(;0!==i;)i%2!=0&&(c=c.mul(s).mod(o,e)),s=s.pow(a).mod(o,e),i=Math.floor(i/2);return c}inv(){return new g(this.denominator,this.numerator)}floor(r){return this.denominator===u?new f(this.numerator):this.round(r,t.RoundingMode.TO_NEGATIVE)}ceil(r){return this.denominator===u?new f(this.numerator):this.round(r,t.RoundingMode.TO_POSITIVE)}trunc(r){return this.denominator===u?new f(this.numerator):this.round(r,t.RoundingMode.TO_ZERO)}round(t,r){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(t,r);return new f(`${e.toFixed(t+1)}1`).round(t,r)}roundToDigits(t,r){if(!Number.isSafeInteger(t)||t<1)throw new Error("Invalid value for digits");if(this.isZero())return new f(s);let e=this.abs(),n=0;for(;e.gte(u);)e=e.div(h),n++;const i=new g(u,h);for(;e.lt(i);)e=e.mul(h),n--;let o=e.round(t,r);return o=o._incExponent(n),-1===this.sign()?o.neg():o}gcd(t,r){let e=t<s?-t:t,n=r<s?-r:r;if(n>e){const t=e;e=n,n=t}for(;;){if(n===s)return e;if(e%=n,e===s)return n;n%=e}}simplify(){let{numerator:t,denominator:r}=this;const e=this.gcd(t,r);return e>u&&(t/=e,r/=e),r<s&&(t=-t,r=-r),new g(t,r)}normalize(){const{numerator:r,denominator:e}=this.simplify();if(e===u)return new f(r,0);const n=new g(r,e),{cycleLen:i,cycleStart:o}=n.getDecimalFormat(0);return 0!==i?n:n.round(o,t.RoundingMode.TO_ZERO)}getFractionParts(t=!0){const r=t?this.simplify():this;return{numerator:new f(r.numerator),denominator:new f(r.denominator)}}sign(){return(this.numerator<s?-1:1)*(this.denominator<s?-1:1)}abs(){return new g(this.numerator<s?-this.numerator:this.numerator,this.denominator<s?-this.denominator:this.denominator)}neg(){return this.mul(-u)}intPart(){return this.trunc()}fracPart(){return this.sub(this.trunc())}cmp(t){const r=this.parseParameter(t),e=this.denominator===r.denominator,n=e?this.numerator:this.numerator*r.denominator,i=e?r.numerator:r.numerator*this.denominator;return n===i?0:n>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,r){const e=b(t),n=b(r);if(e.gt(n))throw new Error("Min parameter has to be smaller than max");return this.lt(e)?e:this.gt(n)?n:this}isZero(){return this.numerator===s}isOne(){return this.numerator===this.denominator}isInteger(){return this.numerator%this.denominator===s}serialize(){return[this.numerator,this.denominator]}toNumber(){return Number(this.toPrecision(20))}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 r=this.denominator<s?-this.denominator:this.denominator,e=0;for(;r%a===s;)r/=a,e++;let n=0;for(;r%d===s;)r/=d,n++;const i=Math.max(e,n);if(r===u)return{cycleLen:0,cycleStart:i};const o=Math.max(1,t-i);let c=h%r,m=1;for(;c!==u;){if(m===o)return{cycleLen:null,cycleStart:i};c=c*h%r,m++}return{cycleLen:m,cycleStart:i}}toFixed(r,e=t.RoundingMode.TO_ZERO,n=!1){if(!Number.isSafeInteger(r)||r<0)throw new Error("Invalid parameter");return this.round(r,e).toFixed(r,t.RoundingMode.TO_ZERO,n)}toRepeatingParts(t){if(this.isZero())return["0","",""];const{cycleLen:r,cycleStart:e}=this.simplify().getDecimalFormat(t);if(null===r||0===r){const r=t??e,i=this.toFixed(r),o=n(i).split(".");return[o[0],o[1]??"",""]}const i=e+r,o=this.toFixed(i).split(".");return[o[0],o[1].slice(0,e),o[1].slice(e)]}toRepeatingDigits(t){const r=this.toRepeatingParts(t);let e=r[0];return(r[1]||r[2])&&(e+=`.${r[1]}`),r[2]&&(e+=`(${r[2]})`),e}toExponential(r,e=t.RoundingMode.TO_ZERO,n=!1){if(!Number.isSafeInteger(r)||r<0)throw new Error("Invalid parameters");return this.toFixedNumber(r).toExponential(r,e,n)}toFraction(){const{numerator:t,denominator:r}=this.getFractionParts(!0);return`${t.toString()}/${r.toString()}`}toFixedNumber(t){const r=this.numerator*h**BigInt(t);return new f(r/this.denominator,t)}toBase(t,r){if(!Number.isSafeInteger(t)||t<2||t>16)throw new Error("Invalid radix");if(void 0!==r&&(!Number.isSafeInteger(r)||r<0))throw new Error("Invalid parameter");if(10===t)return void 0===r?this.toRepeatingDigits(r):n(this.toFixed(r));const e=this.normalize(),i=void 0===r?Number.MAX_SAFE_INTEGER:r+1;let o=e.intPart(),s=e.sub(o);const u=-1===e.sign();u&&(o=o.neg(),s=s.neg());const a=new Map;let c=[];for(;!s.isZero()&&c.length!==i;){const r=s.mul(t),e=r.normalize().toFraction(),n=a.get(e);if(void 0!==n){c=[...c.slice(0,n-1),"(",...c.slice(n-1),")"];break}const i=Math.abs(r.intPart().toNumber());c.push(i.toString(t)),s=r.fracPart(),a.set(e,c.length)}c.length===i&&c.pop();const m=c.join("");return`${u?"-":""}${o.toString(t)}${c.length?".":""}${m}`}toString(t,r){return void 0===t||10===t?this.toRepeatingDigits(r):this.toBase(t,r)}toPrecision(r,e=t.RoundingMode.TO_ZERO,n=!1){if(!Number.isSafeInteger(r)||r<1)throw new Error("Invalid parameter");return this.roundToDigits(r,e).toPrecision(r,t.RoundingMode.TO_ZERO,n)}valueOf(){throw new Error("Unsafe conversion to Number type! Use toNumber() instead.")}}function w(t){if(t instanceof f||t instanceof g)return t;if("bigint"==typeof t)return new f(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 f(t)}if("string"==typeof t)return t.includes("/")||t.includes("(")?new g(t,u):new f(t);throw new Error("Unsupported parameter type")}const b=(t,r)=>{if(void 0===t)throw new Error("First parameter cannot be undefined");const e=w(t);if(void 0===r)return e;const n=w(r);return new g(e,u).div(new g(n,u))};b.min=(...t)=>{if(0===t.length)throw new Error("Got empty array");let r=b(t[0]);for(let e=1;e<t.length;e++){const n=b(t[e]);n.lt(r)&&(r=n)}return r},b.max=(...t)=>{if(0===t.length)throw new Error("Got empty array");let r=b(t[0]);for(let e=1;e<t.length;e++){const n=b(t[e]);n.gt(r)&&(r=n)}return r};const p=(t,r)=>{let e=s;for(let n=0;n<t.length;n++){const i=t.charAt(n),o=parseInt(i,r);if(Number.isNaN(o))throw new Error(`Invalid digit "${i}"`);e*=BigInt(r),e+=BigInt(o)}return e};b.fromBase=(t,r)=>{if("string"!=typeof t)throw new Error("First parameter must be string");if(!Number.isSafeInteger(r)||r<2||r>16)throw new Error("Invalid radix");if(10===r)return b(t);if(0===(t=t.trim()).length)throw new Error("Empty string is not allowed");const e=t.startsWith("-");e&&(t=t.slice(1));const n=t.match(/^([0-9a-f]*)(?:\.([0-9a-f]*)(?:\(([0-9a-f]+)\))?)?$/i);if(!n)throw new Error(`Cannot parse number "${t}"`);const i=n[1]??"",o=n[2]??"",s=n[3]??"";if(s.length>0){const t=p(`${i}${o}${s}`,r)-p(`${i}${o}`,r),n=p((r-1).toString(r).repeat(s.length)+"0".repeat(o.length),r),u=new g(t,n).normalize();return e?u.neg():u}const a=p(i,r),c=p(o,r),m=new g(c,BigInt(r)**BigInt(o.length)),d=new g(a,u).add(m).normalize();return e?d.neg():d},b.range=function*(t,r,e){const n=b(r),i=b(e??1);let o=b(t);for(;o.lt(n);)yield o,o=o.add(i)},b.gcd=(t,r)=>{const e=b(t).abs(),n=b(r).abs();let i=n.gt(e)?n:e,o=i.eq(e)?n:e;for(;;){if(o.isZero())return i;if(i=i.mod(o),i.isZero())return o;o=o.mod(i)}},b.lcm=(t,r)=>{const e=b(t).abs(),n=b(r).abs(),i=e.mul(n);if(i.isZero())throw new Error("LCM of zero is undefined");const o=b.gcd(e,n);return i.div(o)};const E=(t,r,e)=>{const n=((t,r)=>{let e=r.toNumber();if(Number.isFinite(e)){const r=e<0;r&&(e=-e);let n=e**(1/t);return r&&(n=-n),n.toString()}const n=r.abs().toFixed(0).length,i=Math.ceil(n/t);return`${1===r.sign()?"":"-"}5e${i}`})(t,r);let i=new f("0"!==n?n:"1");const o=new g(t-1,t),s=new g(r,t),u=BigInt(t-1);let a=i.trunc(e+5);for(;i=o.mul(i).add(s.mul(i.pow(u).inv())),i=i.trunc(e+5),!i.isZero()&&!a.eq(i);)a=i;return i.trunc(e)},I=(t,r,e)=>{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");const n=o(b(r),e);if(1===t)return n.trunc(e);if(t%2==0&&-1===n.sign())throw new Error("Complex numbers are not supported");if(n.isZero())return new f(s).trunc(e);if(n.isOne())return new f(u).trunc(e);return E(t,n,e)},N=(t,r)=>I(2,t,r);class v{constructor(t,r){this.cachedDecimals=0,this.fn=t,this.max=r}get(t){if(t<=this.cachedDecimals)return this.cache.trunc(t);const r=new f(this.fn(t)),e=Math.min(this.max,t);return this.cachedDecimals!==e&&(this.cache=r.trunc(e),this.cachedDecimals=e),r}}const T=(t,r)=>{let e=o(b(t),r);if(e.isOne())return new f(0).trunc(r);if(e.lte(0))throw new Error("Invalid parameter");let n=0;const i=b("0.1");for(;e.sub(u).abs().gt(i);)e=new f(N(e,r+10)),n++;const c=function*(t,r){const e=t.pow(a).normalize();let n=t,i=u,o=b(t);for(;;){n=n.mul(e),i+=a;const t=n.div(i).trunc(r+10);o=o.add(t),yield{term:t,sum:o}}}(e.sub(u).div(e.add(u)),r);for(const{term:t,sum:e}of c)if(t.isZero()){return e.mul(a**BigInt(n+1)).trunc(r)}return b(s)},O=new v((t=>T(a,t)),200),R=new v((t=>T(h,t)),200);const P=(t,r)=>{const e=o(b(t),r),n=b(`1e-${r+5}`),i=function*(t,r){let e=t.add(1),n=BigInt(6),i=m;const o=t.pow(a);let s=o;for(;;){const c=s.mul(t.add(i-u)).div(n);n*=i*(i+u),i+=a,s=s.mul(o),e=e.add(c).trunc(r+5),yield{term:c,sum:e}}}(e,r);for(const{term:t,sum:e}of i)if(t.abs().lt(n))return e.trunc(r);return b(s)},_=new v((t=>{if(0===t)return b(c);let r=u,e=c*h**BigInt(t+20),n=e;for(;e!==s;)e=e*r/((r+u)*m),r+=a,n+=e/r;return b(`3.${n.toString().slice(1,t+1)}`)}),1e3),S=t=>0===t?b(c):_.get(t).trunc(t),M=(r,e)=>{let n=r.round(e+5,t.RoundingMode.NEAREST_AWAY_FROM_ZERO);const i=S(e+5),o=((t,r,e)=>{const n=Math.max(3,e),i=t.trunc(n),o=i.div(r).round();return r.mul(o).trunc(n).eq(i)?o:null})(n,i.div(12),e);if(null!==o)return(t=>{let r=t.mod(l).toNumber();r<0&&(r+=24);const e=Math.floor(r/6)+1;let n=15*r;return 4===e?n=360-n:3===e?n-=180:2===e&&(n=180-n),{specialCaseDeg:n,quadrant:e,subHalfPiAngle:null}})(o);const s=i.mul(a);n=n.mod(s),-1===n.sign()&&(n=n.add(s));const u=n.mul(a).div(i).floor().toNumber()+1;let c=n;return 4===u?c=s.sub(c):3===u?c=c.sub(i):2===u&&(c=i.sub(c)),{specialCaseDeg:null,quadrant:u,subHalfPiAngle:c}};const A=(t,r,e)=>{let n=b(t);return r&&(n=n.neg()),n.trunc(e)},y=(r,e)=>{const n=e+10,i=o(b(r),e+5),{specialCaseDeg:m,subHalfPiAngle:d,quadrant:h}=M(i,e),l=2===h||3===h;if(null!==m){if(0===m)return A(u,l,e);if(30===m)return A(b(N(c,e+5)).div(a),l,e);if(45===m)return A(b(N(a,e+5)).div(a),l,e);if(60===m)return A("0.5",l,e);if(90===m)return A(s,l,e);throw new Error}const f=b(`1e-${n}`),g=function*(r,e){const n=r.round(e+10,t.RoundingMode.NEAREST_AWAY_FROM_ZERO).pow(a);let i=n,o=a,s=b(u).sub(i.div(o).trunc(e+10)),m=c;for(;;){o*=m*(m+u),m+=a;const t=m*(m+u);m+=a,i=i.mul(n),o*=t;let r=i.mul(t);i=i.mul(n),r=r.sub(i);const c=r.div(o).trunc(e+10);s=s.add(c),yield{term:c,sum:s}}}(d,e);for(const{term:t,sum:r}of g)if(t.lt(f))return A(r,l,e);return b(0)};const F=(t,r)=>{let e=o(b(t),r);if(e.isZero())return b(0);if(e.abs().isOne())return b(S(r)).div(4*e.sign()).trunc(r);let n=0;const i=b("0.42");for(;e.abs().gt(i);){const t=b(N(e.pow(a).add(u),r+10));e=e.div(t.add(u)),n++}const s=b(`1e-${r+10}`),m=function*(t,r){const e=t.pow(a).normalize(),n=e.pow(a).normalize();let i=c,o=t.sub(t.mul(e).div(i)),s=t.mul(n);for(;;){i+=a;const t=i+a,u=s.mul(e.mul(-i).add(t)).div(i*t);i=t,s=s.mul(n),o=o.add(u).trunc(r+10),yield{term:u,sum:o}}}(e,r);for(const{term:t,sum:e}of m)if(t.abs().lt(s)){return e.mul(a**BigInt(n)).trunc(r)}return b(0)},B=(t,r)=>{const e=o(b(t),r);if(e.isZero())return b(s);if(e.abs().isOne())return b(S(r)).mul(e.sign()).div(a).trunc(r);if(e.abs().eq("1/2"))return b(S(r)).mul(e.sign()).div(6).trunc(r);if(e.gt(u)||e.lt(-u))throw new Error("Out of range");const n=b(N(e.pow(a).neg().add(u),r+10));return b(F(e.div(n.add(u)),r+10)).mul(a).trunc(r)};const Z=(t,r)=>{const e=o(b(t),r),n=new f(`1e-${r+5}`),i=function*(t,r){const e=t.pow(a).normalize();let n=e,i=a,o=n.div(i).add(u).trunc(r+5),s=c;for(;;){n=n.mul(e),i*=s*(s+u),s+=a;const t=n.div(i);o=o.add(t).trunc(r+5),yield{term:t,sum:o}}}(e,r);for(const{term:t,sum:e}of i)if(t.abs().lt(n))return e.trunc(r);return b(s)};t.ExactNumber=b,t.PI=S,t.acos=(t,r)=>{const e=o(b(t),r);if(e.isZero())return b(S(r)).div(a).trunc(r);if(e.isOne())return b(s);if(e.abs().isOne())return S(r);if(e.abs().eq("1/2")){const t=b(S(r)).div(c);return-1===e.sign()?t.mul(a).trunc(r):t.trunc(r)}if(e.gt(u)||e.lt(-u))throw new Error("Out of range");return b(S(r+10)).div(a).sub(B(e,r+10)).trunc(r)},t.acosh=(t,r)=>{const e=o(b(t),r);if(e.isOne())return b(s);if(e.lt(u))throw new Error("Out of range");const n=N(e.pow(a).sub(u),r+5);return T(e.add(n),r+5).trunc(r)},t.asin=B,t.asinh=(t,r)=>{const e=o(b(t),r);if(e.isZero())return b(s);const n=N(e.pow(a).add(u),r+5);return T(e.add(n),r+5).trunc(r)},t.atan=F,t.atanh=(t,r)=>{const e=o(b(t),r);if(e.abs().gte(u))throw new Error("Out of range");if(e.isZero())return b(s);const n=T(e.add(u).div(e.neg().add(u)),r+5);return b(n).div(a).trunc(r)},t.cbrt=(t,r)=>I(3,t,r),t.cos=y,t.cosh=Z,t.exp=P,t.log=T,t.log10=(t,r)=>new f(T(t,r+10)).div(R.get(r+10)).trunc(r),t.log2=(t,r)=>new f(T(t,r+10)).div(O.get(r+10)).trunc(r),t.logn=(t,r,e)=>{if(!Number.isSafeInteger(t)||t<2)throw new Error("Invalid parameter for N");const n=T(r,e+10),i=T(t,e+10);return new f(n).div(i).trunc(e)},t.nthroot=I,t.pow=(t,r,e)=>{const n=o(b(t),e),i=o(b(r),e);if(i.isInteger()&&Number.isSafeInteger(i.toNumber()))return n.pow(i).trunc(e);if(-1===n.sign()&&!i.isInteger())throw new Error("Complex numbers are not supported");const s=T(n,e+5),u=i.mul(s);return P(u,e+5).trunc(e)},t.sin=(t,r)=>{const e=new f(S(r+10)),n=o(b(t),r+5);return y(e.div(a).sub(n),r+5).trunc(r)},t.sinh=(t,r)=>{const e=o(b(t),r),n=new f(`1e-${r+5}`),i=function*(t,r){let e=t,n=u;const i=t.pow(a).normalize();let o=t.trunc(r+5),s=a;for(;;){e=e.mul(i),n*=s*(s+u),s+=a;const t=e.div(n);o=o.add(t).trunc(r+5),yield{term:t,sum:o}}}(e,r);for(const{term:t,sum:e}of i)if(t.abs().lt(n))return e.trunc(r);return b(s)},t.sqrt=N,t.tan=(t,r)=>{const e=o(b(t),r+5),{specialCaseDeg:n,quadrant:i,subHalfPiAngle:s}=M(e,r),m=1===i||3===i;if(null!==n){if(0===n)return A("0",m,r);if(30===n)return A(b(u).div(N(c,r+5)),m,r);if(4===n)return A("1",m,r);if(60===n)return A(N(c,r+5),m,r);if(90===n)throw new Error("Out of range");throw new Error}const d=b(y(s.mul(a),r+5)),h=b(u).sub(d).div(b(u).add(d)).round(r+5),l=N(h,r+5).trunc(r);return m?l:l.neg()},t.tanh=(t,r)=>{const e=o(b(t),r);if(e.isZero())return b(s);const n=Z(e,r+10).abs();return N(n.pow(a).sub(u),r+10).div(n).mul(e.sign()).trunc(r)}})); |
import { ExactNumberType } from '../types'; | ||
export declare const PI: (decimals: number) => ExactNumberType; | ||
declare type EvaluationRes = { | ||
specialCaseDeg: number | null; | ||
quadrant: number; | ||
subHalfPiAngle: ExactNumberType | null; | ||
}; | ||
export declare const evaluateAngle: (x: ExactNumberType, decimals: number) => EvaluationRes; | ||
export declare const cos: (_angle: number | bigint | string | ExactNumberType, decimals: number) => ExactNumberType; | ||
export declare const sin: (angle: number | bigint | string | ExactNumberType, decimals: number) => ExactNumberType; | ||
export declare const tan: (angle: number | bigint | string | ExactNumberType, decimals: number) => ExactNumberType; | ||
export {}; |
@@ -14,2 +14,3 @@ import { Fraction } from './Fraction'; | ||
pow(x: number | bigint | string | ExactNumberType): ExactNumberType; | ||
powm(_exp: number | bigint | string | ExactNumberType, _mod: number | bigint | string | ExactNumberType, modType?: ModType): FixedNumber; | ||
div(x: number | bigint | string | ExactNumberType): ExactNumberType; | ||
@@ -57,9 +58,9 @@ divToInt(x: number | bigint | string | ExactNumberType): ExactNumberType; | ||
toNumber(): number; | ||
toFixed(decimals: number, roundingMode?: RoundingMode): string; | ||
toExponential(digits: number, roundingMode?: RoundingMode): string; | ||
toFixed(decimals: number, roundingMode?: RoundingMode, trimZeros?: boolean): string; | ||
toExponential(digits: number, roundingMode?: RoundingMode, trimZeros?: boolean): string; | ||
private toBase; | ||
toFraction(): string; | ||
toString(radix?: number, maxDigits?: number): string; | ||
toPrecision(digits: number, roundingMode?: RoundingMode): string; | ||
toPrecision(digits: number, roundingMode?: RoundingMode, trimZeros?: boolean): string; | ||
valueOf(): number; | ||
} |
@@ -17,2 +17,3 @@ import { ExactNumberType, ModType, RoundingMode } from './types'; | ||
pow(x: number | bigint | string | ExactNumberType): ExactNumberType; | ||
powm(_exp: number | bigint | string | ExactNumberType, _mod: number | bigint | string | ExactNumberType, modType?: ModType): ExactNumberType; | ||
inv(): ExactNumberType; | ||
@@ -56,6 +57,6 @@ floor(decimals?: number): FixedNumber; | ||
private getDecimalFormat; | ||
toFixed(decimals: number, roundingMode?: RoundingMode): string; | ||
toFixed(decimals: number, roundingMode?: RoundingMode, trimZeros?: boolean): string; | ||
private toRepeatingParts; | ||
toRepeatingDigits(maxDigits: number | undefined): string; | ||
toExponential(digits: number, roundingMode?: RoundingMode): string; | ||
toExponential(digits: number, roundingMode?: RoundingMode, trimZeros?: boolean): string; | ||
toFraction(): string; | ||
@@ -65,4 +66,4 @@ private toFixedNumber; | ||
toString(radix?: number, maxDigits?: number): string; | ||
toPrecision(digits: number, roundingMode?: RoundingMode): string; | ||
toPrecision(digits: number, roundingMode?: RoundingMode, trimZeros?: boolean): string; | ||
valueOf(): number; | ||
} |
export { ExactNumber } from './ExactNumber'; | ||
export { RoundingMode, ModType, ExactNumberType, ExactNumberParameter } from './types'; | ||
export { trimTrailingZeros } from './util'; | ||
export * from './approx'; | ||
export { nthroot, sqrt, cbrt } from './approx/roots'; | ||
export { pow, exp } from './approx/exponential'; | ||
export { log, logn, log10, log2 } from './approx/logarithm'; | ||
export { PI, sin, cos, tan } from './approx/trigonometry'; | ||
export { asin, acos, atan } from './approx/inverse_trigonometry'; | ||
export { sinh, cosh, tanh } from './approx/hyperbolic'; | ||
export { asinh, acosh, atanh } from './approx/inverse_hyperbolic'; |
@@ -38,3 +38,4 @@ import { Fraction } from './Fraction'; | ||
pow(x: number | bigint | string | ExactNumberType): ExactNumberType; | ||
/** Returns b^e mod m (modular exponentiation) */ | ||
/** Returns modulo of this number exponentiated to the given value (modular exponentiation) */ | ||
powm(exponent: number | bigint | string | ExactNumberType, modulus: number | bigint | string | ExactNumberType, type?: ModType): ExactNumberType; | ||
/** Returns the result of the division of this number by the given one. */ | ||
@@ -117,7 +118,7 @@ div(x: number | bigint | string | ExactNumberType): ExactNumberType; | ||
*/ | ||
toFixed(decimals: number, roundingMode?: RoundingMode): string; | ||
toFixed(decimals: number, roundingMode?: RoundingMode, trimZeros?: boolean): string; | ||
/** Returns a string representing the number in exponential notation. | ||
* Defaults to RoundingMode.TO_ZERO | ||
*/ | ||
toExponential(digits: number, roundingMode?: RoundingMode): string; | ||
toExponential(digits: number, roundingMode?: RoundingMode, trimZeros?: boolean): string; | ||
/** Returns a string representing the number using fixed-point notation, rounded to the specified number of significant digits. | ||
@@ -127,3 +128,3 @@ * In contrary to JS Number.toPrecision(), this function never returns exponential notation. | ||
*/ | ||
toPrecision(digits: number, roundingMode?: RoundingMode): string; | ||
toPrecision(digits: number, roundingMode?: RoundingMode, trimZeros?: boolean): string; | ||
/** Converts current value to a JavaScript Number */ | ||
@@ -130,0 +131,0 @@ toNumber(): number; |
import { FixedNumber } from './FixedNumber'; | ||
import { ExactNumberType } from './types'; | ||
/** Trims trailing zeros from numbers in fixed-point format (1.23000 -> 1.23) */ | ||
export declare const trimTrailingZeros: (num: string) => string; | ||
export declare const trimTrailingZerosFromFixed: (num: string) => string; | ||
export declare const bigIntToStr: (num: bigint, inputDecimals: number, outputDecimals: number, trimZeros: boolean) => string; | ||
export declare const limitDecimals: (x: ExactNumberType, decimals: number) => ExactNumberType | FixedNumber; | ||
export declare const _0N: bigint; | ||
export declare const _1N: bigint; | ||
export declare const _2N: bigint; | ||
export declare const _3N: bigint; | ||
export declare const _4N: bigint; | ||
export declare const _5N: bigint; | ||
export declare const _10N: bigint; | ||
export declare const _24N: bigint; |
{ | ||
"name": "exactnumber", | ||
"description": "Arbitrary-precision decimals. Enables making precise math calculations with rational numbers, without precision loss.", | ||
"version": "0.11.0", | ||
"description": "Arbitrary-precision decimals. Enables making math calculations with rational numbers, without precision loss.", | ||
"version": "1.0.0", | ||
"main": "dist/index.umd.js", | ||
@@ -47,2 +47,3 @@ "module": "dist/index.esm.js", | ||
}, | ||
"sideEffects": false, | ||
"license": "MIT", | ||
@@ -55,7 +56,6 @@ "devDependencies": { | ||
"@types/estree": "^1.0.0", | ||
"@types/jest": "^29.2.0", | ||
"@types/node": "^18.11.3", | ||
"@typescript-eslint/eslint-plugin": "^5.40.1", | ||
"@typescript-eslint/parser": "^5.40.1", | ||
"decimal.js": "^10.4.2", | ||
"@types/jest": "^29.2.2", | ||
"@types/node": "^18.11.9", | ||
"@typescript-eslint/eslint-plugin": "^5.42.0", | ||
"@typescript-eslint/parser": "^5.42.0", | ||
"eslint": "^8.26.0", | ||
@@ -65,13 +65,13 @@ "eslint-config-airbnb": "^19.0.4", | ||
"eslint-config-prettier": "^8.5.0", | ||
"jest": "29.2.1", | ||
"jest": "^29.2.2", | ||
"prettier": "^2.7.1", | ||
"rollup": "^2.79.1", | ||
"rollup": "^3.2.5", | ||
"rollup-plugin-copy": "^3.4.0", | ||
"rollup-plugin-license": "^2.8.2", | ||
"rollup-plugin-terser": "^7.0.2", | ||
"rollup-plugin-license": "^3.0.1", | ||
"@rollup/plugin-terser": "^0.1.0", | ||
"ts-jest": "^29.0.3", | ||
"ts-node": "^10.9.1", | ||
"typescript": "^4.8.4", | ||
"typedoc": "^0.23.17" | ||
"typedoc": "^0.23.20" | ||
} | ||
} |
126
README.md
@@ -10,48 +10,40 @@ # ExactNumber | ||
## Quick comparision with JS floating-point arithmetic | ||
```js | ||
console.log(1 + 0.36); | ||
// returns 1.3599999999999999 | ||
console.log(ExactNumber(1).add('0.36').toString()); | ||
// returns 1.36 | ||
console.log(1 / 3); | ||
// returns 0.3333333333333333 | ||
console.log(ExactNumber(1).div(3).toString()); | ||
// returns 0.(3) | ||
console.log((1 / 49) * 49); | ||
// returns 0.9999999999999999 | ||
console.log(ExactNumber(1).div(49).mul(49).toString()); | ||
// returns 1 | ||
console.log(10e16 + 5); | ||
// returns 100000000000000000 | ||
console.log(ExactNumber('10e16').add(5).toString()); | ||
// returns 100000000000000005 | ||
``` | ||
## Features | ||
- Works with arbitrary large numbers without precision loss | ||
- There is **no automatic rounding** or truncation. Rounding can be archived by **explicit calls** to rounding functions | ||
- All fractions can be represented as repeating decimals like `1.23(45)` | ||
- This repeating decimal format (`1.23(45)`) can also be parsed back | ||
- Works with all number bases between `2` and `16` | ||
- There are no special values like `NaN`, `Infinity` or `-0`. | ||
- No silent errors: it throws errors immediatelly when a confusing parameter is received. | ||
- All fractions can be represented as repeating decimals like `1.23(45)` | ||
- Repeating decimal format can also be parsed back | ||
- **No special values** like `NaN`, `Infinity` or `-0`. | ||
- **No silent errors**: it throws errors immediatelly when a confusing parameter is received (e.g. 0/0) | ||
- Supports bitwise operators (`and`, `or`, `xor`, `shiftLeft`, `shiftRight`) | ||
- Approximation algorithms for irrational numbers (_experimental_) | ||
- Includes approximation algorithms for irrational numbers like `PI`, `sin(1)`. | ||
- Supports all modern browsers, web workers, Node.js and Deno | ||
- Includes TypeScript type definitions: [documentation](https://daninet.github.io/exactnumber) | ||
- Zero external dependencies | ||
- Uses `BigInt` type under the hood. It automatically switches back and forth between fixed-precision and fractional representations. | ||
- Under the hood, it relies on the `BigInt` type. It automatically switches back and forth between fixed-precision and fractional representations. | ||
- Tries to deliver the best possible performance | ||
- 100% open source + MIT license | ||
## Comparision with built-in numbers | ||
```js | ||
import { ExactNumber as N } from 'exactnumber'; | ||
1 + 0.36 // 1.3599999999999999 | ||
N(1).add('0.36').toString() // 1.36 | ||
(1 / 49) * 49 // 0.9999999999999999 | ||
N(1).div(49).mul(49).toString() // 1 | ||
10e16 + 5 // 100000000000000000 | ||
N('10e16').add(5).toString() // 100000000000000005 | ||
1 / 3 // 0.3333333333333333 | ||
N(1).div(3).toString() // 0.(3) | ||
2**32 >> 32 // 0 | ||
N(2).pow(32).shiftRight(32).toString() // 1 | ||
``` | ||
## Installation | ||
@@ -83,2 +75,3 @@ | ||
N('1/7').toString(); // 0.(142857) | ||
N('1/7').toString(6); // 0.(05) | ||
N('1/7').toFixed(3); // 0.142 | ||
@@ -93,11 +86,64 @@ N('1/7').trunc(3).toString(); // 0.142 | ||
import { PI, sin } from 'exactnumber'; | ||
PI(10); // 3.1415926535 | ||
// approximations | ||
const PI_OVER_2 = N(PI(10)).div(2); | ||
sin(PI_OVER_2, 5); // 1.00000 | ||
import { PI, sin, pow } from 'exactnumber'; | ||
PI(10).toString(); // 3.1415926535 | ||
const PI_OVER_2 = PI(10).div(2); | ||
sin(PI_OVER_2, 5).toString(); // 1.00000 | ||
// 0.1232323 raised to the power of 2.193333, approximated with 10 decimals | ||
pow('0.1(23)', '2.19(3)', 10).toString(); // 0.0101310867 | ||
``` | ||
## Supported approximations | ||
## Functions | ||
- Addition / subtraction: `add()`, `sub()` | ||
- Multiplication / division: `mul()`, `div()`, `divToInt()` | ||
- Exponentiation: `pow()` | ||
- Modular arithmetic: `mod()`, `powm()` | ||
- Getting the sign / absolute value: `sign()`, `abs()` | ||
- Negation / inversion: `neg()`, `inv()` | ||
- Integer and fractional parts: `intPart()`, `fracPart()` | ||
- Comparisons: `cmp()`, `eq()`, `lt()`, `lte()`, `gt()`, `gte()` | ||
- Special comparisons: `isZero()`, `isOne()` | ||
- Type testing: `isInteger()` | ||
- Rounding: `round()`, `roundToDigits()`, `floor()`, `ceil()`, `trunc()` | ||
- Bitwise operators: `bitwiseAnd()`, `bitwiseOr()`, `bitwiseXor()`, `shiftLeft()`, `shiftRight()` | ||
- Clamping: `clamp()` | ||
- Fraction helper: `getFractionParts()` | ||
- Normalization / simplifying fractions: `normalize()` | ||
- String output: `toFixed()`, `toExponential()`, `toPrecision()`, `toString()`, `toFraction()` | ||
- Number output: `toNumber()` | ||
- GCD, LCM: `ExactNumber.gcd()`, `ExactNumber.lcm()` | ||
- Minimum, maximum: `ExactNumber.min()`, `ExactNumber.max()` | ||
- Parsing numbers in different bases: `ExactNumber.fromBase()` | ||
- Range generator: `ExactNumber.range()` | ||
## Rounding modes | ||
- `NEAREST_TO_POSITIVE` - Rounds to nearest number, with ties rounded towards +Infinity. Similar to Math.round(). | ||
- `NEAREST_TO_NEGATIVE` - Rounds to nearest number, with ties rounded towards -Infinity. | ||
- `NEAREST_TO_EVEN` - Rounds to nearest number, with ties rounded towards the nearest even number. | ||
- `NEAREST_TO_ZERO` - Rounds to nearest number, with ties rounded towards zero. | ||
- `NEAREST_AWAY_FROM_ZERO` - Rounds to nearest number, with ties rounded away from zero. | ||
- `TO_POSITIVE` - Rounds towards +Infinity. Similar to Math.ceil(). | ||
- `TO_NEGATIVE` - Rounds towards -Infinity. Similar to Math.floor(). | ||
- `TO_ZERO` - Rounds towards zero. Similar to Math.trunc(). | ||
- `AWAY_FROM_ZERO` - Rounds away from zero | ||
## Modulo variants | ||
- `TRUNCATED` | ||
- `FLOORED` | ||
- `EUCLIDEAN` | ||
Read more about them [here](https://en.wikipedia.org/wiki/Modulo_operation). | ||
## Approximation algorithms | ||
These functions approximate irrational numbers with arbitrary number of decimals. | ||
The last parameter is always used to specify the number of correct decimals in the result. | ||
- Roots: `sqrt()`, `cbrt()`, `nthroot()` | ||
@@ -104,0 +150,0 @@ - Exponentials: `pow()`, `exp()` |
@@ -1,2 +0,2 @@ | ||
import { limitDecimals } from '../util'; | ||
import { limitDecimals, _0N, _1N, _2N, _4N } from '../util'; | ||
import { ExactNumber } from '../ExactNumber'; | ||
@@ -8,8 +8,8 @@ import { ExactNumberType } from '../types'; | ||
function* expGenerator(x: ExactNumberType, decimals: number) { | ||
let sum = x.add(1n); | ||
let sum = x.add(1); | ||
let denominator = 6n; | ||
let i = 4n; | ||
let denominator = BigInt(6); | ||
let i = _4N; | ||
const xPow2 = x.pow(2n); | ||
const xPow2 = x.pow(_2N); | ||
@@ -22,5 +22,5 @@ let xPow = xPow2; | ||
const term = xPow.mul(x.add(i - 1n)).div(denominator); | ||
denominator *= i * (i + 1n); | ||
i += 2n; | ||
const term = xPow.mul(x.add(i - _1N)).div(denominator); | ||
denominator *= i * (i + _1N); | ||
i += _2N; | ||
xPow = xPow.mul(xPow2); | ||
@@ -46,3 +46,3 @@ sum = sum.add(term).trunc(decimals + 5); | ||
return ExactNumber(0); | ||
return ExactNumber(_0N); | ||
}; | ||
@@ -49,0 +49,0 @@ |
@@ -5,3 +5,3 @@ import { FixedNumber } from '../FixedNumber'; | ||
import { sqrt } from './roots'; | ||
import { limitDecimals } from '../util'; | ||
import { limitDecimals, _0N, _1N, _2N, _3N } from '../util'; | ||
@@ -11,10 +11,10 @@ // sinh x = x + x^3/3! + x^5/5! + ... | ||
let numerator = x; | ||
let denominator = 1n; | ||
const x2 = x.pow(2n).normalize(); | ||
let denominator = _1N; | ||
const x2 = x.pow(_2N).normalize(); | ||
let sum = x.trunc(decimals + 5); | ||
let i = 2n; | ||
let i = _2N; | ||
while (true) { | ||
numerator = numerator.mul(x2); | ||
denominator *= i * (i + 1n); | ||
i += 2n; | ||
denominator *= i * (i + _1N); | ||
i += _2N; | ||
const term = numerator.div(denominator); | ||
@@ -38,3 +38,3 @@ sum = sum.add(term).trunc(decimals + 5); | ||
return ExactNumber(0); | ||
return ExactNumber(_0N); | ||
}; | ||
@@ -44,15 +44,15 @@ | ||
function* coshGenerator(x: ExactNumberType, decimals: number) { | ||
const x2 = x.pow(2n).normalize(); | ||
const x2 = x.pow(_2N).normalize(); | ||
let numerator = x2; | ||
let denominator = 2n; | ||
let denominator = _2N; | ||
let sum = numerator | ||
.div(denominator) | ||
.add(1n) | ||
.add(_1N) | ||
.trunc(decimals + 5); | ||
let i = 3n; | ||
let i = _3N; | ||
while (true) { | ||
numerator = numerator.mul(x2); | ||
denominator *= i * (i + 1n); | ||
i += 2n; | ||
denominator *= i * (i + _1N); | ||
i += _2N; | ||
const term = numerator.div(denominator); | ||
@@ -76,3 +76,3 @@ sum = sum.add(term).trunc(decimals + 5); | ||
return ExactNumber(0); | ||
return ExactNumber(_0N); | ||
}; | ||
@@ -82,3 +82,3 @@ | ||
const angleNum = limitDecimals(ExactNumber(angle), decimals); | ||
if (angleNum.isZero()) return ExactNumber(0); | ||
if (angleNum.isZero()) return ExactNumber(_0N); | ||
@@ -89,3 +89,3 @@ // tanh x = sinh x / cosh x; | ||
const coshRes = cosh(angleNum, decimals + 10).abs(); | ||
const sinhRes = sqrt(coshRes.pow(2).sub(1), decimals + 10); | ||
const sinhRes = sqrt(coshRes.pow(_2N).sub(_1N), decimals + 10); | ||
@@ -92,0 +92,0 @@ const res = sinhRes.div(coshRes).mul(angleNum.sign()); |
@@ -1,2 +0,2 @@ | ||
import { limitDecimals } from '../util'; | ||
import { limitDecimals, _0N, _1N, _2N } from '../util'; | ||
import { ExactNumber } from '../ExactNumber'; | ||
@@ -9,7 +9,7 @@ import { ExactNumberType } from '../types'; | ||
const input = limitDecimals(ExactNumber(x), decimals); | ||
if (input.isZero()) return ExactNumber(0); | ||
if (input.isZero()) return ExactNumber(_0N); | ||
// asinh(x) = ln(x + sqrt(x^2 + 1)) | ||
const root = sqrt(input.pow(2).add(1n), decimals + 5); | ||
const root = sqrt(input.pow(_2N).add(_1N), decimals + 5); | ||
const res = log(input.add(root), decimals + 5); | ||
@@ -22,8 +22,8 @@ | ||
const input = limitDecimals(ExactNumber(x), decimals); | ||
if (input.isOne()) return ExactNumber(0); | ||
if (input.lt(1n)) throw new Error('Out of range'); | ||
if (input.isOne()) return ExactNumber(_0N); | ||
if (input.lt(_1N)) throw new Error('Out of range'); | ||
// acosh(x) = ln(x + sqrt(x^2 - 1)) | ||
const root = sqrt(input.pow(2).sub(1n), decimals + 5); | ||
const root = sqrt(input.pow(_2N).sub(_1N), decimals + 5); | ||
const res = log(input.add(root), decimals + 5); | ||
@@ -36,10 +36,10 @@ | ||
const input = limitDecimals(ExactNumber(x), decimals); | ||
if (input.abs().gte(1n)) throw new Error('Out of range'); | ||
if (input.isZero()) return ExactNumber(0); | ||
if (input.abs().gte(_1N)) throw new Error('Out of range'); | ||
if (input.isZero()) return ExactNumber(_0N); | ||
// atanh(x) = 0.5 * ln((1 + x) / (1 - x)) | ||
const res = log(input.add(1n).div(input.neg().add(1n)), decimals + 5); | ||
const res = log(input.add(_1N).div(input.neg().add(_1N)), decimals + 5); | ||
return ExactNumber(res).div(2n).trunc(decimals); | ||
return ExactNumber(res).div(_2N).trunc(decimals); | ||
}; |
@@ -1,2 +0,2 @@ | ||
import { limitDecimals } from '../util'; | ||
import { limitDecimals, _0N, _1N, _2N, _3N } from '../util'; | ||
import { ExactNumber } from '../ExactNumber'; | ||
@@ -9,5 +9,5 @@ import { ExactNumberType } from '../types'; | ||
function* atanGenerator(x: ExactNumberType, decimals: number) { | ||
const x2 = x.pow(2n).normalize(); | ||
const x4 = x2.pow(2n).normalize(); | ||
let denominator = 3n; | ||
const x2 = x.pow(_2N).normalize(); | ||
const x4 = x2.pow(_2N).normalize(); | ||
let denominator = _3N; | ||
@@ -21,4 +21,4 @@ let sum = x.sub(x.mul(x2).div(denominator)); | ||
// = x^5 * (-ax^2 + (a + 2)) / (a * (a + 2)) | ||
denominator += 2n; | ||
const denominator2 = denominator + 2n; | ||
denominator += _2N; | ||
const denominator2 = denominator + _2N; | ||
const numerator = xPow.mul(x2.mul(-denominator).add(denominator2)); | ||
@@ -50,4 +50,4 @@ const term = numerator.div(denominator * denominator2); | ||
while (x.abs().gt(reductionLimit)) { | ||
const root = ExactNumber(sqrt(x.pow(2n).add(1n), decimals + 10)); | ||
x = x.div(root.add(1n)); | ||
const root = ExactNumber(sqrt(x.pow(_2N).add(_1N), decimals + 10)); | ||
x = x.div(root.add(_1N)); | ||
reductionSteps++; | ||
@@ -62,3 +62,3 @@ } | ||
// undo argument reduction | ||
const res = sum.mul(2n ** BigInt(reductionSteps)); | ||
const res = sum.mul(_2N ** BigInt(reductionSteps)); | ||
return res.trunc(decimals); | ||
@@ -74,10 +74,10 @@ } | ||
if (x.isZero()) return ExactNumber(0); | ||
if (x.isZero()) return ExactNumber(_0N); | ||
if (x.abs().isOne()) { | ||
return ExactNumber(PI(decimals)).mul(x.sign()).div(2n).trunc(decimals); | ||
return ExactNumber(PI(decimals)).mul(x.sign()).div(_2N).trunc(decimals); | ||
} | ||
if (x.abs().eq('1/2')) { | ||
return ExactNumber(PI(decimals)).mul(x.sign()).div(6n).trunc(decimals); | ||
return ExactNumber(PI(decimals)).mul(x.sign()).div(6).trunc(decimals); | ||
} | ||
if (x.gt(1n) || x.lt(-1n)) { | ||
if (x.gt(_1N) || x.lt(-_1N)) { | ||
throw new Error('Out of range'); | ||
@@ -88,5 +88,5 @@ } | ||
const root = ExactNumber(sqrt(x.pow(2n).neg().add(1), decimals + 10)); | ||
const atangent = ExactNumber(atan(x.div(root.add(1n)), decimals + 10)); | ||
return atangent.mul(2).trunc(decimals); | ||
const root = ExactNumber(sqrt(x.pow(_2N).neg().add(_1N), decimals + 10)); | ||
const atangent = ExactNumber(atan(x.div(root.add(_1N)), decimals + 10)); | ||
return atangent.mul(_2N).trunc(decimals); | ||
}; | ||
@@ -97,6 +97,6 @@ | ||
if (x.isZero()) return ExactNumber(PI(decimals)).div(2n).trunc(decimals); | ||
if (x.isZero()) return ExactNumber(PI(decimals)).div(_2N).trunc(decimals); | ||
if (x.isOne()) { | ||
return ExactNumber(0); | ||
return ExactNumber(_0N); | ||
} | ||
@@ -109,7 +109,7 @@ | ||
if (x.abs().eq('1/2')) { | ||
const PI_OVER_3 = ExactNumber(PI(decimals)).div(3n); | ||
return x.sign() === -1 ? PI_OVER_3.mul(2n).trunc(decimals) : PI_OVER_3.trunc(decimals); | ||
const PI_OVER_3 = ExactNumber(PI(decimals)).div(_3N); | ||
return x.sign() === -1 ? PI_OVER_3.mul(_2N).trunc(decimals) : PI_OVER_3.trunc(decimals); | ||
} | ||
if (x.gt(1n) || x.lt(-1n)) { | ||
if (x.gt(_1N) || x.lt(-_1N)) { | ||
throw new Error('Out of range'); | ||
@@ -120,5 +120,5 @@ } | ||
return ExactNumber(PI(decimals + 10)) | ||
.div(2n) | ||
.div(_2N) | ||
.sub(asin(x, decimals + 10)) | ||
.trunc(decimals); | ||
}; |
@@ -1,2 +0,2 @@ | ||
import { limitDecimals } from '../util'; | ||
import { limitDecimals, _0N, _10N, _1N, _2N } from '../util'; | ||
import { ExactNumber } from '../ExactNumber'; | ||
@@ -11,6 +11,6 @@ import { FixedNumber } from '../FixedNumber'; | ||
function* logGenerator(y: ExactNumberType, decimals: number) { | ||
const y2 = y.pow(2n).normalize(); | ||
const y2 = y.pow(_2N).normalize(); | ||
let numerator = y; | ||
let denominator = 1n; | ||
let denominator = _1N; | ||
@@ -21,3 +21,3 @@ let sum = ExactNumber(y); | ||
numerator = numerator.mul(y2); | ||
denominator += 2n; | ||
denominator += _2N; | ||
const term = numerator.div(denominator).trunc(decimals + 10); | ||
@@ -35,3 +35,3 @@ sum = sum.add(term); | ||
if (input.lte(0n)) { | ||
if (input.lte(0)) { | ||
throw new Error('Invalid parameter'); | ||
@@ -44,3 +44,3 @@ } | ||
const reductionLimit = ExactNumber('0.1'); | ||
while (input.sub(1n).abs().gt(reductionLimit)) { | ||
while (input.sub(_1N).abs().gt(reductionLimit)) { | ||
input = new FixedNumber(sqrt(input, decimals + 10)); | ||
@@ -52,3 +52,3 @@ reductions++; | ||
// y = (x - 1)/(x + 1) (|y| < 1) | ||
const y = input.sub(1n).div(input.add(1n)); | ||
const y = input.sub(_1N).div(input.add(_1N)); | ||
@@ -59,3 +59,3 @@ const gen = logGenerator(y, decimals); | ||
// undo reductions | ||
const res = sum.mul(2n ** BigInt(reductions + 1)); | ||
const res = sum.mul(_2N ** BigInt(reductions + 1)); | ||
return res.trunc(decimals); | ||
@@ -65,3 +65,3 @@ } | ||
return ExactNumber(0); | ||
return ExactNumber(_0N); | ||
}; | ||
@@ -80,3 +80,3 @@ | ||
const LOG_2 = new ConstantCache(decimals => log(2n, decimals), 200); | ||
const LOG_2 = new ConstantCache(decimals => log(_2N, decimals), 200); | ||
@@ -89,3 +89,3 @@ export const log2 = (x: number | bigint | string | ExactNumberType, decimals: number): ExactNumberType => { | ||
const LOG_10 = new ConstantCache(decimals => log(10n, decimals), 200); | ||
const LOG_10 = new ConstantCache(decimals => log(_10N, decimals), 200); | ||
@@ -92,0 +92,0 @@ export const log10 = (x: number | bigint | string | ExactNumberType, decimals: number): ExactNumberType => { |
@@ -5,3 +5,3 @@ import { FixedNumber } from '../FixedNumber'; | ||
import { ExactNumber } from '../ExactNumber'; | ||
import { limitDecimals } from '../util'; | ||
import { limitDecimals, _0N, _1N } from '../util'; | ||
@@ -73,4 +73,4 @@ const approximateNthRoot = (n: number, x: ExactNumberType): string => { | ||
if (n % 2 === 0 && xNum.sign() === -1) throw new Error('Complex numbers are not supported'); | ||
if (xNum.isZero()) return new FixedNumber(0n).trunc(decimals); | ||
if (xNum.isOne()) return new FixedNumber(1n).trunc(decimals); | ||
if (xNum.isZero()) return new FixedNumber(_0N).trunc(decimals); | ||
if (xNum.isOne()) return new FixedNumber(_1N).trunc(decimals); | ||
@@ -77,0 +77,0 @@ const res = nthrootWithNewton(n, xNum, decimals); |
@@ -0,3 +1,4 @@ | ||
import { ExactNumberType } from '../types'; | ||
import { ExactNumber } from '../ExactNumber'; | ||
import { cos, PI, sin, tan } from './trigonometry'; | ||
import { cos, evaluateAngle, PI, sin, tan } from './trigonometry'; | ||
import { compareError, testStability } from '../testHelper.test'; | ||
@@ -24,4 +25,54 @@ | ||
it('evaluates angles', () => { | ||
const precision = 10; | ||
const pi = PI(15); | ||
const toRad = (x: ExactNumberType) => ExactNumber(x).div(180).mul(pi).trunc(precision); | ||
const normalizeAngle = (x: ExactNumberType) => { | ||
let ref = ExactNumber(x).mod(360); | ||
if (ref.sign() === -1) ref = ref.add(360); | ||
return ref; | ||
}; | ||
for (let deg = -3600; deg <= 3600; deg++) { | ||
const rad = toRad(ExactNumber(deg)); | ||
const ref = normalizeAngle(ExactNumber(deg)); | ||
const quadrant = ref.div(90).floor().toNumber() + 1; | ||
const res = evaluateAngle(rad, precision); | ||
expect(res.quadrant).toBe(quadrant); | ||
if (deg % 15 === 0) { | ||
expect(res.specialCaseDeg).not.toBe(null); | ||
expect(res.specialCaseDeg).toBeGreaterThanOrEqual(0); | ||
expect(res.specialCaseDeg).toBeLessThanOrEqual(90); | ||
expect(res.subHalfPiAngle).toBe(null); | ||
} else { | ||
expect(res.specialCaseDeg).toBe(null); | ||
expect(res.subHalfPiAngle.gte(0)).toBe(true); | ||
expect(res.subHalfPiAngle.lte('1.571')).toBe(true); | ||
} | ||
} | ||
}); | ||
it('reduces angles correctly', () => { | ||
const precision = 10; | ||
const pi = PI(100); | ||
const piOver2 = pi.div(2); | ||
const seq = [ExactNumber(0), pi.div(6), pi.div(4), pi.div(3)]; | ||
for (let base = ExactNumber(0); base.lt(200); base = base.add(pi.mul(2))) { | ||
for (let quadrant = 1; quadrant <= 4; quadrant++) { | ||
const basePlusQuadrant = base.add(piOver2.mul(quadrant - 1)); | ||
for (const angle of seq) { | ||
const x = basePlusQuadrant.add(angle).trunc(precision); | ||
const res = evaluateAngle(x, precision); | ||
expect(res.quadrant).toBe(quadrant); | ||
} | ||
} | ||
} | ||
}); | ||
it('cos reduce to half pi', () => { | ||
const pi = ExactNumber(PI(100)); | ||
const pi = PI(100); | ||
const piOverTwo = pi.div(2); | ||
@@ -53,2 +104,4 @@ | ||
it('tan', () => { | ||
// expect(tan(PI(12).div(2), 10).toFixed(10)).toBe('3.1415926535'); | ||
const range = [Math.floor(Math.PI * -4), Math.ceil(Math.PI * 4)]; | ||
@@ -55,0 +108,0 @@ for (let i = range[0]; i <= range[1]; i += 0.01) { |
@@ -6,3 +6,3 @@ import { FixedNumber } from '../FixedNumber'; | ||
import { sqrt } from './roots'; | ||
import { limitDecimals } from '../util'; | ||
import { limitDecimals, _0N, _1N, _2N, _3N, _4N, _10N, _24N } from '../util'; | ||
@@ -14,11 +14,12 @@ // TODO: https://en.wikipedia.org/wiki/Niven%27s_theorem | ||
const PIcalc = (decimals: number): ExactNumberType => { | ||
if (decimals === 0) return ExactNumber(3n); | ||
if (decimals === 0) return ExactNumber(_3N); | ||
// PI = 3 + 3(1/2)(1/3)(1/4) + 3((1/2)(3/4))(1/5)(1/4^2) + 3((1/2)(3/4)(5/6))(1/7)(1/4^3) + ... | ||
let i = 1n; | ||
let x = 3n * 10n ** BigInt(decimals + 20); | ||
let i = _1N; | ||
let x = _3N * _10N ** BigInt(decimals + 20); | ||
let res = x; | ||
while (x !== 0n) { | ||
x = (x * i) / ((i + 1n) * 4n); | ||
i += 2n; | ||
while (x !== _0N) { | ||
x = (x * i) / ((i + _1N) * _4N); | ||
i += _2N; | ||
res += x / i; | ||
@@ -33,37 +34,77 @@ } | ||
export const PI = (decimals: number): ExactNumberType => { | ||
if (decimals === 0) return ExactNumber(3); | ||
if (decimals === 0) return ExactNumber(_3N); | ||
return PI_CACHE.get(decimals).trunc(decimals); | ||
}; | ||
const evaluateAngle = (x: ExactNumberType, decimals: number) => { | ||
const pi = new FixedNumber(PI(decimals + 5)); | ||
const twoPi = pi.mul(2n); | ||
const roundedX = x.round(decimals + 5, RoundingMode.NEAREST_AWAY_FROM_ZERO); | ||
// a number between (-1, 1) | ||
let turns = roundedX.div(twoPi).fracPart(); | ||
const getMultiplierOf = (x: ExactNumberType, y: ExactNumberType, decimals: number) => { | ||
const precision = Math.max(3, decimals); | ||
const input = x.trunc(precision); | ||
const closestQuotient = input.div(y).round(); | ||
const ref = y.mul(closestQuotient).trunc(precision); | ||
// normalize into the [0, 1) interval | ||
if (turns.lt(0n)) { | ||
turns = turns.add(1n); | ||
if (ref.eq(input)) { | ||
return closestQuotient; | ||
} | ||
// limit precision | ||
turns = turns.round(decimals + 5); | ||
return null; | ||
}; | ||
const quadrant = turns.div('0.25').floor().toNumber() + 1; | ||
type EvaluationRes = { specialCaseDeg: number | null; quadrant: number; subHalfPiAngle: ExactNumberType | null }; | ||
let subHalfPiAngle = twoPi.mul(turns); | ||
let quadrantDegrees = turns.mul(360n); | ||
const evaluateSpecialAngle = (angleMultiplier: ExactNumberType): EvaluationRes => { | ||
let multiplier = angleMultiplier.mod(_24N).toNumber(); | ||
if (multiplier < 0) { | ||
multiplier += 24; | ||
} | ||
const quadrant = Math.floor(multiplier / 6) + 1; | ||
let specialCaseDeg = multiplier * 15; | ||
if (quadrant === 4) { | ||
specialCaseDeg = 360 - specialCaseDeg; | ||
} else if (quadrant === 3) { | ||
specialCaseDeg -= 180; | ||
} else if (quadrant === 2) { | ||
specialCaseDeg = 180 - specialCaseDeg; | ||
} | ||
return { | ||
specialCaseDeg, | ||
quadrant, | ||
subHalfPiAngle: null, | ||
}; | ||
}; | ||
export const evaluateAngle = (x: ExactNumberType, decimals: number): EvaluationRes => { | ||
let angle = x.round(decimals + 5, RoundingMode.NEAREST_AWAY_FROM_ZERO); | ||
const pi = PI(decimals + 5); | ||
const angleMultiplier = getMultiplierOf(angle, pi.div(12), decimals); | ||
if (angleMultiplier !== null) { | ||
return evaluateSpecialAngle(angleMultiplier); | ||
} | ||
const twoPi = pi.mul(_2N); | ||
angle = angle.mod(twoPi); | ||
if (angle.sign() === -1) { | ||
angle = angle.add(twoPi); | ||
} | ||
const quadrant = angle.mul(_2N).div(pi).floor().toNumber() + 1; | ||
let subHalfPiAngle = angle; | ||
if (quadrant === 4) { | ||
subHalfPiAngle = twoPi.sub(subHalfPiAngle); | ||
quadrantDegrees = ExactNumber(360).sub(quadrantDegrees); | ||
} else if (quadrant === 3) { | ||
subHalfPiAngle = subHalfPiAngle.sub(pi); | ||
quadrantDegrees = quadrantDegrees.sub(180); | ||
} else if (quadrant === 2) { | ||
subHalfPiAngle = pi.sub(subHalfPiAngle); | ||
quadrantDegrees = ExactNumber(180).sub(quadrantDegrees); | ||
} | ||
return { quadrantDegrees: quadrantDegrees.round(decimals), quadrant, subHalfPiAngle }; | ||
return { | ||
specialCaseDeg: null, | ||
quadrant, | ||
subHalfPiAngle, | ||
}; | ||
}; | ||
@@ -73,10 +114,9 @@ | ||
function* cosGenerator(x: ExactNumberType, decimals: number) { | ||
const x2 = x.round(decimals + 10, RoundingMode.NEAREST_AWAY_FROM_ZERO).pow(2n); | ||
const x2 = x.round(decimals + 10, RoundingMode.NEAREST_AWAY_FROM_ZERO).pow(_2N); | ||
let xPow = x2; | ||
let termDenominator = 2n; | ||
let sum = ExactNumber(1n).sub(xPow.div(termDenominator).trunc(decimals + 10)); | ||
let i = 3n; | ||
// let rndErrors = 1; | ||
let termDenominator = _2N; | ||
let sum = ExactNumber(_1N).sub(xPow.div(termDenominator).trunc(decimals + 10)); | ||
let i = _3N; | ||
@@ -86,6 +126,6 @@ while (true) { | ||
// = (5*6*x^4 - x^6)/6! | ||
termDenominator *= i * (i + 1n); | ||
i += 2n; | ||
const multiplier = i * (i + 1n); | ||
i += 2n; | ||
termDenominator *= i * (i + _1N); | ||
i += _2N; | ||
const multiplier = i * (i + _1N); | ||
i += _2N; | ||
xPow = xPow.mul(x2); | ||
@@ -98,7 +138,5 @@ termDenominator *= multiplier; | ||
const term = termNumerator.div(termDenominator).trunc(decimals + 10); | ||
// rndErrors++; | ||
sum = sum.add(term); | ||
// max lagrange error = x^(k+1)/(k+1)! | ||
// const le = xPow.mul(x).div(termDenominator * i); | ||
@@ -109,3 +147,7 @@ yield { term, sum }; | ||
const resultHandler = (value: string | ExactNumberType, shouldNegate: boolean, decimals: number): ExactNumberType => { | ||
const resultHandler = ( | ||
value: bigint | string | ExactNumberType, | ||
shouldNegate: boolean, | ||
decimals: number, | ||
): ExactNumberType => { | ||
let convertedValue = ExactNumber(value); | ||
@@ -122,15 +164,18 @@ if (shouldNegate) { | ||
const angle = limitDecimals(ExactNumber(_angle), decimals + 5); | ||
const { quadrantDegrees, subHalfPiAngle: x, quadrant } = evaluateAngle(angle, decimals); | ||
const { specialCaseDeg, subHalfPiAngle: x, quadrant } = evaluateAngle(angle, decimals); | ||
const shouldNegate = quadrant === 2 || quadrant === 3; | ||
if (quadrantDegrees.isZero()) return resultHandler('1', shouldNegate, decimals); | ||
if (quadrantDegrees.eq(30n)) { | ||
return resultHandler(ExactNumber(sqrt(3n, decimals + 5)).div(2n), shouldNegate, decimals); | ||
if (specialCaseDeg !== null) { | ||
if (specialCaseDeg === 0) return resultHandler(_1N, shouldNegate, decimals); | ||
if (specialCaseDeg === 30) { | ||
return resultHandler(ExactNumber(sqrt(_3N, decimals + 5)).div(_2N), shouldNegate, decimals); | ||
} | ||
if (specialCaseDeg === 45) { | ||
return resultHandler(ExactNumber(sqrt(_2N, decimals + 5)).div(_2N), shouldNegate, decimals); | ||
} | ||
if (specialCaseDeg === 60) return resultHandler('0.5', shouldNegate, decimals); | ||
if (specialCaseDeg === 90) return resultHandler(_0N, shouldNegate, decimals); | ||
throw new Error(); | ||
} | ||
if (quadrantDegrees.eq(45n)) { | ||
return resultHandler(ExactNumber(sqrt(2n, decimals + 5)).div(2n), shouldNegate, decimals); | ||
} | ||
if (quadrantDegrees.eq(60n)) return resultHandler('0.5', shouldNegate, decimals); | ||
if (quadrantDegrees.eq(90n)) return resultHandler('0', shouldNegate, decimals); | ||
@@ -152,3 +197,3 @@ const maxError = ExactNumber(`1e-${EXTRA_DECIMALS}`); | ||
const x = limitDecimals(ExactNumber(angle), decimals + 5); | ||
return cos(pi.div(2n).sub(x), decimals + 5).trunc(decimals); | ||
return cos(pi.div(_2N).sub(x), decimals + 5).trunc(decimals); | ||
}; | ||
@@ -159,24 +204,27 @@ | ||
const { quadrantDegrees, quadrant, subHalfPiAngle: x } = evaluateAngle(angleNum, decimals + 5); | ||
const { specialCaseDeg, quadrant, subHalfPiAngle: x } = evaluateAngle(angleNum, decimals); | ||
const shouldNegate = quadrant === 1 || quadrant === 3; | ||
if (quadrantDegrees.isZero()) return resultHandler('0', shouldNegate, decimals); | ||
if (quadrantDegrees.eq(30n)) { | ||
return resultHandler(ExactNumber(1n).div(sqrt(3n, decimals + 5)), shouldNegate, decimals); | ||
if (specialCaseDeg !== null) { | ||
if (specialCaseDeg === 0) return resultHandler('0', shouldNegate, decimals); | ||
if (specialCaseDeg === 30) { | ||
return resultHandler(ExactNumber(_1N).div(sqrt(_3N, decimals + 5)), shouldNegate, decimals); | ||
} | ||
if (specialCaseDeg === 4) { | ||
return resultHandler('1', shouldNegate, decimals); | ||
} | ||
if (specialCaseDeg === 60) return resultHandler(sqrt(_3N, decimals + 5), shouldNegate, decimals); | ||
if (specialCaseDeg === 90) { | ||
throw new Error('Out of range'); | ||
} | ||
throw new Error(); | ||
} | ||
if (quadrantDegrees.eq(45n)) { | ||
return resultHandler('1', shouldNegate, decimals); | ||
} | ||
if (quadrantDegrees.eq(60n)) return resultHandler(sqrt(3n, decimals + 5), shouldNegate, decimals); | ||
if (quadrantDegrees.eq(90n)) { | ||
throw new Error('Out of range'); | ||
} | ||
// tan x = sqrt((1 - cos(2x)) / 1 + cos(2x)) | ||
const cos2x = ExactNumber(cos(x.mul(2n), decimals + 5)); | ||
const cos2x = ExactNumber(cos(x.mul(_2N), decimals + 5)); | ||
const res = ExactNumber(1n) | ||
const res = ExactNumber(_1N) | ||
.sub(cos2x) | ||
.div(ExactNumber(1n).add(cos2x)) | ||
.div(ExactNumber(_1N).add(cos2x)) | ||
.round(decimals + 5); | ||
@@ -183,0 +231,0 @@ |
import { Fraction } from './Fraction'; | ||
import { FixedNumber } from './FixedNumber'; | ||
import { ExactNumberParameter, ExactNumberType } from './types'; | ||
import { _0N, _1N } from './util'; | ||
@@ -23,3 +24,3 @@ export function parseParameter(x: number | bigint | string | ExactNumberType): ExactNumberType { | ||
if (x.includes('/') || x.includes('(')) { | ||
return new Fraction(x, 1n); | ||
return new Fraction(x, _1N); | ||
} | ||
@@ -66,3 +67,3 @@ return new FixedNumber(x); | ||
const yVal = parseParameter(y); | ||
return new Fraction(xVal, 1n).div(new Fraction(yVal, 1n)); | ||
return new Fraction(xVal, _1N).div(new Fraction(yVal, _1N)); | ||
}); | ||
@@ -103,3 +104,3 @@ | ||
const parseDigitsInBase = (str: string, radix: number) => { | ||
let res = 0n; | ||
let res = _0N; | ||
for (let i = 0; i < str.length; i++) { | ||
@@ -150,4 +151,4 @@ const c = str.charAt(i); | ||
const numerator = | ||
parseDigitsInBase([wholePartStr, nonRepeatingPartStr, repeatingPartStr].join(''), radix) - | ||
parseDigitsInBase([wholePartStr, nonRepeatingPartStr].join(''), radix); | ||
parseDigitsInBase(`${wholePartStr}${nonRepeatingPartStr}${repeatingPartStr}`, radix) - | ||
parseDigitsInBase(`${wholePartStr}${nonRepeatingPartStr}`, radix); | ||
@@ -168,3 +169,3 @@ const denominator = parseDigitsInBase( | ||
const res = new Fraction(whole, 1n).add(fracPath).normalize(); | ||
const res = new Fraction(whole, _1N).add(fracPath).normalize(); | ||
return isNegative ? res.neg() : res; | ||
@@ -171,0 +172,0 @@ }); |
@@ -180,2 +180,18 @@ import { FixedNumber } from './FixedNumber'; | ||
it('powm()', () => { | ||
const run = (b: ExactNumberParameter, e: ExactNumberParameter, m: ExactNumberParameter) => | ||
new FixedNumber(b).powm(e, m).toString(); | ||
expect(run(3, 4, 5)).toBe('1'); | ||
expect(run(314, 23, 971)).toBe('865'); | ||
for (let b = 2; b <= 25; b++) { | ||
for (let e = 0; e <= 10; e++) { | ||
for (let m = 11; m <= 13; m++) { | ||
expect(run(b, e, m)).toBe((b ** e % m).toString()); | ||
} | ||
} | ||
} | ||
}); | ||
it('div()', () => { | ||
@@ -232,2 +248,5 @@ const run = (a: ExactNumberParameter, b: ExactNumberParameter) => new FixedNumber(a).div(b).toString(); | ||
expect(run('-3.745', '-1.25')).toBe('-1.245'); | ||
expect(run('17.891', '-1.66')).toBe('1.291'); | ||
expect(run('-712.8929', '-1.79')).toBe('-0.4729'); | ||
expect(run('-2.8', '-1.789')).toBe('-1.011'); | ||
@@ -697,3 +716,4 @@ const values = [ | ||
it('toFixed()', () => { | ||
const run = (x: string, digits: number, rndMode?: RoundingMode) => new FixedNumber(x).toFixed(digits, rndMode); | ||
const run = (x: string, digits: number, trimZeros?: boolean) => | ||
new FixedNumber(x).toFixed(digits, RoundingMode.TO_ZERO, trimZeros); | ||
@@ -708,5 +728,7 @@ expect(run('0', 0)).toBe('0'); | ||
expect(run('0.45600', 6)).toBe('0.456000'); | ||
expect(run('0.45600', 6, true)).toBe('0.456'); | ||
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('123000', 2, true)).toBe('123000'); | ||
@@ -730,3 +752,4 @@ expect(() => run('-1.45', -1)).toThrow('Invalid parameter'); | ||
it('toPrecision()', () => { | ||
const run = (x: string, digits: number) => new FixedNumber(x).toPrecision(digits); | ||
const run = (x: string, digits: number, trimZeros?: boolean) => | ||
new FixedNumber(x).toPrecision(digits, RoundingMode.TO_ZERO, trimZeros); | ||
@@ -744,2 +767,4 @@ expect(run('0', 1)).toBe('0'); | ||
expect(run('0.0045600', 6)).toBe('0.00456000'); | ||
expect(run('0.0045600', 6, true)).toBe('0.00456'); | ||
expect(run('123000', 2, true)).toBe('120000'); | ||
@@ -751,15 +776,21 @@ expect(() => run('-1.45', -1)).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('toPrecision() rounding modes', () => { | ||
for (const rndMode of Object.values(RoundingMode)) { | ||
if (!Number.isInteger(rndMode)) continue; | ||
for (let i = 1; i < 10; i++) { | ||
let num = new FixedNumber('123.45600'); | ||
expect(num.toPrecision(i, rndMode as RoundingMode)).toBe( | ||
num.roundToDigits(i, rndMode as RoundingMode).toPrecision(i), | ||
); | ||
num = num.neg(); | ||
expect(num.toPrecision(i, rndMode as RoundingMode)).toBe( | ||
num.roundToDigits(i, rndMode as RoundingMode).toPrecision(i), | ||
); | ||
} | ||
} | ||
}); | ||
it('toExponential()', () => { | ||
const run = (a: string, digits: number) => new FixedNumber(a).toExponential(digits); | ||
const run = (a: string, digits: number, trimZeros?: boolean) => | ||
new FixedNumber(a).toExponential(digits, RoundingMode.TO_ZERO, trimZeros); | ||
@@ -791,2 +822,7 @@ expect(run('0', 0)).toBe('0e+0'); | ||
expect(run('0.0045600', 6, true)).toBe('4.56e-3'); | ||
expect(run('123000', 2, true)).toBe('1.23e+5'); | ||
expect(run('123000', 10, false)).toBe('1.2300000000e+5'); | ||
expect(run('123000', 10, true)).toBe('1.23e+5'); | ||
expect(() => run('-1.45', -1)).toThrow('Invalid parameter'); | ||
@@ -807,3 +843,3 @@ expect(() => run('-1.45', 0.5)).toThrow('Invalid parameter'); | ||
expect(run('0.4', 3)).toBe('0.(1012)'); | ||
expect(run('0.3', 16)).toBe('0.4(c)'); | ||
expect(run('0.300', 16)).toBe('0.4(c)'); | ||
expect(run('0.013', 7)).toBe('0.(00431330261442015456)'); | ||
@@ -813,2 +849,5 @@ expect(run('0.012', 6)).toBe('0.0(0233151220401052455413443)'); | ||
expect(run('-15.012', 6)).toBe('-23.0(0233151220401052455413443)'); | ||
expect(run('-123.500', 6)).toBe('-323.3'); | ||
expect(run('1234.88', 16)).toBe('4d2.(e147a)'); | ||
expect(run('-1234.2000', 15)).toBe('-574.3'); | ||
@@ -815,0 +854,0 @@ expect(run('100', 5)).toBe('400'); |
@@ -1,2 +0,2 @@ | ||
import { bigIntToStr } from './util'; | ||
import { bigIntToStr, trimTrailingZerosFromFixed, _0N, _10N, _1N, _24N, _2N } from './util'; | ||
import { Fraction } from './Fraction'; | ||
@@ -80,4 +80,4 @@ import { ExactNumber, parseParameter } from './ExactNumber'; | ||
const maxPos = Math.max(this.decimalPos, decimalPos); | ||
const a = maxPos === this.decimalPos ? this.number : this.number * 10n ** BigInt(maxPos - this.decimalPos); | ||
const b = maxPos === decimalPos ? number : number * 10n ** BigInt(maxPos - decimalPos); | ||
const a = maxPos === this.decimalPos ? this.number : this.number * _10N ** BigInt(maxPos - this.decimalPos); | ||
const b = maxPos === decimalPos ? number : number * _10N ** BigInt(maxPos - decimalPos); | ||
return { a, b, decimalPos: maxPos }; | ||
@@ -127,2 +127,27 @@ } | ||
powm( | ||
_exp: number | bigint | string | ExactNumberType, | ||
_mod: number | bigint | string | ExactNumberType, | ||
modType?: ModType, | ||
): FixedNumber { | ||
let exp = parseParameter(_exp).toNumber(); | ||
if (!Number.isSafeInteger(exp)) { | ||
throw new Error('Unsupported parameter'); | ||
} | ||
const mod = parseParameter(_mod); | ||
let base = this as FixedNumber; | ||
let res = new FixedNumber(_1N); | ||
while (exp !== 0) { | ||
if (exp % 2 !== 0) { | ||
res = res.mul(base).mod(mod, modType) as FixedNumber; | ||
} | ||
base = base.pow(_2N).mod(mod, modType) as FixedNumber; | ||
exp = Math.floor(exp / 2); | ||
} | ||
return res; | ||
} | ||
div(x: number | bigint | string | ExactNumberType): ExactNumberType { | ||
@@ -162,7 +187,7 @@ const frac = this.convertToFraction(); | ||
if (type === ModType.FLOORED) { | ||
return Number(a < 0) ^ Number(b < 0) ? res.add(b) : res; | ||
return Number(a < _0N) ^ Number(b < _0N) ? res.add(b) : res; | ||
} | ||
if (type === ModType.EUCLIDEAN) { | ||
return mod < 0 ? res.add(b < 0 ? -b : b) : res; | ||
return mod < _0N ? res.add(b < _0N ? -b : b) : res; | ||
} | ||
@@ -174,3 +199,3 @@ | ||
abs(): FixedNumber { | ||
const res = new FixedNumber(this.number < 0 ? -this.number : this.number, this.decimalPos); | ||
const res = new FixedNumber(this.number < _0N ? -this.number : this.number, this.decimalPos); | ||
return res; | ||
@@ -180,3 +205,3 @@ } | ||
neg() { | ||
return this.mul(-1n) as FixedNumber; | ||
return this.mul(-_1N) as FixedNumber; | ||
} | ||
@@ -222,3 +247,3 @@ | ||
const exp = 10n ** BigInt(shift); | ||
const exp = _10N ** BigInt(shift); | ||
const outDigits = this.number / exp; | ||
@@ -231,3 +256,3 @@ | ||
const extraDigits = this.number % exp; | ||
if (extraDigits === 0n) { | ||
if (extraDigits === _0N) { | ||
return new FixedNumber(outDigits, decimals); | ||
@@ -237,3 +262,3 @@ } | ||
if (roundingMode === RoundingMode.AWAY_FROM_ZERO) { | ||
const res = this.number < 0n ? outDigits - 1n : outDigits + 1n; | ||
const res = this.number < _0N ? outDigits - _1N : outDigits + _1N; | ||
return new FixedNumber(res, decimals); | ||
@@ -243,3 +268,3 @@ } | ||
if (roundingMode === RoundingMode.TO_POSITIVE) { | ||
const res = this.number < 0n ? outDigits : outDigits + 1n; | ||
const res = this.number < _0N ? outDigits : outDigits + _1N; | ||
return new FixedNumber(res, decimals); | ||
@@ -249,3 +274,3 @@ } | ||
if (roundingMode === RoundingMode.TO_NEGATIVE) { | ||
const res = this.number >= 0n ? outDigits : outDigits - 1n; | ||
const res = this.number >= _0N ? outDigits : outDigits - _1N; | ||
return new FixedNumber(res, decimals); | ||
@@ -267,3 +292,3 @@ } | ||
let extraDigitsStr = (extraDigits < 0n ? -extraDigits : extraDigits).toString(); | ||
let extraDigitsStr = (extraDigits < _0N ? -extraDigits : extraDigits).toString(); | ||
// '00123' extra part will appear in extraDigitsStr as '123' | ||
@@ -281,3 +306,3 @@ // -> in this case we can exclude the tie case by setting the extra part to zero | ||
if (roundingMode === RoundingMode.NEAREST_AWAY_FROM_ZERO) { | ||
const res = this.number < 0n ? outDigits - 1n : outDigits + 1n; | ||
const res = this.number < _0N ? outDigits - _1N : outDigits + _1N; | ||
return new FixedNumber(res, decimals); | ||
@@ -287,3 +312,3 @@ } | ||
if (roundingMode === undefined || roundingMode === RoundingMode.NEAREST_TO_POSITIVE) { | ||
const res = this.number < 0n ? outDigits : outDigits + 1n; | ||
const res = this.number < _0N ? outDigits : outDigits + _1N; | ||
return new FixedNumber(res, decimals); | ||
@@ -293,3 +318,3 @@ } | ||
if (roundingMode === RoundingMode.NEAREST_TO_NEGATIVE) { | ||
const res = this.number >= 0n ? outDigits : outDigits - 1n; | ||
const res = this.number >= _0N ? outDigits : outDigits - _1N; | ||
return new FixedNumber(res, decimals); | ||
@@ -299,7 +324,7 @@ } | ||
if (roundingMode === RoundingMode.NEAREST_TO_EVEN) { | ||
if (outDigits % 2n === 0n) { | ||
if (outDigits % _2N === _0N) { | ||
return new FixedNumber(outDigits, decimals); | ||
} | ||
const res = outDigits < 0n ? outDigits - 1n : outDigits + 1n; | ||
const res = outDigits < _0N ? outDigits - _1N : outDigits + _1N; | ||
return new FixedNumber(res, decimals); | ||
@@ -313,3 +338,3 @@ } | ||
const res = this.number < 0 ? outDigits - 1n : outDigits + 1n; | ||
const res = this.number < _0N ? outDigits - _1N : outDigits + _1N; | ||
return new FixedNumber(res, decimals); | ||
@@ -340,3 +365,3 @@ } | ||
if (rem > 0) { | ||
newNumber *= 10n ** BigInt(rem); | ||
newNumber *= _10N ** BigInt(rem); | ||
} | ||
@@ -349,7 +374,7 @@ } | ||
private countDigits() { | ||
if (this.number === 0n) return 1; | ||
if (this.number === _0N) return 1; | ||
let digits = 0; | ||
let x = this.number < 0 ? -this.number : this.number; | ||
while (x > 0n) { | ||
x /= 10n; | ||
let x = this.number < _0N ? -this.number : this.number; | ||
while (x > _0N) { | ||
x /= _10N; | ||
digits++; | ||
@@ -389,3 +414,3 @@ } | ||
sign(): -1 | 1 { | ||
return this.number < 0n ? -1 : 1; | ||
return this.number < _0N ? -1 : 1; | ||
} | ||
@@ -404,9 +429,9 @@ | ||
const pow = 2n ** 24n; | ||
const pow = _2N ** _24N; | ||
let an = this.normalize().number; | ||
let bn = (x.trunc().normalize() as FixedNumber).number; | ||
let res = 0n; | ||
let shift = 1n; | ||
let res = _0N; | ||
let shift = _1N; | ||
while (an > 0 && bn > 0) { | ||
while (an > _0N && bn > _0N) { | ||
const modA = BigInt.asUintN(24, an); | ||
@@ -434,9 +459,9 @@ const modB = BigInt.asUintN(24, bn); | ||
const pow = 2n ** 24n; | ||
const pow = _2N ** _24N; | ||
let an = this.normalize().number; | ||
let bn = (x.trunc().normalize() as FixedNumber).number; | ||
let res = 0n; | ||
let shift = 1n; | ||
let res = _0N; | ||
let shift = _1N; | ||
while (an > 0 || bn > 0) { | ||
while (an > _0N || bn > _0N) { | ||
const modA = BigInt.asUintN(24, an); | ||
@@ -464,9 +489,9 @@ const modB = BigInt.asUintN(24, bn); | ||
const pow = 2n ** 24n; | ||
const pow = _2N ** _24N; | ||
let an = this.normalize().number; | ||
let bn = (x.trunc().normalize() as FixedNumber).number; | ||
let res = 0n; | ||
let shift = 1n; | ||
let res = _0N; | ||
let shift = _1N; | ||
while (an > 0 || bn > 0) { | ||
while (an > _0N || bn > _0N) { | ||
const modA = BigInt.asUintN(24, an); | ||
@@ -492,3 +517,3 @@ const modB = BigInt.asUintN(24, bn); | ||
const pow = 2n ** BigInt(bitCount); | ||
const pow = _2N ** BigInt(bitCount); | ||
return this.mul(pow); | ||
@@ -506,3 +531,3 @@ } | ||
const pow = 2n ** BigInt(bitCount); | ||
const pow = _2N ** BigInt(bitCount); | ||
return new FixedNumber(this.normalize().number / pow); | ||
@@ -557,3 +582,3 @@ } | ||
isZero() { | ||
return this.number === 0n; | ||
return this.number === _0N; | ||
} | ||
@@ -563,8 +588,8 @@ | ||
if (this.decimalPos === 0) { | ||
return this.number === 1n; | ||
return this.number === _1N; | ||
} | ||
const exp = 10n ** BigInt(this.decimalPos); | ||
const exp = _10N ** BigInt(this.decimalPos); | ||
const q = this.number / exp; | ||
return q === 1n && q * exp === this.number; | ||
return q === _1N && q * exp === this.number; | ||
} | ||
@@ -574,3 +599,3 @@ | ||
if (this.decimalPos === 0) return true; | ||
return this.number % 10n ** BigInt(this.decimalPos) === 0n; | ||
return this.number % _10N ** BigInt(this.decimalPos) === _0N; | ||
} | ||
@@ -590,5 +615,5 @@ | ||
let n = this.number; | ||
while (pos > 0 && n % 10n === 0n) { | ||
while (pos > 0 && n % _10N === _0N) { | ||
pos--; | ||
n /= 10n; | ||
n /= _10N; | ||
} | ||
@@ -600,5 +625,5 @@ return new FixedNumber(n, pos); | ||
if (this.decimalPos === 0) { | ||
return new Fraction(this.number, 1n); | ||
return new Fraction(this.number, _1N); | ||
} | ||
const denominator = 10n ** BigInt(this.decimalPos); | ||
const denominator = _10N ** BigInt(this.decimalPos); | ||
return new Fraction(this.number, denominator); | ||
@@ -611,3 +636,3 @@ } | ||
toFixed(decimals: number, roundingMode = RoundingMode.TO_ZERO): string { | ||
toFixed(decimals: number, roundingMode = RoundingMode.TO_ZERO, trimZeros = false): string { | ||
if (!Number.isSafeInteger(decimals) || decimals < 0) throw new Error('Invalid parameter'); | ||
@@ -617,6 +642,6 @@ | ||
return bigIntToStr(rounded.number, rounded.decimalPos, decimals, false); | ||
return bigIntToStr(rounded.number, rounded.decimalPos, decimals, trimZeros); | ||
} | ||
toExponential(digits: number, roundingMode = RoundingMode.TO_ZERO): string { | ||
toExponential(digits: number, roundingMode = RoundingMode.TO_ZERO, trimZeros = false): string { | ||
if (!Number.isSafeInteger(digits) || digits < 0) throw new Error('Invalid parameter'); | ||
@@ -633,5 +658,11 @@ | ||
const strWithPoint = | ||
slicedString.length > 1 ? `${slicedString.slice(0, 1)}.${slicedString.slice(1)}` : slicedString; | ||
let strWithPoint = slicedString; | ||
if (slicedString.length > 1) { | ||
strWithPoint = `${slicedString.slice(0, 1)}.${slicedString.slice(1)}`; | ||
if (trimZeros) { | ||
strWithPoint = trimTrailingZerosFromFixed(strWithPoint); | ||
} | ||
} | ||
const fractionalDigitsBefore = absNumber.decimalPos; | ||
@@ -689,3 +720,7 @@ const fractionalDigitsAfter = str.length - 1; | ||
return [isNegative ? '-' : '', intPart.number.toString(radix), digits.length ? '.' : '', ...digits].join(''); | ||
const digitsStr = digits.join(''); | ||
const res = `${isNegative ? '-' : ''}${intPart.number.toString(radix)}${digits.length ? '.' : ''}${digitsStr}`; | ||
return res; | ||
} | ||
@@ -706,6 +741,7 @@ | ||
toPrecision(digits: number, roundingMode = RoundingMode.TO_ZERO): string { | ||
toPrecision(digits: number, roundingMode = RoundingMode.TO_ZERO, trimZeros = false): string { | ||
if (!Number.isSafeInteger(digits) || digits < 1) throw new Error('Invalid parameter'); | ||
const rounded = this.roundToDigits(digits, roundingMode); | ||
const { subZeroNum, exponentDiff } = rounded.toSubZeroNum(); | ||
@@ -724,3 +760,2 @@ | ||
const suffixLength = Math.max(0, digits - whole.length - frac.length); | ||
const suffix = '0'.repeat(suffixLength); | ||
const prefix = '0'.repeat(exponentDiff < 0 ? -exponentDiff : 0); | ||
@@ -730,3 +765,7 @@ | ||
if (frac.length + prefix.length + suffixLength > 0) { | ||
const suffix = '0'.repeat(suffixLength); | ||
res += `.${prefix}${frac}${suffix}`; | ||
if (trimZeros) { | ||
res = trimTrailingZerosFromFixed(res); | ||
} | ||
} | ||
@@ -733,0 +772,0 @@ |
@@ -213,2 +213,18 @@ import { Fraction } from './Fraction'; | ||
it('powm()', () => { | ||
const run = (b: ExactNumberParameter, e: ExactNumberParameter, m: ExactNumberParameter) => | ||
new Fraction(b, 1n).powm(e, m).toString(); | ||
expect(run(3, 4, 5)).toBe('1'); | ||
expect(run(314, 23, 971)).toBe('865'); | ||
for (let b = 2; b <= 25; b++) { | ||
for (let e = 0; e <= 10; e++) { | ||
for (let m = 11; m <= 13; m++) { | ||
expect(run(b, e, m)).toBe((b ** e % m).toString()); | ||
} | ||
} | ||
} | ||
}); | ||
it('round()', () => { | ||
@@ -215,0 +231,0 @@ const run = (a: string, decimals?: number, rndMode?: RoundingMode) => |
import { CommonNumberFields, ExactNumberType, ModType, RoundingMode } from './types'; | ||
import { FixedNumber } from './FixedNumber'; | ||
import { trimTrailingZeros } from './util'; | ||
import { trimTrailingZerosFromFixed, _0N, _10N, _1N, _2N, _5N } from './util'; | ||
import { ExactNumber } from './ExactNumber'; | ||
@@ -35,3 +35,3 @@ | ||
const isNegativeExp = exponent.startsWith('-'); | ||
const exp = 10n ** BigInt(isNegativeExp ? exponent.slice(1) : exponent); | ||
const exp = _10N ** BigInt(isNegativeExp ? exponent.slice(1) : exponent); | ||
if (isNegativeExp) { | ||
@@ -59,7 +59,7 @@ return fraction.div(exp).normalize() as Fraction; | ||
} | ||
return new Fraction(BigInt(x), 1n); | ||
return new Fraction(BigInt(x), _1N); | ||
} | ||
if (typeof x === 'bigint') { | ||
return new Fraction(x, 1n); | ||
return new Fraction(x, _1N); | ||
} | ||
@@ -71,3 +71,3 @@ | ||
const numerator = this.parseRepeatingDecimal(parts[0]); | ||
const denominator = parts[1] ? this.parseRepeatingDecimal(parts[1]) : new Fraction(1n, 1n); | ||
const denominator = parts[1] ? this.parseRepeatingDecimal(parts[1]) : new Fraction(_1N, _1N); | ||
const res = numerator.div(denominator) as CommonNumberFields; | ||
@@ -95,3 +95,3 @@ const fraction = res.convertToFraction(); | ||
} | ||
if (this.denominator === 0n) { | ||
if (this.denominator === _0N) { | ||
throw new Error('Division by zero'); | ||
@@ -161,3 +161,3 @@ } | ||
if (type === ModType.EUCLIDEAN) { | ||
return res.sign() < 0 ? res.add(rFrac.sign() < 0 ? rFrac.neg() : rFrac) : res; | ||
return res.sign() === -1 ? res.add(rFrac.sign() === -1 ? rFrac.neg() : rFrac) : res; | ||
} | ||
@@ -175,8 +175,35 @@ | ||
const exp = param.numerator / param.denominator; | ||
const absExp = exp < 0 ? -exp : exp; | ||
const absExp = exp < _0N ? -exp : exp; | ||
const res = new Fraction(this.numerator ** absExp, this.denominator ** absExp); | ||
return exp < 0 ? res.inv() : res; | ||
return exp < _0N ? res.inv() : res; | ||
} | ||
powm( | ||
_exp: number | bigint | string | ExactNumberType, | ||
_mod: number | bigint | string | ExactNumberType, | ||
modType?: ModType, | ||
): ExactNumberType { | ||
const exp = this.parseParameter(_exp); | ||
if (!exp.isInteger()) { | ||
throw new Error('Unsupported parameter'); | ||
} | ||
let expInt = exp.toNumber(); | ||
const mod = this.parseParameter(_mod); | ||
let base = this as Fraction; | ||
let res = new Fraction(_1N, _1N); | ||
while (expInt !== 0) { | ||
if (expInt % 2 !== 0) { | ||
res = res.mul(base).mod(mod, modType) as Fraction; | ||
} | ||
base = base.pow(_2N).mod(mod, modType) as Fraction; | ||
expInt = Math.floor(expInt / 2); | ||
} | ||
return res; | ||
} | ||
inv(): ExactNumberType { | ||
@@ -188,3 +215,3 @@ const res = new Fraction(this.denominator, this.numerator); | ||
floor(decimals?: number) { | ||
if (this.denominator === 1n) return new FixedNumber(this.numerator); | ||
if (this.denominator === _1N) return new FixedNumber(this.numerator); | ||
@@ -195,3 +222,3 @@ return this.round(decimals, RoundingMode.TO_NEGATIVE); | ||
ceil(decimals?: number) { | ||
if (this.denominator === 1n) return new FixedNumber(this.numerator); | ||
if (this.denominator === _1N) return new FixedNumber(this.numerator); | ||
@@ -202,3 +229,3 @@ return this.round(decimals, RoundingMode.TO_POSITIVE); | ||
trunc(decimals?: number) { | ||
if (this.denominator === 1n) return new FixedNumber(this.numerator); | ||
if (this.denominator === _1N) return new FixedNumber(this.numerator); | ||
@@ -240,3 +267,3 @@ return this.round(decimals, RoundingMode.TO_ZERO); | ||
if (this.isZero()) return new FixedNumber(0n); | ||
if (this.isZero()) return new FixedNumber(_0N); | ||
@@ -248,10 +275,10 @@ let x = this.abs(); | ||
while (x.gte(1n)) { | ||
x = x.div(10n); | ||
while (x.gte(_1N)) { | ||
x = x.div(_10N); | ||
divisions++; | ||
} | ||
const zeroPointOne = new Fraction(1n, 10n); | ||
const zeroPointOne = new Fraction(_1N, _10N); | ||
while (x.lt(zeroPointOne)) { | ||
x = x.mul(10n); | ||
x = x.mul(_10N); | ||
divisions--; | ||
@@ -268,4 +295,4 @@ } | ||
private gcd(numerator: bigint, denominator: bigint): bigint { | ||
let a = numerator < 0 ? -numerator : numerator; | ||
let b = denominator < 0 ? -denominator : denominator; | ||
let a = numerator < _0N ? -numerator : numerator; | ||
let b = denominator < _0N ? -denominator : denominator; | ||
@@ -279,5 +306,5 @@ if (b > a) { | ||
while (true) { | ||
if (b === 0n) return a; | ||
if (b === _0N) return a; | ||
a %= b; | ||
if (a === 0n) return b; | ||
if (a === _0N) return b; | ||
b %= a; | ||
@@ -295,3 +322,3 @@ } | ||
const gcd = this.gcd(numerator, denominator); | ||
if (gcd > 1n) { | ||
if (gcd > _1N) { | ||
numerator /= gcd; | ||
@@ -301,3 +328,3 @@ denominator /= gcd; | ||
if (denominator < 0n) { | ||
if (denominator < _0N) { | ||
numerator = -numerator; | ||
@@ -313,3 +340,3 @@ denominator = -denominator; | ||
if (denominator === 1n) { | ||
if (denominator === _1N) { | ||
return new FixedNumber(numerator, 0); | ||
@@ -339,4 +366,4 @@ } | ||
sign(): -1 | 1 { | ||
const numeratorSign = this.numerator < 0n ? -1 : 1; | ||
const denominatorSign = this.denominator < 0n ? -1 : 1; | ||
const numeratorSign = this.numerator < _0N ? -1 : 1; | ||
const denominatorSign = this.denominator < _0N ? -1 : 1; | ||
return (numeratorSign * denominatorSign) as -1 | 1; | ||
@@ -347,4 +374,4 @@ } | ||
const res = new Fraction( | ||
this.numerator < 0n ? -this.numerator : this.numerator, | ||
this.denominator < 0n ? -this.denominator : this.denominator, | ||
this.numerator < _0N ? -this.numerator : this.numerator, | ||
this.denominator < _0N ? -this.denominator : this.denominator, | ||
); | ||
@@ -355,3 +382,3 @@ return res; | ||
neg() { | ||
return this.mul(-1n); | ||
return this.mul(-_1N); | ||
} | ||
@@ -412,3 +439,3 @@ | ||
isZero() { | ||
return this.numerator === 0n; | ||
return this.numerator === _0N; | ||
} | ||
@@ -421,3 +448,3 @@ | ||
isInteger() { | ||
return this.numerator % this.denominator === 0n; | ||
return this.numerator % this.denominator === _0N; | ||
} | ||
@@ -467,7 +494,7 @@ | ||
let d = this.denominator < 0 ? -this.denominator : this.denominator; | ||
let d = this.denominator < _0N ? -this.denominator : this.denominator; | ||
let twoExp = 0; | ||
while (d % 2n === 0n) { | ||
d /= 2n; | ||
while (d % _2N === _0N) { | ||
d /= _2N; | ||
twoExp++; | ||
@@ -477,4 +504,4 @@ } | ||
let fiveExp = 0; | ||
while (d % 5n === 0n) { | ||
d /= 5n; | ||
while (d % _5N === _0N) { | ||
d /= _5N; | ||
fiveExp++; | ||
@@ -485,3 +512,3 @@ } | ||
if (d === 1n) { | ||
if (d === _1N) { | ||
return { cycleLen: 0, cycleStart }; | ||
@@ -492,7 +519,7 @@ } | ||
let rem = 10n % d; | ||
let rem = _10N % d; | ||
let cycleLen = 1; | ||
// 10^l ≡ 1 (mod d) | ||
while (rem !== 1n) { | ||
while (rem !== _1N) { | ||
if (cycleLen === end) { | ||
@@ -502,3 +529,3 @@ // abort calculation | ||
} | ||
rem = (rem * 10n) % d; | ||
rem = (rem * _10N) % d; | ||
cycleLen++; | ||
@@ -510,6 +537,6 @@ } | ||
toFixed(decimals: number, roundingMode = RoundingMode.TO_ZERO): string { | ||
toFixed(decimals: number, roundingMode = RoundingMode.TO_ZERO, trimZeros = false): string { | ||
if (!Number.isSafeInteger(decimals) || decimals < 0) throw new Error('Invalid parameter'); | ||
return this.round(decimals, roundingMode).toFixed(decimals); | ||
return this.round(decimals, roundingMode).toFixed(decimals, RoundingMode.TO_ZERO, trimZeros); | ||
} | ||
@@ -528,3 +555,3 @@ | ||
const str = this.toFixed(outputDigits); | ||
const parts = trimTrailingZeros(str).split('.'); | ||
const parts = trimTrailingZerosFromFixed(str).split('.'); | ||
return [parts[0], parts[1] ?? '', '']; | ||
@@ -555,7 +582,7 @@ } | ||
toExponential(digits: number, roundingMode = RoundingMode.TO_ZERO): string { | ||
toExponential(digits: number, roundingMode = RoundingMode.TO_ZERO, trimZeros = false): string { | ||
if (!Number.isSafeInteger(digits) || digits < 0) throw new Error('Invalid parameters'); | ||
const fixedNum = this.toFixedNumber(digits); | ||
return fixedNum.toExponential(digits, roundingMode); | ||
return fixedNum.toExponential(digits, roundingMode, trimZeros); | ||
} | ||
@@ -570,3 +597,3 @@ | ||
private toFixedNumber(digits: number): FixedNumber { | ||
const numerator = this.numerator * 10n ** BigInt(digits); | ||
const numerator = this.numerator * _10N ** BigInt(digits); | ||
const fixedNum = new FixedNumber(numerator / this.denominator, digits); | ||
@@ -584,3 +611,5 @@ return fixedNum; | ||
if (radix === 10) { | ||
return maxDigits === undefined ? this.toRepeatingDigits(maxDigits) : trimTrailingZeros(this.toFixed(maxDigits)); | ||
return maxDigits === undefined | ||
? this.toRepeatingDigits(maxDigits) | ||
: trimTrailingZerosFromFixed(this.toFixed(maxDigits)); | ||
} | ||
@@ -627,3 +656,7 @@ | ||
return [isNegative ? '-' : '', intPart.toString(radix), digits.length ? '.' : '', ...digits].join(''); | ||
const digitsStr = digits.join(''); | ||
const res = `${isNegative ? '-' : ''}${intPart.toString(radix)}${digits.length ? '.' : ''}${digitsStr}`; | ||
return res; | ||
} | ||
@@ -639,6 +672,6 @@ | ||
toPrecision(digits: number, roundingMode = RoundingMode.TO_ZERO): string { | ||
toPrecision(digits: number, roundingMode = RoundingMode.TO_ZERO, trimZeros = false): string { | ||
if (!Number.isSafeInteger(digits) || digits < 1) throw new Error('Invalid parameter'); | ||
return this.roundToDigits(digits, roundingMode).toPrecision(digits); | ||
return this.roundToDigits(digits, roundingMode).toPrecision(digits, RoundingMode.TO_ZERO, trimZeros); | ||
} | ||
@@ -645,0 +678,0 @@ |
@@ -9,3 +9,2 @@ import * as API from '.'; | ||
'ModType', | ||
'trimTrailingZeros', | ||
'nthroot', | ||
@@ -12,0 +11,0 @@ 'sqrt', |
@@ -5,4 +5,8 @@ export { ExactNumber } from './ExactNumber'; | ||
export { trimTrailingZeros } from './util'; | ||
export * from './approx'; | ||
export { nthroot, sqrt, cbrt } from './approx/roots'; | ||
export { pow, exp } from './approx/exponential'; | ||
export { log, logn, log10, log2 } from './approx/logarithm'; | ||
export { PI, sin, cos, tan } from './approx/trigonometry'; | ||
export { asin, acos, atan } from './approx/inverse_trigonometry'; | ||
export { sinh, cosh, tanh } from './approx/hyperbolic'; | ||
export { asinh, acosh, atanh } from './approx/inverse_hyperbolic'; |
@@ -50,8 +50,8 @@ import { Fraction } from './Fraction'; | ||
/** Returns b^e mod m (modular exponentiation) */ | ||
// modpow( | ||
// exponent: number | bigint | string | ExactNumberType, | ||
// modulus: number | bigint | string | ExactNumberType, | ||
// type?: ModType, | ||
// ): ExactNumberType; | ||
/** Returns modulo of this number exponentiated to the given value (modular exponentiation) */ | ||
powm( | ||
exponent: number | bigint | string | ExactNumberType, | ||
modulus: number | bigint | string | ExactNumberType, | ||
type?: ModType, | ||
): ExactNumberType; | ||
@@ -166,3 +166,3 @@ /** Returns the result of the division of this number by the given one. */ | ||
*/ | ||
toFixed(decimals: number, roundingMode?: RoundingMode): string; | ||
toFixed(decimals: number, roundingMode?: RoundingMode, trimZeros?: boolean): string; | ||
@@ -172,3 +172,3 @@ /** Returns a string representing the number in exponential notation. | ||
*/ | ||
toExponential(digits: number, roundingMode?: RoundingMode): string; | ||
toExponential(digits: number, roundingMode?: RoundingMode, trimZeros?: boolean): string; | ||
@@ -179,3 +179,3 @@ /** Returns a string representing the number using fixed-point notation, rounded to the specified number of significant digits. | ||
*/ | ||
toPrecision(digits: number, roundingMode?: RoundingMode): string; | ||
toPrecision(digits: number, roundingMode?: RoundingMode, trimZeros?: boolean): string; | ||
@@ -182,0 +182,0 @@ /** Converts current value to a JavaScript Number */ |
@@ -1,24 +0,24 @@ | ||
import { trimTrailingZeros } from './util'; | ||
import { trimTrailingZerosFromFixed } from './util'; | ||
describe('Util functions', () => { | ||
it('trimTrailingZeros()', () => { | ||
expect(trimTrailingZeros('0')).toBe('0'); | ||
expect(trimTrailingZeros('-0')).toBe('-0'); | ||
expect(trimTrailingZeros('00000')).toBe('00000'); | ||
expect(trimTrailingZeros('0.0000')).toBe('0'); | ||
expect(trimTrailingZeros('.0000')).toBe('0'); | ||
expect(trimTrailingZeros('.0001')).toBe('.0001'); | ||
expect(trimTrailingZeros('-.00010')).toBe('-.0001'); | ||
expect(trimTrailingZeros('-123.0000')).toBe('-123'); | ||
expect(trimTrailingZeros('-123.002')).toBe('-123.002'); | ||
expect(trimTrailingZeros('-123.0020')).toBe('-123.002'); | ||
expect(trimTrailingZeros('100.00')).toBe('100'); | ||
expect(trimTrailingZeros('1231.')).toBe('1231'); | ||
expect(trimTrailingZeros('1230.0')).toBe('1230'); | ||
expect(trimTrailingZeros('1230.2304')).toBe('1230.2304'); | ||
expect(trimTrailingZeros('001230.0')).toBe('001230'); | ||
expect(trimTrailingZeros('-001230.01')).toBe('-001230.01'); | ||
expect(trimTrailingZeros('001230.010')).toBe('001230.01'); | ||
expect(trimTrailingZeros('001230.01000000')).toBe('001230.01'); | ||
it('trimTrailingZerosFromFixed()', () => { | ||
expect(trimTrailingZerosFromFixed('0')).toBe('0'); | ||
expect(trimTrailingZerosFromFixed('-0')).toBe('-0'); | ||
expect(trimTrailingZerosFromFixed('00000')).toBe('00000'); | ||
expect(trimTrailingZerosFromFixed('0.0000')).toBe('0'); | ||
expect(trimTrailingZerosFromFixed('.0000')).toBe('0'); | ||
expect(trimTrailingZerosFromFixed('.0001')).toBe('.0001'); | ||
expect(trimTrailingZerosFromFixed('-.00010')).toBe('-.0001'); | ||
expect(trimTrailingZerosFromFixed('-123.0000')).toBe('-123'); | ||
expect(trimTrailingZerosFromFixed('-123.002')).toBe('-123.002'); | ||
expect(trimTrailingZerosFromFixed('-123.0020')).toBe('-123.002'); | ||
expect(trimTrailingZerosFromFixed('100.00')).toBe('100'); | ||
expect(trimTrailingZerosFromFixed('1231.')).toBe('1231'); | ||
expect(trimTrailingZerosFromFixed('1230.0')).toBe('1230'); | ||
expect(trimTrailingZerosFromFixed('1230.2304')).toBe('1230.2304'); | ||
expect(trimTrailingZerosFromFixed('001230.0')).toBe('001230'); | ||
expect(trimTrailingZerosFromFixed('-001230.01')).toBe('-001230.01'); | ||
expect(trimTrailingZerosFromFixed('001230.010')).toBe('001230.01'); | ||
expect(trimTrailingZerosFromFixed('001230.01000000')).toBe('001230.01'); | ||
}); | ||
}); |
@@ -0,1 +1,2 @@ | ||
/* eslint-disable @typescript-eslint/naming-convention */ | ||
import { FixedNumber } from './FixedNumber'; | ||
@@ -5,3 +6,3 @@ import { ExactNumberType, RoundingMode } from './types'; | ||
/** Trims trailing zeros from numbers in fixed-point format (1.23000 -> 1.23) */ | ||
export const trimTrailingZeros = (num: string): string => { | ||
export const trimTrailingZerosFromFixed = (num: string): string => { | ||
const pointPos = num.indexOf('.'); | ||
@@ -43,3 +44,3 @@ if (pointPos === -1) return num; | ||
if (trimZeros) { | ||
str = trimTrailingZeros(str); | ||
str = trimTrailingZerosFromFixed(str); | ||
} | ||
@@ -49,3 +50,3 @@ } else { | ||
} | ||
} else if (outputDecimals > 0) { | ||
} else if (outputDecimals > 0 && !trimZeros) { | ||
str = `${str}.${'0'.repeat(outputDecimals)}`; | ||
@@ -67,12 +68,11 @@ } | ||
// 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; | ||
// }; | ||
// BigInt literals (1n) are not supported by all parsers | ||
// also, the BigInt() constructor is still too slow to call in a loop | ||
export const _0N = BigInt(0); | ||
export const _1N = BigInt(1); | ||
export const _2N = BigInt(2); | ||
export const _3N = BigInt(3); | ||
export const _4N = BigInt(4); | ||
export const _5N = BigInt(5); | ||
export const _10N = BigInt(10); | ||
export const _24N = BigInt(24); |
/* eslint-disable no-console */ | ||
import { ExactNumberType } from 'src'; | ||
import { sin, cos, tan, sqrt, cbrt } from '../src/approx'; | ||
import { ExactNumberType, sin, cos, tan, sqrt, cbrt } from 'src'; | ||
@@ -5,0 +4,0 @@ function run(name: string, fn: (digits: number) => ExactNumberType) { |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
405456
23
8417
0
160
78
1