Spaces:
Runtime error
Runtime error
| // https://github.com/Naruyoko/ExpantaNum.js/blob/develop/ExpantaNum.js | |
| //Code snippets and templates from Decimal.js | |
| ;(function (globalScope) { | |
| "use strict"; | |
| // -- EDITABLE DEFAULTS -- // | |
| var ExpantaNum = { | |
| // The maximum number of operators stored in array. | |
| // If the number of operations exceed the limit, then the least significant operations will be discarded. | |
| // This is to prevent long loops and eating away of memory and processing time. | |
| // 1000 means there are at maximum of 1000 elements in array. | |
| // It is not recommended to make this number too big. | |
| // `ExpantaNum.maxOps = 1000;` | |
| maxOps: 1e3, | |
| // Specify what format is used when serializing for JSON.stringify | |
| // | |
| // JSON 0 JSON object | |
| // STRING 1 String | |
| serializeMode: 0, | |
| // Deprecated | |
| // Level of debug information printed in console | |
| // | |
| // NONE 0 Show no information. | |
| // NORMAL 1 Show operations. | |
| // ALL 2 Show everything. | |
| debug: 0 | |
| }, | |
| // -- END OF EDITABLE DEFAULTS -- // | |
| external = true, | |
| expantaNumError = "[ExpantaNumError] ", | |
| invalidArgument = expantaNumError + "Invalid argument: ", | |
| isExpantaNum = /^[-\+]*(Infinity|NaN|(J+|J\^\d+ )?(10(\^+|\{[1-9]\d*\})|\(10(\^+|\{[1-9]\d*\})\)\^[1-9]\d* )*((\d+(\.\d*)?|\d*\.\d+)?([Ee][-\+]*))*(0|\d+(\.\d*)?|\d*\.\d+))$/, | |
| MAX_SAFE_INTEGER = 9007199254740991, | |
| MAX_E = Math.log10(MAX_SAFE_INTEGER), //15.954589770191003 | |
| // ExpantaNum.prototype object | |
| P={}, | |
| // ExpantaNum static object | |
| Q={}, | |
| // ExpantaNum constants | |
| R={}; | |
| R.ZERO=0; | |
| R.ONE=1; | |
| R.E=Math.E; | |
| R.LN2=Math.LN2; | |
| R.LN10=Math.LN10; | |
| R.LOG2E=Math.LOG2E; | |
| R.LOG10E=Math.LOG10E; | |
| R.PI=Math.PI; | |
| R.SQRT1_2=Math.SQRT1_2; | |
| R.SQRT2=Math.SQRT2; | |
| R.MAX_SAFE_INTEGER=MAX_SAFE_INTEGER; | |
| R.MIN_SAFE_INTEGER=Number.MIN_SAFE_INTEGER; | |
| R.NaN=Number.NaN; | |
| R.NEGATIVE_INFINITY=Number.NEGATIVE_INFINITY; | |
| R.POSITIVE_INFINITY=Number.POSITIVE_INFINITY; | |
| R.E_MAX_SAFE_INTEGER="e"+MAX_SAFE_INTEGER; | |
| R.EE_MAX_SAFE_INTEGER="ee"+MAX_SAFE_INTEGER; | |
| R.TETRATED_MAX_SAFE_INTEGER="10^^"+MAX_SAFE_INTEGER; | |
| R.GRAHAMS_NUMBER="J^63 10^^^(10^)^7625597484984 3638334640023.7783"; | |
| // ExpantaNum prototype methods | |
| P.absoluteValue=P.abs=function(){ | |
| var x=this.clone(); | |
| x.sign=1; | |
| return x; | |
| }; | |
| Q.absoluteValue=Q.abs=function(x){ | |
| return new ExpantaNum(x).abs(); | |
| }; | |
| P.negate=P.neg=function (){ | |
| var x=this.clone(); | |
| x.sign=x.sign*-1; | |
| return x; | |
| }; | |
| Q.negate=Q.neg=function (x){ | |
| return new ExpantaNum(x).neg(); | |
| }; | |
| P.compareTo=P.cmp=function (other){ | |
| if (!(other instanceof ExpantaNum)) other=new ExpantaNum(other); | |
| if (isNaN(this.array[0][1])||isNaN(other.array[0][1])) return NaN; | |
| if (this.array[0][1]==Infinity&&other.array[0][1]!=Infinity) return this.sign; | |
| if (this.array[0][1]!=Infinity&&other.array[0][1]==Infinity) return -other.sign; | |
| if (this.array.length==1&&this.array[0][1]===0&&other.array.length==1&&other.array[0][1]===0) return 0; | |
| if (this.sign!=other.sign) return this.sign; | |
| var m=this.sign; | |
| var r; | |
| if (this.layer>other.layer) r=1; | |
| else if (this.layer<other.layer) r=-1; | |
| else{ | |
| var e,f; | |
| for (var i=0,l=Math.min(this.array.length,other.array.length);i<l;++i){ | |
| e=this.array[this.array.length-1-i]; | |
| f=other.array[other.array.length-1-i]; | |
| if (e[0]>f[0]||e[0]==f[0]&&e[1]>f[1]){ | |
| r=1; | |
| break; | |
| }else if (e[0]<f[0]||e[0]==f[0]&&e[1]<f[1]){ | |
| r=-1; | |
| break; | |
| } | |
| } | |
| if (r===undefined){ | |
| if (this.array.length==other.array.length){ | |
| r=0; | |
| }else if (this.array.length>other.array.length){ | |
| e=this.array[this.array.length-l]; | |
| if (e[0]>=1||e[1]>10){ | |
| r=1; | |
| }else{ | |
| r=-1; | |
| } | |
| }else{ | |
| e=other.array[other.array.length-l]; | |
| if (e[0]>=1||e[1]>10){ | |
| r=-1; | |
| }else{ | |
| r=1; | |
| } | |
| } | |
| } | |
| } | |
| return r*m; | |
| }; | |
| Q.compare=Q.cmp=function (x,y){ | |
| return new ExpantaNum(x).cmp(y); | |
| }; | |
| P.greaterThan=P.gt=function (other){ | |
| return this.cmp(other)>0; | |
| }; | |
| Q.greaterThan=Q.gt=function (x,y){ | |
| return new ExpantaNum(x).gt(y); | |
| }; | |
| P.greaterThanOrEqualTo=P.gte=function (other){ | |
| return this.cmp(other)>=0; | |
| }; | |
| Q.greaterThanOrEqualTo=Q.gte=function (x,y){ | |
| return new ExpantaNum(x).gte(y); | |
| }; | |
| P.lessThan=P.lt=function (other){ | |
| return this.cmp(other)<0; | |
| }; | |
| Q.lessThan=Q.lt=function (x,y){ | |
| return new ExpantaNum(x).lt(y); | |
| }; | |
| P.lessThanOrEqualTo=P.lte=function (other){ | |
| return this.cmp(other)<=0; | |
| }; | |
| Q.lessThanOrEqualTo=Q.lte=function (x,y){ | |
| return new ExpantaNum(x).lte(y); | |
| }; | |
| P.equalsTo=P.equal=P.eq=function (other){ | |
| return this.cmp(other)===0; | |
| }; | |
| Q.equalsTo=Q.equal=Q.eq=function (x,y){ | |
| return new ExpantaNum(x).eq(y); | |
| }; | |
| P.notEqualsTo=P.notEqual=P.neq=function (other){ | |
| return this.cmp(other)!==0; | |
| }; | |
| Q.notEqualsTo=Q.notEqual=Q.neq=function (x,y){ | |
| return new ExpantaNum(x).neq(y); | |
| }; | |
| P.minimum=P.min=function (other){ | |
| return this.lt(other)?this.clone():new ExpantaNum(other); | |
| }; | |
| Q.minimum=Q.min=function (x,y){ | |
| return new ExpantaNum(x).min(y); | |
| }; | |
| P.maximum=P.max=function (other){ | |
| return this.gt(other)?this.clone():new ExpantaNum(other); | |
| }; | |
| Q.maximum=Q.max=function (x,y){ | |
| return new ExpantaNum(x).max(y); | |
| }; | |
| P.compareTo_tolerance=P.cmp_tolerance=function (other,tolerance){ | |
| if (!(other instanceof ExpantaNum)) other=new ExpantaNum(other); | |
| return this.eq_tolerance(other,tolerance)?0:this.cmp(other); | |
| }; | |
| Q.compare_tolerance=Q.cmp_tolerance=function (x,y,tolerance){ | |
| return new ExpantaNum(x).cmp_tolerance(y,tolerance); | |
| }; | |
| P.greaterThan_tolerance=P.gt_tolerance=function (other,tolerance){ | |
| if (!(other instanceof ExpantaNum)) other=new ExpantaNum(other); | |
| return !this.eq_tolerance(other,tolerance)&&this.gt(other); | |
| }; | |
| Q.greaterThan_tolerance=Q.gt_tolerance=function (x,y,tolerance){ | |
| return new ExpantaNum(x).gt_tolerance(y,tolerance); | |
| }; | |
| P.greaterThanOrEqualTo_tolerance=P.gte_tolerance=function (other,tolerance){ | |
| if (!(other instanceof ExpantaNum)) other=new ExpantaNum(other); | |
| return this.eq_tolerance(other,tolerance)||this.gt(other); | |
| }; | |
| Q.greaterThanOrEqualTo_tolerance=Q.gte_tolerance=function (x,y,tolerance){ | |
| return new ExpantaNum(x).gte_tolerance(y,tolerance); | |
| }; | |
| P.lessThan_tolerance=P.lt_tolerance=function (other,tolerance){ | |
| if (!(other instanceof ExpantaNum)) other=new ExpantaNum(other); | |
| return !this.eq_tolerance(other,tolerance)&&this.lt(other); | |
| }; | |
| Q.lessThan_tolerance=Q.lt_tolerance=function (x,y,tolerance){ | |
| return new ExpantaNum(x).lt_tolerance(y,tolerance); | |
| }; | |
| P.lessThanOrEqualTo_tolerance=P.lte_tolerance=function (other,tolerance){ | |
| if (!(other instanceof ExpantaNum)) other=new ExpantaNum(other); | |
| return this.eq_tolerance(other,tolerance)||this.lt(other); | |
| }; | |
| Q.lessThanOrEqualTo_tolerance=Q.lte_tolerance=function (x,y,tolerance){ | |
| return new ExpantaNum(x).lte_tolerance(y,tolerance); | |
| }; | |
| //From break_eternity.js | |
| //https://github.com/Patashu/break_eternity.js/blob/96901974c175cb28f66c7164a5a205cdda783872/src/index.ts#L2802 | |
| P.equalsTo_tolerance=P.equal_tolerance=P.eq_tolerance=function (other,tolerance){ | |
| if (!(other instanceof ExpantaNum)) other=new ExpantaNum(other); | |
| if (tolerance==null) tolerance=1e-7; | |
| if (this.isNaN()||other.isNaN()||this.isFinite()!=other.isFinite()) return false; | |
| if (this.sign!=other.sign) return false; | |
| if (Math.abs(this.layer-other.layer)>1) return false; | |
| var a,b; | |
| if (this.layer!=other.layer){ | |
| var x,y; | |
| if (this.layer>other.layer) x=this,y=other; | |
| else x=other,y=this; | |
| if (!(x.array.length==2&&x.array[0][0]===0&&x.array[1][0]==1&&x.array[1][1]==1)) return false; | |
| a=x.array[0][1]; | |
| if (y.array[y.array.length-1][1]>=10) b=Math.log10(y.array[y.array.length-1][0]+1); | |
| else b=Math.log10(y.array[y.array.length-1][0]); | |
| }else{ | |
| if (Math.abs(this.array[this.array.length-1][0]-other.array[other.array.length-1][0])>1) return false; | |
| for (var i=1;Math.max(this.array.length,other.array.length)-i>=0;++i){ | |
| var c=this.array[this.array.length-i][0]; | |
| var d=other.array[other.array.length-i][0]; | |
| var x,y,e,f; | |
| if (c!=d){ | |
| if (c>d) x=this,y=other; | |
| else x=other,y=this,c=d; | |
| e=x.array[x.array.length-i][1]; | |
| f=0; | |
| }else{ | |
| x=this; | |
| y=other; | |
| e=x.array[x.array.length-i][1]; | |
| f=y.array[y.array.length-i][1]; | |
| if (x.array.length-i==0){ | |
| a=e; | |
| b=f; | |
| break; | |
| } | |
| } | |
| if (Math.abs(e-f)>1) return false; | |
| if (e!=f){ | |
| if (!(x.array.length-i<2||x.array.length-i==2&&x.array[0][0]===0&&x.array[1][0]==1&&x.array[1][1]==1)) return false; | |
| a=x.array[0][1]; | |
| if (c==1) b=Math.log10(y.operator(0)); | |
| else if (c==2&&y.operator(0)>=1e10) b=Math.log10(y.operator(1)+2); | |
| else if (y.operator(c-2)>=10) b=Math.log10(y.operator(c-1)+1); | |
| else b=Math.log10(y.operator(c-1)); | |
| break; | |
| } | |
| } | |
| } | |
| return Math.abs(a-b)<=tolerance*Math.max(Math.abs(a),Math.abs(b)); | |
| }; | |
| Q.equalsTo_tolerance=Q.equal_tolerance=Q.eq_tolerance=function (x,y,tolerance){ | |
| return new ExpantaNum(x).eq_tolerance(y,tolerance); | |
| }; | |
| P.notEqualsTo_tolerance=P.notEqual_tolerance=P.neq_tolerance=function (other,tolerance){ | |
| return !this.eq_tolerance(other,tolerance); | |
| }; | |
| Q.notEqualsTo_tolerance=Q.notEqual_tolerance=Q.neq_tolerance=function (x,y,tolerance){ | |
| return new ExpantaNum(x).neq_tolerance(y,tolerance); | |
| }; | |
| P.isPositive=P.ispos=function (){ | |
| return this.gt(ExpantaNum.ZERO); | |
| }; | |
| Q.isPositive=Q.ispos=function (x){ | |
| return new ExpantaNum(x).ispos(); | |
| }; | |
| P.isNegative=P.isneg=function (){ | |
| return this.lt(ExpantaNum.ZERO); | |
| }; | |
| Q.isNegative=Q.isneg=function (x){ | |
| return new ExpantaNum(x).isneg(); | |
| }; | |
| P.isNaN=function (){ | |
| return isNaN(this.array[0][1]); | |
| }; | |
| Q.isNaN=function (x){ | |
| return new ExpantaNum(x).isNaN(); | |
| }; | |
| P.isFinite=function (){ | |
| return isFinite(this.array[0][1]); | |
| }; | |
| Q.isFinite=function (x){ | |
| return new ExpantaNum(x).isFinite(); | |
| }; | |
| P.isInfinite=function (){ | |
| return this.array[0][1]==Infinity; | |
| }; | |
| Q.isInfinite=function (x){ | |
| return new ExpantaNum(x).isInfinite(); | |
| }; | |
| P.isInteger=P.isint=function (){ | |
| if (this.sign==-1) return this.abs().isint(); | |
| if (this.gt(ExpantaNum.MAX_SAFE_INTEGER)) return true; | |
| return Number.isInteger(this.toNumber()); | |
| }; | |
| Q.isInteger=Q.isint=function (x){ | |
| return new ExpantaNum(x).isint(); | |
| }; | |
| P.floor=function (){ | |
| if (this.isInteger()) return this.clone(); | |
| return new ExpantaNum(Math.floor(this.toNumber())); | |
| }; | |
| Q.floor=function (x){ | |
| return new ExpantaNum(x).floor(); | |
| }; | |
| P.ceiling=P.ceil=function (){ | |
| if (this.isInteger()) return this.clone(); | |
| return new ExpantaNum(Math.ceil(this.toNumber())); | |
| }; | |
| Q.ceiling=Q.ceil=function (x){ | |
| return new ExpantaNum(x).ceil(); | |
| }; | |
| P.round=function (){ | |
| if (this.isInteger()) return this.clone(); | |
| return new ExpantaNum(Math.round(this.toNumber())); | |
| }; | |
| Q.round=function (x){ | |
| return new ExpantaNum(x).round(); | |
| }; | |
| var debugMessageSent=false; | |
| P.plus=P.add=function (other){ | |
| var x=this.clone(); | |
| other=new ExpantaNum(other); | |
| if (ExpantaNum.debug>=ExpantaNum.NORMAL){ | |
| console.log(this+"+"+other); | |
| if (!debugMessageSent) console.warn(expantaNumError+"Debug output via 'debug' is being deprecated and will be removed in the future!"),debugMessageSent=true; | |
| } | |
| if (x.sign==-1) return x.neg().add(other.neg()).neg(); | |
| if (other.sign==-1) return x.sub(other.neg()); | |
| if (x.eq(ExpantaNum.ZERO)) return other; | |
| if (other.eq(ExpantaNum.ZERO)) return x; | |
| if (x.isNaN()||other.isNaN()||x.isInfinite()&&other.isInfinite()&&x.eq(other.neg())) return ExpantaNum.NaN.clone(); | |
| if (x.isInfinite()) return x; | |
| if (other.isInfinite()) return other; | |
| var p=x.min(other); | |
| var q=x.max(other); | |
| var op0=q.operator(0); | |
| var op1=q.operator(1); | |
| var t; | |
| if (q.gt(ExpantaNum.E_MAX_SAFE_INTEGER)||q.div(p).gt(ExpantaNum.MAX_SAFE_INTEGER)){ | |
| t=q; | |
| }else if (!op1){ | |
| t=new ExpantaNum(x.toNumber()+other.toNumber()); | |
| }else if (op1==1){ | |
| var a=p.operator(1)?p.operator(0):Math.log10(p.operator(0)); | |
| t=new ExpantaNum([a+Math.log10(Math.pow(10,op0-a)+1),1]); | |
| } | |
| p=q=null; | |
| return t; | |
| }; | |
| Q.plus=Q.add=function (x,y){ | |
| return new ExpantaNum(x).add(y); | |
| }; | |
| P.minus=P.sub=function (other){ | |
| var x=this.clone(); | |
| other=new ExpantaNum(other); | |
| if (ExpantaNum.debug>=ExpantaNum.NORMAL) console.log(x+"-"+other); | |
| if (x.sign==-1) return x.neg().sub(other.neg()).neg(); | |
| if (other.sign==-1) return x.add(other.neg()); | |
| if (x.eq(other)) return ExpantaNum.ZERO.clone(); | |
| if (other.eq(ExpantaNum.ZERO)) return x; | |
| if (x.isNaN()||other.isNaN()||x.isInfinite()&&other.isInfinite()) return ExpantaNum.NaN.clone(); | |
| if (x.isInfinite()) return x; | |
| if (other.isInfinite()) return other.neg(); | |
| var p=x.min(other); | |
| var q=x.max(other); | |
| var n=other.gt(x); | |
| var op0=q.operator(0); | |
| var op1=q.operator(1); | |
| var t; | |
| if (q.gt(ExpantaNum.E_MAX_SAFE_INTEGER)||q.div(p).gt(ExpantaNum.MAX_SAFE_INTEGER)){ | |
| t=q; | |
| t=n?t.neg():t; | |
| }else if (!op1){ | |
| t=new ExpantaNum(x.toNumber()-other.toNumber()); | |
| }else if (op1==1){ | |
| var a=p.operator(1)?p.operator(0):Math.log10(p.operator(0)); | |
| t=new ExpantaNum([a+Math.log10(Math.pow(10,op0-a)-1),1]); | |
| t=n?t.neg():t; | |
| } | |
| p=q=null; | |
| return t; | |
| }; | |
| Q.minus=Q.sub=function (x,y){ | |
| return new ExpantaNum(x).sub(y); | |
| }; | |
| P.times=P.mul=function (other){ | |
| var x=this.clone(); | |
| other=new ExpantaNum(other); | |
| if (ExpantaNum.debug>=ExpantaNum.NORMAL) console.log(x+"*"+other); | |
| if (x.sign*other.sign==-1) return x.abs().mul(other.abs()).neg(); | |
| if (x.sign==-1) return x.abs().mul(other.abs()); | |
| if (x.isNaN()||other.isNaN()||x.eq(ExpantaNum.ZERO)&&other.isInfinite()||x.isInfinite()&&other.abs().eq(ExpantaNum.ZERO)) return ExpantaNum.NaN.clone(); | |
| if (other.eq(ExpantaNum.ZERO)) return ExpantaNum.ZERO.clone(); | |
| if (other.eq(ExpantaNum.ONE)) return x.clone(); | |
| if (x.isInfinite()) return x; | |
| if (other.isInfinite()) return other; | |
| if (x.max(other).gt(ExpantaNum.EE_MAX_SAFE_INTEGER)) return x.max(other); | |
| var n=x.toNumber()*other.toNumber(); | |
| if (n<=MAX_SAFE_INTEGER) return new ExpantaNum(n); | |
| return ExpantaNum.pow(10,x.log10().add(other.log10())); | |
| }; | |
| Q.times=Q.mul=function (x,y){ | |
| return new ExpantaNum(x).mul(y); | |
| }; | |
| P.divide=P.div=function (other){ | |
| var x=this.clone(); | |
| other=new ExpantaNum(other); | |
| if (ExpantaNum.debug>=ExpantaNum.NORMAL) console.log(x+"/"+other); | |
| if (x.sign*other.sign==-1) return x.abs().div(other.abs()).neg(); | |
| if (x.sign==-1) return x.abs().div(other.abs()); | |
| if (x.isNaN()||other.isNaN()||x.isInfinite()&&other.isInfinite()||x.eq(ExpantaNum.ZERO)&&other.eq(ExpantaNum.ZERO)) return ExpantaNum.NaN.clone(); | |
| if (other.eq(ExpantaNum.ZERO)) return ExpantaNum.POSITIVE_INFINITY.clone(); | |
| if (other.eq(ExpantaNum.ONE)) return x.clone(); | |
| if (x.eq(other)) return ExpantaNum.ONE.clone(); | |
| if (x.isInfinite()) return x; | |
| if (other.isInfinite()) return ExpantaNum.ZERO.clone(); | |
| if (x.max(other).gt(ExpantaNum.EE_MAX_SAFE_INTEGER)) return x.gt(other)?x.clone():ExpantaNum.ZERO.clone(); | |
| var n=x.toNumber()/other.toNumber(); | |
| if (n<=MAX_SAFE_INTEGER) return new ExpantaNum(n); | |
| var pw=ExpantaNum.pow(10,x.log10().sub(other.log10())); | |
| var fp=pw.floor(); | |
| if (pw.sub(fp).lt(new ExpantaNum(1e-9))) return fp; | |
| return pw; | |
| }; | |
| Q.divide=Q.div=function (x,y){ | |
| return new ExpantaNum(x).div(y); | |
| }; | |
| P.reciprocate=P.rec=function (){ | |
| if (ExpantaNum.debug>=ExpantaNum.NORMAL) console.log(this+"^-1"); | |
| if (this.isNaN()||this.eq(ExpantaNum.ZERO)) return ExpantaNum.NaN.clone(); | |
| if (this.abs().gt("2e323")) return ExpantaNum.ZERO.clone(); | |
| return new ExpantaNum(1/this); | |
| }; | |
| Q.reciprocate=Q.rec=function (x){ | |
| return new ExpantaNum(x).rec(); | |
| }; | |
| P.modular=P.mod=function (other){ | |
| other=new ExpantaNum(other); | |
| if (other.eq(ExpantaNum.ZERO)) return ExpantaNum.ZERO.clone(); | |
| if (this.sign*other.sign==-1) return this.abs().mod(other.abs()).neg(); | |
| if (this.sign==-1) return this.abs().mod(other.abs()); | |
| return this.sub(this.div(other).floor().mul(other)); | |
| }; | |
| Q.modular=Q.mod=function (x,y){ | |
| return new ExpantaNum(x).mod(y); | |
| }; | |
| //All of these are from Patashu's break_eternity.js | |
| //from HyperCalc source code | |
| var f_gamma=function (n){ | |
| if (!isFinite(n)) return n; | |
| if (n<-50){ | |
| if (n==Math.trunc(n)) return Number.NEGATIVE_INFINITY; | |
| return 0; | |
| } | |
| var scal1=1; | |
| while (n<10){ | |
| scal1=scal1*n; | |
| ++n; | |
| } | |
| n-=1; | |
| var l=0.9189385332046727; //0.5*Math.log(2*Math.PI) | |
| l+=(n+0.5)*Math.log(n); | |
| l-=n; | |
| var n2=n*n; | |
| var np=n; | |
| l+=1/(12*np); | |
| np*=n2; | |
| l-=1/(360*np); | |
| np*=np*n2; | |
| l+=1/(1260*np); | |
| np*=n2; | |
| l-=1/(1680*np); | |
| np*=n2; | |
| l+=1/(1188*np); | |
| np*=n2; | |
| l-=691/(360360*np); | |
| np*=n2; | |
| l+=7/(1092*np); | |
| np*=n2; | |
| l-=3617/(122400*np); | |
| return Math.exp(l)/scal1; | |
| }; | |
| //from HyperCalc source code | |
| P.gamma=function (){ | |
| var x=this.clone(); | |
| if (x.gt(ExpantaNum.TETRATED_MAX_SAFE_INTEGER)) return x; | |
| if (x.gt(ExpantaNum.E_MAX_SAFE_INTEGER)) return ExpantaNum.exp(x); | |
| if (x.gt(ExpantaNum.MAX_SAFE_INTEGER)) return ExpantaNum.exp(ExpantaNum.mul(x,ExpantaNum.ln(x).sub(1))); | |
| var n=x.operator(0); | |
| if (n>1){ | |
| if (n<24) return new ExpantaNum(f_gamma(x.sign*n)); | |
| var t=n-1; | |
| var l=0.9189385332046727; //0.5*Math.log(2*Math.PI) | |
| l+=((t+0.5)*Math.log(t)); | |
| l-=t; | |
| var n2=t*t; | |
| var np=t; | |
| var lm=12*np; | |
| var adj=1/lm; | |
| var l2=l+adj; | |
| if (l2==l) return ExpantaNum.exp(l); | |
| l=l2; | |
| np*=n2; | |
| lm=360*np; | |
| adj=1/lm; | |
| l2=l-adj; | |
| if (l2==l) return ExpantaNum.exp(l); | |
| l=l2; | |
| np*=n2; | |
| lm=1260*np; | |
| var lt=1/lm; | |
| l+=lt; | |
| np*=n2; | |
| lm=1680*np; | |
| lt=1/lm; | |
| l-=lt; | |
| return ExpantaNum.exp(l); | |
| }else return this.rec(); | |
| }; | |
| Q.gamma=function (x){ | |
| return new ExpantaNum(x).gamma(); | |
| }; | |
| //end break_eternity.js excerpt | |
| Q.factorials=[1,1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600,6227020800,87178291200,1307674368000,20922789888000,355687428096000,6402373705728000,121645100408832000,2432902008176640000,51090942171709440000,1.1240007277776076800e+21,2.5852016738884978213e+22,6.2044840173323941000e+23,1.5511210043330986055e+25,4.0329146112660565032e+26,1.0888869450418351940e+28,3.0488834461171387192e+29,8.8417619937397018986e+30,2.6525285981219106822e+32,8.2228386541779224302e+33,2.6313083693369351777e+35,8.6833176188118859387e+36,2.9523279903960415733e+38,1.0333147966386145431e+40,3.7199332678990125486e+41,1.3763753091226345579e+43,5.2302261746660111714e+44,2.0397882081197444123e+46,8.1591528324789768380e+47,3.3452526613163807956e+49,1.4050061177528799549e+51,6.0415263063373834074e+52,2.6582715747884488694e+54,1.1962222086548018857e+56,5.5026221598120891536e+57,2.5862324151116817767e+59,1.2413915592536072528e+61,6.0828186403426752249e+62,3.0414093201713375576e+64,1.5511187532873821895e+66,8.0658175170943876846e+67,4.2748832840600254848e+69,2.3084369733924137924e+71,1.2696403353658276447e+73,7.1099858780486348103e+74,4.0526919504877214100e+76,2.3505613312828784949e+78,1.3868311854568983861e+80,8.3209871127413898951e+81,5.0758021387722483583e+83,3.1469973260387939390e+85,1.9826083154044400850e+87,1.2688693218588416544e+89,8.2476505920824715167e+90,5.4434493907744306945e+92,3.6471110918188683221e+94,2.4800355424368305480e+96,1.7112245242814129738e+98,1.1978571669969892213e+100,8.5047858856786230047e+101,6.1234458376886084639e+103,4.4701154615126843855e+105,3.3078854415193862416e+107,2.4809140811395399745e+109,1.8854947016660503806e+111,1.4518309202828587210e+113,1.1324281178206296794e+115,8.9461821307829757136e+116,7.1569457046263805709e+118,5.7971260207473678414e+120,4.7536433370128420198e+122,3.9455239697206587884e+124,3.3142401345653531943e+126,2.8171041143805501310e+128,2.4227095383672734128e+130,2.1077572983795278544e+132,1.8548264225739843605e+134,1.6507955160908460244e+136,1.4857159644817615149e+138,1.3520015276784029158e+140,1.2438414054641308179e+142,1.1567725070816415659e+144,1.0873661566567430754e+146,1.0329978488239059305e+148,9.9167793487094964784e+149,9.6192759682482120384e+151,9.4268904488832479837e+153,9.3326215443944153252e+155,9.3326215443944150966e+157,9.4259477598383598816e+159,9.6144667150351270793e+161,9.9029007164861804721e+163,1.0299016745145628100e+166,1.0813967582402909767e+168,1.1462805637347083683e+170,1.2265202031961380050e+172,1.3246418194518290179e+174,1.4438595832024936625e+176,1.5882455415227430287e+178,1.7629525510902445874e+180,1.9745068572210740115e+182,2.2311927486598137657e+184,2.5435597334721876552e+186,2.9250936934930159967e+188,3.3931086844518980862e+190,3.9699371608087210616e+192,4.6845258497542909237e+194,5.5745857612076058231e+196,6.6895029134491271205e+198,8.0942985252734440920e+200,9.8750442008336010580e+202,1.2146304367025329301e+205,1.5061417415111409314e+207,1.8826771768889261129e+209,2.3721732428800468512e+211,3.0126600184576594309e+213,3.8562048236258040716e+215,4.9745042224772874590e+217,6.4668554892204741474e+219,8.4715806908788206314e+221,1.1182486511960043298e+224,1.4872707060906857134e+226,1.9929427461615187928e+228,2.6904727073180504073e+230,3.6590428819525488642e+232,5.0128887482749919605e+234,6.9177864726194885808e+236,9.6157231969410893532e+238,1.3462012475717525742e+241,1.8981437590761708898e+243,2.6953641378881628530e+245,3.8543707171800730787e+247,5.5502938327393044385e+249,8.0479260574719917061e+251,1.1749972043909107097e+254,1.7272458904546389230e+256,2.5563239178728653927e+258,3.8089226376305697893e+260,5.7133839564458546840e+262,8.6272097742332399855e+264,1.3113358856834524492e+267,2.0063439050956822953e+269,3.0897696138473507759e+271,4.7891429014633940780e+273,7.4710629262828942235e+275,1.1729568794264144743e+278,1.8532718694937349890e+280,2.9467022724950384028e+282,4.7147236359920616095e+284,7.5907050539472189932e+286,1.2296942187394494177e+289,2.0044015765453026266e+291,3.2872185855342959088e+293,5.4239106661315886750e+295,9.0036917057784375454e+297,1.5036165148649991456e+300,2.5260757449731984219e+302,4.2690680090047051083e+304,7.2574156153079990350e+306]; | |
| P.factorial=P.fact=function (){ | |
| var x=this.clone(); | |
| var f=ExpantaNum.factorials; | |
| if (x.lt(ExpantaNum.ZERO)||!x.isint()) return x.add(1).gamma(); | |
| if (x.lte(170)) return new ExpantaNum(f[+x]); | |
| var errorFixer=1; | |
| var e=+x; | |
| if (e<500) e+=163879/209018880*Math.pow(e,5); | |
| if (e<1000) e+=-571/2488320*Math.pow(e,4); | |
| if (e<50000) e+=-139/51840*Math.pow(e,3); | |
| if (e<1e7) e+=1/288*Math.pow(e,2); | |
| if (e<1e20) e+=1/12*e; | |
| return x.div(ExpantaNum.E).pow(x).mul(x.mul(ExpantaNum.PI).mul(2).sqrt()).times(errorFixer); | |
| }; | |
| Q.factorial=Q.fact=function (x){ | |
| return new ExpantaNum(x).fact(); | |
| }; | |
| P.toPower=P.pow=function (other){ | |
| other=new ExpantaNum(other); | |
| if (ExpantaNum.debug>=ExpantaNum.NORMAL) console.log(this+"^"+other); | |
| if (other.eq(ExpantaNum.ZERO)) return ExpantaNum.ONE.clone(); | |
| if (other.eq(ExpantaNum.ONE)) return this.clone(); | |
| if (other.lt(ExpantaNum.ZERO)) return this.pow(other.neg()).rec(); | |
| if (this.lt(ExpantaNum.ZERO)&&other.isint()){ | |
| if (other.mod(2).lt(ExpantaNum.ONE)) return this.abs().pow(other); | |
| return this.abs().pow(other).neg(); | |
| } | |
| if (this.lt(ExpantaNum.ZERO)) return ExpantaNum.NaN.clone(); | |
| if (this.eq(ExpantaNum.ONE)) return ExpantaNum.ONE.clone(); | |
| if (this.eq(ExpantaNum.ZERO)) return ExpantaNum.ZERO.clone(); | |
| if (this.max(other).gt(ExpantaNum.TETRATED_MAX_SAFE_INTEGER)) return this.max(other); | |
| if (this.eq(10)){ | |
| if (other.gt(ExpantaNum.ZERO)){ | |
| other.operator(1,(other.operator(1)+1)||1); | |
| other.normalize(); | |
| return other; | |
| }else{ | |
| return new ExpantaNum(Math.pow(10,other.toNumber())); | |
| } | |
| } | |
| if (other.lt(ExpantaNum.ONE)) return this.root(other.rec()); | |
| var n=Math.pow(this.toNumber(),other.toNumber()); | |
| if (n<=MAX_SAFE_INTEGER) return new ExpantaNum(n); | |
| return ExpantaNum.pow(10,this.log10().mul(other)); | |
| }; | |
| Q.toPower=Q.pow=function (x,y){ | |
| return new ExpantaNum(x).pow(y); | |
| }; | |
| P.exponential=P.exp=function (){ | |
| return ExpantaNum.pow(Math.E,this); | |
| }; | |
| Q.exponential=Q.exp=function (x){ | |
| return ExpantaNum.pow(Math.E,x); | |
| }; | |
| P.squareRoot=P.sqrt=function (){ | |
| return this.root(2); | |
| }; | |
| Q.squareRoot=Q.sqrt=function (x){ | |
| return new ExpantaNum(x).root(2); | |
| }; | |
| P.cubeRoot=P.cbrt=function (){ | |
| return this.root(3); | |
| }; | |
| Q.cubeRoot=Q.cbrt=function (x){ | |
| return new ExpantaNum(x).root(3); | |
| }; | |
| P.root=function (other){ | |
| other=new ExpantaNum(other); | |
| if (ExpantaNum.debug>=ExpantaNum.NORMAL) console.log(this+"root"+other); | |
| if (other.eq(ExpantaNum.ONE)) return this.clone(); | |
| if (other.lt(ExpantaNum.ZERO)) return this.root(other.neg()).rec(); | |
| if (other.lt(ExpantaNum.ONE)) return this.pow(other.rec()); | |
| if (this.lt(ExpantaNum.ZERO)&&other.isint()&&other.mod(2).eq(ExpantaNum.ONE)) return this.neg().root(other).neg(); | |
| if (this.lt(ExpantaNum.ZERO)) return ExpantaNum.NaN.clone(); | |
| if (this.eq(ExpantaNum.ONE)) return ExpantaNum.ONE.clone(); | |
| if (this.eq(ExpantaNum.ZERO)) return ExpantaNum.ZERO.clone(); | |
| if (this.max(other).gt(ExpantaNum.TETRATED_MAX_SAFE_INTEGER)) return this.gt(other)?this.clone():ExpantaNum.ZERO.clone(); | |
| return ExpantaNum.pow(10,this.log10().div(other)); | |
| }; | |
| Q.root=function (x,y){ | |
| return new ExpantaNum(x).root(y); | |
| }; | |
| P.generalLogarithm=P.log10=function (){ | |
| var x=this.clone(); | |
| if (ExpantaNum.debug>=ExpantaNum.NORMAL) console.log("log"+this); | |
| if (x.lt(ExpantaNum.ZERO)) return ExpantaNum.NaN.clone(); | |
| if (x.eq(ExpantaNum.ZERO)) return ExpantaNum.NEGATIVE_INFINITY.clone(); | |
| if (x.lte(ExpantaNum.MAX_SAFE_INTEGER)) return new ExpantaNum(Math.log10(x.toNumber())); | |
| if (!x.isFinite()) return x; | |
| if (x.gt(ExpantaNum.TETRATED_MAX_SAFE_INTEGER)) return x; | |
| x.operator(1,x.operator(1)-1); | |
| return x.normalize(); | |
| }; | |
| Q.generalLogarithm=Q.log10=function (x){ | |
| return new ExpantaNum(x).log10(); | |
| }; | |
| P.logarithm=P.logBase=function (base){ | |
| if (base===undefined) base=Math.E; | |
| return this.log10().div(ExpantaNum.log10(base)); | |
| }; | |
| Q.logarithm=Q.logBase=function (x,base){ | |
| return new ExpantaNum(x).logBase(base); | |
| }; | |
| P.naturalLogarithm=P.log=P.ln=function (){ | |
| return this.logBase(Math.E); | |
| }; | |
| Q.naturalLogarithm=Q.log=Q.ln=function (x){ | |
| return new ExpantaNum(x).ln(); | |
| }; | |
| //All of these are from Patashu's break_eternity.js | |
| var OMEGA=0.56714329040978387299997; //W(1,0) | |
| //from https://math.stackexchange.com/a/465183 | |
| //The evaluation can become inaccurate very close to the branch point | |
| var f_lambertw=function (z,tol,principal){ | |
| if (tol===undefined) tol=1e-10; | |
| if (principal===undefined) principal=true; | |
| var w; | |
| if (!Number.isFinite(z)) return z; | |
| if (principal){ | |
| if (z===0) return z; | |
| if (z===1) return OMEGA; | |
| if (z<10) w=0; | |
| else w=Math.log(z)-Math.log(Math.log(z)); | |
| }else{ | |
| if (z===0) return -Infinity; | |
| if (z<=-0.1) w=-2; | |
| else w=Math.log(-z)-Math.log(-Math.log(-z)); | |
| } | |
| for (var i=0;i<100;++i){ | |
| var wn=(z*Math.exp(-w)+w*w)/(w+1); | |
| if (Math.abs(wn-w)<tol*Math.abs(wn)) return wn; | |
| w=wn; | |
| } | |
| throw Error("Iteration failed to converge: "+z); | |
| }; | |
| //from https://github.com/scipy/scipy/blob/8dba340293fe20e62e173bdf2c10ae208286692f/scipy/special/lambertw.pxd | |
| //The evaluation can become inaccurate very close to the branch point | |
| //at ``-1/e``. In some corner cases, `lambertw` might currently | |
| //fail to converge, or can end up on the wrong branch. | |
| var d_lambertw=function (z,tol,principal){ | |
| if (tol===undefined) tol=1e-10; | |
| if (principal===undefined) principal=true; | |
| z=new ExpantaNum(z); | |
| var w; | |
| if (!z.isFinite()) return z; | |
| if (principal){ | |
| if (z.eq(ExpantaNum.ZERO)) return z; | |
| if (z.eq(ExpantaNum.ONE)) return new ExpantaNum(OMEGA); | |
| w=ExpantaNum.ln(z); | |
| }else{ | |
| if (z.eq(ExpantaNum.ZERO)) return ExpantaNum.NEGATIVE_INFINITY.clone(); | |
| w=ExpantaNum.ln(z.neg()); | |
| } | |
| for (var i=0;i<100;++i){ | |
| var ew=w.neg().exp(); | |
| var wewz=w.sub(z.mul(ew)); | |
| var dd=w.add(ExpantaNum.ONE).sub(w.add(2).mul(wewz).div(ExpantaNum.mul(2,w).add(2))); | |
| if (dd.eq(ExpantaNum.ZERO)) return w; //Escape to fix https://github.com/Naruyoko/ExpantaNum.js/issues/25 | |
| var wn=w.sub(wewz.div(dd)); | |
| if (ExpantaNum.abs(wn.sub(w)).lt(ExpantaNum.abs(wn).mul(tol))) return wn; | |
| w = wn; | |
| } | |
| throw Error("Iteration failed to converge: "+z); | |
| }; | |
| //The Lambert W function, also called the omega function or product logarithm, is the solution W(x) === x*e^x. | |
| //https://en.wikipedia.org/wiki/Lambert_W_function | |
| //Some special values, for testing: https://en.wikipedia.org/wiki/Lambert_W_function#Special_values | |
| P.lambertw=function (principal){ | |
| if (principal===undefined) principal=true; | |
| var x=this.clone(); | |
| if (x.isNaN()) return x; | |
| if (x.lt(-0.3678794411710499)) return ExpantaNum.NaN.clone(); | |
| if (principal){ | |
| if (x.gt(ExpantaNum.TETRATED_MAX_SAFE_INTEGER)) return x; | |
| if (x.gt(ExpantaNum.EE_MAX_SAFE_INTEGER)){ | |
| x.operator(1,x.operator(1)-1); | |
| return x; | |
| } | |
| if (x.gt(ExpantaNum.MAX_SAFE_INTEGER)) return d_lambertw(x); | |
| else return new ExpantaNum(f_lambertw(x.sign*x.operator(0))); | |
| }else{ | |
| if (x.ispos()) return ExpantaNum.NaN.clone(); | |
| if (x.abs().gt(ExpantaNum.EE_MAX_SAFE_INTEGER)) return x.neg().rec().lambertw().neg(); | |
| if (x.abs().gt(ExpantaNum.MAX_SAFE_INTEGER)) return d_lambertw(x,1e-10,false); | |
| else return new ExpantaNum(f_lambertw(x.sign*x.operator(0),1e-10,false)); | |
| } | |
| }; | |
| Q.lambertw=function (x,principal){ | |
| return new ExpantaNum(x).lambertw(principal); | |
| }; | |
| //end break_eternity.js excerpt | |
| //Uses linear approximations for real height | |
| P.tetrate=P.tetr=function (other,payload){ | |
| if (payload===undefined) payload=ExpantaNum.ONE; | |
| var t=this.clone(); | |
| other=new ExpantaNum(other); | |
| payload=new ExpantaNum(payload); | |
| if (t.isNaN()||other.isNaN()||payload.isNaN()) return ExpantaNum.NaN.clone(); | |
| if (payload.neq(ExpantaNum.ONE)) other=other.add(payload.slog(t)); | |
| if (ExpantaNum.debug>=ExpantaNum.NORMAL) console.log(t+"^^"+other); | |
| var negln; | |
| if (other.isInfinite()&&other.sign>0){ | |
| if (t.gte(Math.exp(1/Math.E))) return ExpantaNum.POSITIVE_INFINITY.clone(); | |
| //Formula for infinite height power tower. | |
| negln = t.ln().neg(); | |
| return negln.lambertw().div(negln); | |
| } | |
| if (other.lte(-2)) return ExpantaNum.NaN.clone(); | |
| if (t.eq(ExpantaNum.ZERO)){ | |
| if (other.eq(ExpantaNum.ZERO)) return ExpantaNum.NaN.clone(); | |
| if (other.mod(2).eq(ExpantaNum.ZERO)) return ExpantaNum.ZERO.clone(); | |
| return ExpantaNum.ONE.clone(); | |
| } | |
| if (t.eq(ExpantaNum.ONE)){ | |
| if (other.eq(ExpantaNum.ONE.neg())) return ExpantaNum.NaN.clone(); | |
| return ExpantaNum.ONE.clone(); | |
| } | |
| if (other.eq(ExpantaNum.ONE.neg())) return ExpantaNum.ZERO.clone(); | |
| if (other.eq(ExpantaNum.ZERO)) return ExpantaNum.ONE.clone(); | |
| if (other.eq(ExpantaNum.ONE)) return t; | |
| if (other.eq(2)) return t.pow(t); | |
| if (t.eq(2)){ | |
| if (other.eq(3)) return new ExpantaNum(16); | |
| if (other.eq(4)) return new ExpantaNum(65536); | |
| } | |
| var m=t.max(other); | |
| if (m.gt("10^^^"+MAX_SAFE_INTEGER)) return m; | |
| if (m.gt(ExpantaNum.TETRATED_MAX_SAFE_INTEGER)||other.gt(ExpantaNum.MAX_SAFE_INTEGER)){ | |
| if (this.lt(Math.exp(1/Math.E))){ | |
| negln = t.ln().neg(); | |
| return negln.lambertw().div(negln); | |
| } | |
| var j=t.slog(10).add(other); | |
| j.operator(2,(j.operator(2)||0)+1); | |
| j.normalize(); | |
| return j; | |
| } | |
| var y=other.toNumber(); | |
| var f=Math.floor(y); | |
| var r=t.pow(y-f); | |
| var l=ExpantaNum.NaN; | |
| for (var i=0,w=new ExpantaNum(ExpantaNum.E_MAX_SAFE_INTEGER);f!==0&&r.lt(w)&&i<100;++i){ | |
| if (f>0){ | |
| r=t.pow(r); | |
| if (l.eq(r)){ | |
| f=0; | |
| break; | |
| } | |
| l=r; | |
| --f; | |
| }else{ | |
| r=r.logBase(t); | |
| if (l.eq(r)){ | |
| f=0; | |
| break; | |
| } | |
| l=r; | |
| ++f; | |
| } | |
| } | |
| if (i==100||this.lt(Math.exp(1/Math.E))) f=0; | |
| r.operator(1,(r.operator(1)+f)||f); | |
| r.normalize(); | |
| return r; | |
| }; | |
| Q.tetrate=Q.tetr=function (x,y,payload){ | |
| return new ExpantaNum(x).tetr(y,payload); | |
| }; | |
| //Implementation of functions from break_eternity.js | |
| P.iteratedexp=function (other,payload){ | |
| return this.tetr(other,payload); | |
| }; | |
| Q.iteratedexp=function (x,y,payload){ | |
| return new ExpantaNum(x).iteratedexp(y,payload); | |
| }; | |
| //This implementation is highly inaccurate and slow, and probably be given custom code | |
| P.iteratedlog=function (base,other){ | |
| if (base===undefined) base=10; | |
| if (other===undefined) other=ExpantaNum.ONE.clone(); | |
| var t=this.clone(); | |
| base=new ExpantaNum(base); | |
| other=new ExpantaNum(other); | |
| if (other.eq(ExpantaNum.ZERO)) return t; | |
| if (other.eq(ExpantaNum.ONE)) return t.logBase(base); | |
| return base.tetr(t.slog(base).sub(other)); | |
| }; | |
| Q.iteratedlog=function (x,y,z){ | |
| return new ExpantaNum(x).iteratedlog(y,z); | |
| }; | |
| P.layeradd=function (other,base){ | |
| if (base===undefined) base=10; | |
| if (other===undefined) other=ExpantaNum.ONE.clone(); | |
| var t=this.clone(); | |
| base=new ExpantaNum(base); | |
| other=new ExpantaNum(other); | |
| return base.tetr(t.slog(base).add(other)); | |
| }; | |
| Q.layeradd=function (x,y,z){ | |
| return new ExpantaNum(x).layeradd(y,z); | |
| }; | |
| P.layeradd10=function (other){ | |
| return this.layeradd(other); | |
| }; | |
| Q.layeradd10=function (x,y){ | |
| return new ExpantaNum(x).layeradd10(y); | |
| }; | |
| //End implementation from break_eternity.js | |
| //All of these are from Patashu's break_eternity.js | |
| //The super square-root function - what number, tetrated to height 2, equals this? | |
| //Other sroots are possible to calculate probably through guess and check methods, this one is easy though. | |
| //https://en.wikipedia.org/wiki/Tetration#Super-root | |
| P.ssqrt=P.ssrt=function (){ | |
| var x=this.clone(); | |
| if (x.lt(Math.exp(-1/Math.E))) return ExpantaNum.NaN.clone(); | |
| if (!x.isFinite()) return x; | |
| if (x.gt(ExpantaNum.TETRATED_MAX_SAFE_INTEGER)) return x; | |
| if (x.gt(ExpantaNum.EE_MAX_SAFE_INTEGER)){ | |
| x.operator(1,x.operator(1)-1); | |
| return x; | |
| } | |
| var l=x.ln(); | |
| return l.div(l.lambertw()); | |
| }; | |
| Q.ssqrt=Q.ssrt=function (x){ | |
| return new ExpantaNum(x).ssqrt(); | |
| }; | |
| //Uses linear approximation | |
| //For more information, please see the break_eternity.js source: | |
| //https://github.com/Patashu/break_eternity.js/blob/848736e3dc37d8e7b5cc238f46e3ddb277d0dce2/src/index.ts#L4008 | |
| P.linear_sroot=function (degree){ | |
| var x=new ExpantaNum(this); | |
| degree=new ExpantaNum(degree); | |
| if (degree.isNaN()) return ExpantaNum.NaN.clone(); | |
| var degreeNum=Number(degree); | |
| if (degreeNum==1) return x; | |
| if (x.eq(ExpantaNum.POSITIVE_INFINITY)) return ExpantaNum.POSITIVE_INFINITY.clone(); | |
| if (!x.isFinite()) return ExpantaNum.NaN.clone(); | |
| if (degreeNum>0&°reeNum<1) return x.root(degree); | |
| if (degreeNum>-2&°reeNum<-1) return degree.add(2).pow(x.rec()); | |
| if (degreeNum<=0) return ExpantaNum.NaN.clone(); | |
| if (degree.gt(ExpantaNum.MAX_SAFE_INTEGER)){ | |
| var xNum=Number(x); | |
| if (xNum<Math.E&&xNum>1/Math.E) return x.pow(x.rec()); | |
| if (x.gt(ExpantaNum.TETRATED_MAX_SAFE_INTEGER)){ | |
| var nh=x.slog(10).sub(degree); | |
| if (nh.lte(ExpantaNum.ZERO)) return new ExpantaNum(Math.exp(1/Math.E)); | |
| return ExpantaNum.tetr(10,nh); | |
| } | |
| return ExpantaNum.NaN.clone(); | |
| } | |
| if (x.eq(ExpantaNum.ONE)) return ExpantaNum.ONE.clone(); | |
| if (x.lt(ExpantaNum.ZERO)) return ExpantaNum.NaN.clone(); | |
| if (x.eq(ExpantaNum.ZERO)) return ExpantaNum.ZERO.clone(); | |
| if (x.gt(ExpantaNum.ONE)){ | |
| var upperBound; | |
| if (degreeNum<=1) upperBound=x.root(degree); | |
| else if (x.gte(ExpantaNum.tetr(10,degree))) upperBound=x.iteratedlog(10,degreeNum-1); | |
| else upperBound=new ExpantaNum(10); | |
| var lower=ExpantaNum.ZERO; | |
| var layer=upperBound.array[2]||0; | |
| var upper=upperBound.iteratedlog(10,layer); | |
| var guess=upper.div(2); | |
| while (true){ | |
| if (ExpantaNum.iteratedexp(10,layer,guess).tetr(degree).gt(x)) upper=guess; | |
| else lower=guess; | |
| var newguess=lower.add(upper).div(2); | |
| if (newguess.eq(guess)) break; | |
| guess=newguess; | |
| } | |
| return ExpantaNum.iteratedexp(10,layer,guess); | |
| }else{ | |
| var BIG=new ExpantaNum("10^^10"); | |
| var stage=1; | |
| var minimum=BIG; | |
| var maximum=BIG; | |
| var lower=BIG | |
| var upper=new ExpantaNum(1e-16) | |
| var prevspan=ExpantaNum.ZERO; | |
| var difference=BIG; | |
| var upperBound=ExpantaNum.pow(10,upper).rec(); | |
| var distance=ExpantaNum.ZERO; | |
| var prevPoint=upperBound; | |
| var nextPoint=upperBound; | |
| var evenDegree=Math.ceil(degreeNum)%2==0; | |
| var range=0; | |
| var lastValid=BIG; | |
| var infLoopDetector=false; | |
| var previousUpper=ExpantaNum.ZERO; | |
| var decreasingFound=false; | |
| while (stage<4){ | |
| if (stage==2){ | |
| if (evenDegree) break; | |
| lower=BIG; | |
| upper=minimum; | |
| stage=3; | |
| difference=BIG; | |
| lastValid=BIG; | |
| } | |
| infLoopDetector=false; | |
| while (upper.neq(lower)){ | |
| previousUpper=upper; | |
| var up10r=ExpantaNum.pow(10,upper).rec(); | |
| var up10rtd=up10r.tetr(degree); | |
| if (up10rtd.eq(ExpantaNum.ONE)&&up10r.lt(0.4)){ | |
| upperBound=up10r; | |
| prevPoint=up10r; | |
| nextPoint=up10r; | |
| distance=ExpantaNum.ZERO; | |
| range=-1; | |
| if (stage==3) lastValid=upper; | |
| }else if (up10rtd.eq(up10r)&&!evenDegree&&up10r.lt(0.4)){ | |
| upperBound=up10r; | |
| prevPoint=up10r; | |
| nextPoint=up10r; | |
| distance=ExpantaNum.ZERO; | |
| range=0; | |
| }else if (up10rtd.eq(up10r.mul(2).tetr(degree))){ | |
| upperBound=up10r; | |
| prevPoint=ExpantaNum.ZERO; | |
| nextPoint=upperBound.mul(2); | |
| distance=upperBound; | |
| if (evenDegree) range=-1; | |
| else range=0; | |
| }else{ | |
| prevspan=upper.mul(1.2e-16); | |
| upperBound=up10r; | |
| prevPoint=ExpantaNum.pow(10,upper.add(prevspan)).rec(); | |
| distance=upperBound.sub(prevPoint); | |
| nextPoint=upperBound.add(distance); | |
| var ubtd=upperBound.tetr(degree); //upperBound does not change during lifetime | |
| var pptd; | |
| var nptd; | |
| while (prevPoint.gte(upperBound)||nextPoint.lte(upperBound)||(pptd=prevPoint.tetr(degree)).eq(ubtd)||(nptd=nextPoint.tetr(degree)).eq(ubtd)){ | |
| prevspan=prevspan.mul(2); | |
| prevPoint=ExpantaNum.pow(10,upper.add(prevspan)).rec(); | |
| distance=upperBound.sub(prevPoint); | |
| nextPoint=upperBound.add(distance); | |
| } | |
| //pptd and nptd are up-to-date | |
| if (stage==1&&nptd.gt(ubtd)&&pptd.gt(ubtd)||stage==3&&nptd.lt(ubtd)&&pptd.lt(ubtd)) lastValid=upper; | |
| if (nptd.lt(ubtd)) range=-1; | |
| else if (evenDegree) range=1; | |
| else if (stage==3&&upper.gt_tolerance(minimum,1e-8)) range=0; | |
| else{ | |
| while (prevPoint.gte(upperBound)||nextPoint.lte(upperBound)||(pptd=prevPoint.tetr(degree)).eq_tolerance(ubtd,1e-8)||(nptd=nextPoint.tetr(degree)).eq_tolerance(ubtd,1e-8)){ | |
| prevspan=prevspan.mul(2); | |
| prevPoint=ExpantaNum.pow(10,upper.add(prevspan)).rec(); | |
| distance=upperBound.sub(prevPoint); | |
| nextPoint=upperBound.add(distance); | |
| } | |
| //pptd and nptd are up-to-date | |
| if (nptd.sub(ubtd).lt(ubtd.sub(pptd))) range=0; | |
| else range=1; | |
| } | |
| } | |
| if (range==-1) decreasingFound=true; | |
| if (stage==1&&range==1||stage==3&&range!=0){ | |
| if (lower.eq(BIG)) upper=upper.mul(2); | |
| else{ | |
| upper=upper.add(lower).div(2); | |
| if (infLoopDetector&&(range==1&&stage==1||range==-1&&stage==3)) break; | |
| } | |
| }else{ | |
| if (lower.eq(BIG)){ | |
| lower=upper; | |
| upper=upper.div(2); | |
| }else{ | |
| lower=lower.sub(difference); | |
| upper=upper.sub(difference); | |
| if (infLoopDetector&&(range==1&&stage==1||range==-1&&stage==3)) break; | |
| } | |
| } | |
| var newDifference=lower.sub(upper).div(2).abs(); | |
| if (newDifference.gt(difference.mul(1.5))) infLoopDetector=true; | |
| difference=newDifference; | |
| if (upper.gt(1e18)||upper.eq(previousUpper)) break; | |
| } | |
| if (upper.gt(1e18)) break; | |
| if (!decreasingFound) break; | |
| if (lastValid.eq(BIG)) break; | |
| if (stage==1) minimum=lastValid; | |
| else if (stage==3) maximum=lastValid; | |
| stage++; | |
| } | |
| lower=minimum; | |
| upper=new ExpantaNum(1e-18); | |
| var previous=upper; | |
| var guess=ExpantaNum.ZERO; | |
| var loopGoing=true; | |
| while (loopGoing){ | |
| if (lower.eq(BIG)) guess=upper.mul(2); | |
| else guess=lower.add(upper).div(2); | |
| if (ExpantaNum.pow(10,guess).rec().tetr(degree).gt(x)) upper=guess; | |
| else lower=guess; | |
| if (guess.eq(previous)) loopGoing=false; | |
| else previous=guess; | |
| if (upper.gt(1e18)) return ExpantaNum.NaN.clone(); | |
| } | |
| if (guess.neq_tolerance(minimum,1e-15)) return ExpantaNum.pow(10,guess).rec(); | |
| else{ | |
| if (maximum.eq(BIG)) return ExpantaNum.NaN.clone(); | |
| lower=BIG; | |
| upper=maximum; | |
| previous=upper; | |
| guess=ExpantaNum.ZERO; | |
| var loopGoing=true; | |
| while (loopGoing){ | |
| if (lower.eq(BIG)) guess=upper.mul(2); | |
| else guess=lower.add(upper).div(2); | |
| if (ExpantaNum.pow(10,guess).rec().tetr(degree).gt(x)) upper=guess; | |
| else lower=guess; | |
| if (guess.eq(previous)) loopGoing=false; | |
| else previous=guess; | |
| if (upper.gt(1e18)) return ExpantaNum.NaN.clone(); | |
| } | |
| return ExpantaNum.pow(10,guess).rec(); | |
| } | |
| } | |
| }; | |
| Q.linear_sroot=function (x,y){ | |
| return new ExpantaNum(x).linear_sroot(y); | |
| }; | |
| //Super-logarithm, one of tetration's inverses, tells you what size power tower you'd have to tetrate base to to get number. By definition, will never be higher than 1.8e308 in break_eternity.js, since a power tower 1.8e308 numbers tall is the largest representable number. | |
| //Uses linear approximation | |
| //https://en.wikipedia.org/wiki/Super-logarithm | |
| P.slog=function (base){ | |
| if (base===undefined) base=10; | |
| var x=this.clone(); | |
| base=new ExpantaNum(base); | |
| if (x.isNaN()||base.isNaN()||x.isInfinite()&&base.isInfinite()) return ExpantaNum.NaN.clone(); | |
| if (x.isInfinite()) return x; | |
| if (base.isInfinite()) return ExpantaNum.ZERO.clone(); | |
| if (x.eq(ExpantaNum.ZERO)) return ExpantaNum.ONE.neg(); | |
| if (x.eq(ExpantaNum.ONE)) return ExpantaNum.ZERO.clone(); | |
| if (x.eq(base)) return ExpantaNum.ONE.clone(); | |
| if (base.lt(Math.exp(1/Math.E))){ | |
| var a=ExpantaNum.tetr(base,Infinity); | |
| if (x.eq(a)) return ExpantaNum.POSITIVE_INFINITY.clone(); | |
| if (x.gt(a)) return ExpantaNum.NaN.clone(); | |
| } | |
| if (x.max(base).gt("10^^^"+MAX_SAFE_INTEGER)){ | |
| if (x.gt(base)) return x; | |
| return ExpantaNum.ZERO.clone(); | |
| } | |
| if (x.max(base).gt(ExpantaNum.TETRATED_MAX_SAFE_INTEGER)){ | |
| if (x.gt(base)){ | |
| x.operator(2,x.operator(2)-1); | |
| x.normalize(); | |
| return x.sub(x.operator(1)); | |
| } | |
| return ExpantaNum.ZERO.clone(); | |
| } | |
| if (x.lt(ExpantaNum.ZERO)) return base.pow(x).sub(2); //Inversion of x^^y=log_x(2+y) for -2<y<=-1 | |
| var r=0; | |
| var t=(x.operator(1)||0)-(base.operator(1)||0); | |
| if (t>3){ | |
| var l=t-3; | |
| r+=l; | |
| x.operator(1,x.operator(1)-l); | |
| } | |
| for (var i=0;i<100;++i){ | |
| if (x.lte(ExpantaNum.ONE)) return new ExpantaNum(r+x.toNumber()-1); | |
| ++r; | |
| x=ExpantaNum.logBase(x,base); | |
| } | |
| return ExpantaNum.NaN.clone(); //Failed to converge | |
| }; | |
| Q.slog=function (x,y){ | |
| return new ExpantaNum(x).slog(y); | |
| }; | |
| //end break_eternity.js excerpt | |
| P.pentate=P.pent=function (other){ | |
| return this.arrow(3)(other); | |
| }; | |
| Q.pentate=Q.pent=function (x,y){ | |
| return ExpantaNum.arrow(x,3,y); | |
| }; | |
| P.penta_log=function (other){ | |
| return this.arrow_height_inverse(3)(other); | |
| }; | |
| Q.penta_log=function (x,y){ | |
| return ExpantaNum.arrow_height_inverse(x,3,y); | |
| }; | |
| //Uses linear approximations for real height | |
| P.arrow=function (arrows){ | |
| var t=this.clone(); | |
| arrows=new ExpantaNum(arrows); | |
| if (!arrows.isint()||arrows.lt(ExpantaNum.ZERO)) return function(other){return ExpantaNum.NaN.clone();}; | |
| if (arrows.eq(ExpantaNum.ZERO)) return function(other){return t.mul(other);}; | |
| if (arrows.eq(ExpantaNum.ONE)) return function(other){return t.pow(other);}; | |
| if (arrows.eq(2)) return function(other,payload){return t.tetr(other,payload);}; | |
| return function (other,payload,depth){ | |
| if (payload===undefined) payload=ExpantaNum.ONE; | |
| if (depth===undefined) depth=0; | |
| other=new ExpantaNum(other); | |
| payload=new ExpantaNum(payload); | |
| if (t.isNaN()||other.isNaN()||payload.isNaN()) return ExpantaNum.NaN.clone(); | |
| if (payload.neq(ExpantaNum.ONE)) other=other.add(payload.arrow_height_inverse(arrows)(t)); | |
| if (ExpantaNum.debug>=ExpantaNum.NORMAL) console.log(t+"{"+arrows+"}"+other); | |
| if (t.eq(ExpantaNum.ZERO)){ | |
| if (other.eq(ExpantaNum.ONE)) return ExpantaNum.ZERO.clone(); | |
| return ExpantaNum.NaN.clone(); | |
| } | |
| if (t.eq(ExpantaNum.ONE)) return ExpantaNum.ONE.clone(); | |
| if (other.eq(ExpantaNum.ZERO)) return ExpantaNum.ONE.clone(); | |
| if (other.eq(ExpantaNum.ONE)) return t.clone(); | |
| //By induction: See initialization of r in the fallthrough branch | |
| if (other.gt(ExpantaNum.ZERO)&&other.lt(ExpantaNum.ONE)) return t.pow(other); | |
| if (other.gt(ExpantaNum.ONE)&&arrows.gt(ExpantaNum.MAX_SAFE_INTEGER)){ | |
| var r=arrows.clone(); | |
| r.layer++; | |
| return r; | |
| } | |
| var arrowsNum=arrows.toNumber(); | |
| if (other.eq(2)) return t.arrow(arrowsNum-1)(t,ExpantaNum.ONE,depth+1); | |
| if (t.max(other).gt("10{"+(arrowsNum+1)+"}"+MAX_SAFE_INTEGER)) return t.max(other); | |
| if (t.gt("10{"+arrowsNum+"}"+MAX_SAFE_INTEGER)||other.gt(ExpantaNum.MAX_SAFE_INTEGER)){ | |
| var r; | |
| if (t.gt("10{"+arrowsNum+"}"+MAX_SAFE_INTEGER)){ | |
| r=t.clone(); | |
| r.operator(arrowsNum,r.operator(arrowsNum)-1); | |
| r.normalize(); | |
| }else if (t.gt("10{"+(arrowsNum-1)+"}"+MAX_SAFE_INTEGER)){ | |
| r=new ExpantaNum(t.operator(arrowsNum-1)); | |
| }else{ | |
| r=ExpantaNum.ZERO; | |
| } | |
| var j=r.add(other); | |
| j.operator(arrowsNum,(j.operator(arrowsNum)||0)+1); | |
| j.normalize(); | |
| return j; | |
| } | |
| if (depth>=ExpantaNum.maxOps+10){ | |
| return new ExpantaNum([[0,10],[arrowsNum,1]]); | |
| } | |
| var y=other.toNumber(); | |
| var f=Math.floor(y); | |
| var arrows_m1=arrows.sub(ExpantaNum.ONE); | |
| var r=t.arrow(arrows_m1)(y-f,ExpantaNum.ONE,depth+1); | |
| var l=ExpantaNum.NaN; | |
| for (var i=0,m=new ExpantaNum("10{"+(arrowsNum-1)+"}"+MAX_SAFE_INTEGER);f!==0&&r.lt(m)&&i<100;++i){ | |
| if (f>0){ | |
| r=t.arrow(arrows_m1)(r,ExpantaNum.ONE,depth+1); | |
| if (l.eq(r)){ | |
| f=0; | |
| break; | |
| } | |
| l=r; | |
| --f; | |
| }else{ | |
| r=r.arrow_height_inverse(arrows_m1)(t); | |
| if (l.eq(r)){ | |
| f=0; | |
| break; | |
| } | |
| l=r; | |
| ++f; | |
| } | |
| } | |
| if (i==100) f=0; | |
| r.operator(arrowsNum-1,(r.operator(arrowsNum-1)+f)||f); | |
| r.normalize(); | |
| return r; | |
| }; | |
| }; | |
| P.chain=function (other,arrows){ | |
| return this.arrow(arrows)(other); | |
| }; | |
| Q.arrow=function (x,z,y,payload){ | |
| return new ExpantaNum(x).arrow(z)(y,payload); | |
| }; | |
| Q.chain=function (x,y,z){ | |
| return new ExpantaNum(x).arrow(z)(y); | |
| }; | |
| Q.hyper=function (z){ | |
| z=new ExpantaNum(z); | |
| if (z.eq(ExpantaNum.ZERO)) return function(x,y){return new ExpantaNum(y).eq(ExpantaNum.ZERO)?new ExpantaNum(x):new ExpantaNum(x).add(ExpantaNum.ONE);}; | |
| if (z.eq(ExpantaNum.ONE)) return function(x,y){return ExpantaNum.add(x,y);}; | |
| return function(x,y,payload){return new ExpantaNum(x).arrow(z.sub(2))(y,payload);}; | |
| }; | |
| //arrow_height_inverse{z}_x(x{z}y)=y | |
| //See also: https://github.com/Patashu/break_eternity.js/blob/848736e3dc37d8e7b5cc238f46e3ddb277d0dce2/src/index.ts#L4647 | |
| P.arrow_height_inverse=function (arrows){ | |
| var x=this.clone(); | |
| arrows=new ExpantaNum(arrows); | |
| if (!arrows.isint()||arrows.lt(ExpantaNum.ONE)) return function(other){return ExpantaNum.NaN.clone();}; | |
| if (arrows.eq(ExpantaNum.ONE)) return function(base){return x.logBase(base);}; | |
| if (arrows.eq(2)) return function(base){return x.slog(base);}; | |
| return function (base,depth){ | |
| if (base===undefined) base=10; | |
| if (depth===undefined) depth=0; | |
| base=new ExpantaNum(base); | |
| if (x.isNaN()||base.isNaN()||x.isInfinite()&&base.isInfinite()) return ExpantaNum.NaN.clone(); | |
| if (base.lte(ExpantaNum.ONE)) return ExpantaNum.NaN.clone(); | |
| if (x.isInfinite()) return x; | |
| if (base.isInfinite()) return ExpantaNum.ZERO.clone(); | |
| if (x.eq(ExpantaNum.ZERO)) return ExpantaNum.ONE.neg(); | |
| if (x.eq(ExpantaNum.ONE)) return ExpantaNum.ZERO.clone(); | |
| if (x.eq(base)) return ExpantaNum.ONE.clone(); | |
| //Inverse of shortcut for 0<other<1 in arrow | |
| if (x.gt(ExpantaNum.ONE)&&x.lt(base)) return x.logBase(base); | |
| if (x.gt(ExpantaNum.ONE)&&arrows.gt(ExpantaNum.MAX_SAFE_INTEGER)){ | |
| var twocmp=x.cmp(base.arrow(arrows)(base)); | |
| if (twocmp==0) return new ExpantaNum(2); | |
| if (twocmp>0) return x; | |
| return ExpantaNum.ONE.clone(); //base{arrows}(1+epsilon) explodes | |
| } | |
| var arrowsNum=arrows.toNumber(); | |
| if (arrowsNum==2&&x.lt(ExpantaNum.ONE.neg())){ | |
| if (x.lt(-2)) return ExpantaNum.NaN.clone(); | |
| var infrcmp=x.cmp(base.arrow(arrows.sub(ExpantaNum.ONE))(x)); | |
| if (infrcmp==0) return ExpantaNum.NEGATIVE_INFINITY.clone(); | |
| if (infrcmp>0) return ExpantaNum.NaN.clone(); | |
| } | |
| if (x.max(base).gt("10{"+(arrowsNum+1)+"}"+MAX_SAFE_INTEGER)){ | |
| if (x.gt(base)) return x; | |
| return ExpantaNum.ZERO.clone(); | |
| } | |
| if (x.max(base).gt("10{"+arrowsNum+"}"+MAX_SAFE_INTEGER)){ | |
| if (x.gt(base)){ | |
| x.operator(arrowsNum,x.operator(arrowsNum)-1); | |
| x.normalize(); | |
| return x.sub(x.operator(arrowsNum-1)); | |
| } | |
| return ExpantaNum.ZERO.clone(); | |
| } | |
| var r=0; | |
| var t=(x.operator(arrowsNum-1)||0)-(base.operator(arrowsNum-1)||0); | |
| if (depth>=ExpantaNum.maxOps+10) return new ExpantaNum(t); | |
| if (t>3){ | |
| var l=t-3; | |
| r+=l; | |
| x.operator(arrowsNum-1,x.operator(arrowsNum-1)-l); | |
| } | |
| var arrows_m1=arrows.sub(ExpantaNum.ONE); | |
| for (var i=0;i<100;++i){ | |
| if (x.lt(ExpantaNum.ZERO)){ | |
| x=base.arrow(arrows_m1)(x); | |
| --r; | |
| }else if (x.lte(ExpantaNum.ONE)){ | |
| return new ExpantaNum(r+x.toNumber()-1); | |
| }else{ | |
| ++r; | |
| x=x.arrow_height_inverse(arrows_m1)(base,depth+1); | |
| } | |
| } | |
| return ExpantaNum.NaN.clone(); //Failed to converge | |
| }; | |
| }; | |
| Q.arrow_height_inverse=function (x,z,y){ | |
| return new ExpantaNum(x).arrow_height_inverse(z)(y); | |
| } | |
| P.expansion=function (other){ | |
| var t=this.clone(); | |
| other=new ExpantaNum(other); | |
| var r; | |
| if (ExpantaNum.debug>=ExpantaNum.NORMAL) console.log("{"+t+","+other+",1,2}"); | |
| if (other.lte(ExpantaNum.ZERO)||!other.isint()) return ExpantaNum.NaN.clone(); | |
| if (other.eq(ExpantaNum.ONE)) return t.clone(); | |
| if (!t.isint()) return ExpantaNum.NaN.clone(); | |
| if (t.eq(2)) return new ExpantaNum(4); | |
| if (other.gt(ExpantaNum.MAX_SAFE_INTEGER)) return ExpantaNum.POSITIVE_INFINITY.clone(); | |
| var f=other.toNumber()-1; | |
| r=t; | |
| for (var i=0;f!==0&&r.lt(ExpantaNum.MAX_SAFE_INTEGER)&&i<100;++i){ | |
| if (f>0){ | |
| r=t.arrow(r)(t); | |
| --f; | |
| } | |
| } | |
| if (i==100) f=0; | |
| r.layer+=f; | |
| r.normalize(); | |
| return r; | |
| }; | |
| Q.expansion=function (x,y){ | |
| return new ExpantaNum(x).expansion(y); | |
| }; | |
| // All of these are from Patashu's break_eternity.js | |
| Q.affordGeometricSeries = function (resourcesAvailable, priceStart, priceRatio, currentOwned) { | |
| /* | |
| If you have resourcesAvailable, the price of something starts at | |
| priceStart, and on each purchase it gets multiplied by priceRatio, | |
| and you have already bought currentOwned, how many of the object | |
| can you buy. | |
| */ | |
| resourcesAvailable=new ExpantaNum(resourcesAvailable); | |
| priceStart=new ExpantaNum(priceStart); | |
| priceRatio=new ExpantaNum(priceRatio); | |
| var actualStart = priceStart.mul(priceRatio.pow(currentOwned)); | |
| return ExpantaNum.floor(resourcesAvailable.div(actualStart).mul(priceRatio.sub(ExpantaNum.ONE)).add(ExpantaNum.ONE).log10().div(priceRatio.log10())); | |
| }; | |
| Q.affordArithmeticSeries = function (resourcesAvailable, priceStart, priceAdd, currentOwned) { | |
| /* | |
| If you have resourcesAvailable, the price of something starts at | |
| priceStart, and on each purchase it gets increased by priceAdd, | |
| and you have already bought currentOwned, how many of the object | |
| can you buy. | |
| */ | |
| resourcesAvailable=new ExpantaNum(resourcesAvailable); | |
| priceStart=new ExpantaNum(priceStart); | |
| priceAdd=new ExpantaNum(priceAdd); | |
| currentOwned=new ExpantaNum(currentOwned); | |
| var actualStart = priceStart.add(currentOwned.mul(priceAdd)); | |
| var b = actualStart.sub(priceAdd.div(2)); | |
| var b2 = b.pow(2); | |
| return b.neg().add(b2.add(priceAdd.mul(resourcesAvailable).mul(2)).sqrt()).div(priceAdd).floor(); | |
| }; | |
| Q.sumGeometricSeries = function (numItems, priceStart, priceRatio, currentOwned) { | |
| /* | |
| If you want to buy numItems of something, the price of something starts at | |
| priceStart, and on each purchase it gets multiplied by priceRatio, | |
| and you have already bought currentOwned, what will be the price of numItems | |
| of something. | |
| */ | |
| priceStart=new ExpantaNum(priceStart); | |
| priceRatio=new ExpantaNum(priceRatio); | |
| return priceStart.mul(priceRatio.pow(currentOwned)).mul(ExpantaNum.sub(ExpantaNum.ONE, priceRatio.pow(numItems))).div(ExpantaNum.sub(ExpantaNum.ONE, priceRatio)); | |
| }; | |
| Q.sumArithmeticSeries = function (numItems, priceStart, priceAdd, currentOwned) { | |
| /* | |
| If you want to buy numItems of something, the price of something starts at | |
| priceStart, and on each purchase it gets increased by priceAdd, | |
| and you have already bought currentOwned, what will be the price of numItems | |
| of something. | |
| */ | |
| numItems=new ExpantaNum(numItems); | |
| priceStart=new ExpantaNum(priceStart); | |
| currentOwned=new ExpantaNum(currentOwned); | |
| var actualStart = priceStart.add(currentOwned.mul(priceAdd)); | |
| return numItems.div(2).mul(actualStart.mul(2).plus(numItems.sub(ExpantaNum.ONE).mul(priceAdd))); | |
| }; | |
| // Binomial Coefficients n choose k | |
| Q.choose = function (n, k) { | |
| /* | |
| If you have n items and you take k out, | |
| how many ways could you do this? | |
| */ | |
| return new ExpantaNum(n).factorial().div(new ExpantaNum(k).factorial().mul(new ExpantaNum(n).sub(new ExpantaNum(k)).factorial())); | |
| }; | |
| P.choose = function (other) { | |
| return ExpantaNum.choose(this, other); | |
| }; | |
| //end break_eternity.js excerpt | |
| P.normalize=function (){ | |
| var b; | |
| var x=this; | |
| if (ExpantaNum.debug>=ExpantaNum.ALL) console.log(x.toString()); | |
| if (!x.array||!x.array.length) x.array=[[0,0]]; | |
| if (x.sign!=1&&x.sign!=-1){ | |
| if (typeof x.sign!="number") x.sign=Number(x.sign); | |
| x.sign=x.sign<0?-1:1; | |
| } | |
| if (x.layer>MAX_SAFE_INTEGER){ | |
| x.array=[[0,Infinity]]; | |
| x.layer=0; | |
| return x; | |
| } | |
| if (Number.isInteger(x.layer)) x.layer=Math.floor(x.layer); | |
| for (var i=0;i<x.array.length;++i){ | |
| var e=x.array[i]; | |
| if (e[0]===null||e[0]===undefined){ | |
| e[0]=0; | |
| } | |
| if (e[0]!==0&&(e[1]===0||e[1]===null||e[1]===undefined)){ | |
| x.array.splice(i,1); | |
| --i; | |
| continue; | |
| } | |
| if (isNaN(e[0])||isNaN(e[1])){ | |
| x.array=[[0,NaN]]; | |
| return x; | |
| } | |
| if (!isFinite(e[0])||!isFinite(e[1])){ | |
| x.array=[[0,Infinity]]; | |
| return x; | |
| } | |
| if (!Number.isInteger(e[0])) e[0]=Math.floor(e[0]); | |
| if (e[0]!==0&&!Number.isInteger(e[1])) e[1]=Math.floor(e[1]); | |
| } | |
| do{ | |
| if (ExpantaNum.debug>=ExpantaNum.ALL) console.log(x.toString()); | |
| b=false; | |
| x.array.sort(function (a,b){return a[0]>b[0]?1:a[0]<b[0]?-1:0;}); | |
| if (x.array.length>ExpantaNum.maxOps) x.array.splice(0,x.array.length-ExpantaNum.maxOps); | |
| if (!x.array.length) x.array=[[0,0]]; | |
| if (x.array[x.array.length-1][0]>MAX_SAFE_INTEGER){ | |
| x.layer++; | |
| x.array=[[0,x.array[x.array.length-1][0]]]; | |
| b=true; | |
| }else if (x.layer&&x.array.length==1&&x.array[0][0]===0){ | |
| x.layer--; | |
| if (x.array[0][1]===0) x.array=[[0,10]]; | |
| else x.array=[[0,10],[Math.round(x.array[0][1]),1]]; | |
| b=true; | |
| } | |
| if (x.array.length<ExpantaNum.maxOps&&x.array[0][0]!==0) x.array.unshift([0,10]); | |
| for (i=0;i<x.array.length-1;++i){ | |
| if (x.array[i][0]==x.array[i+1][0]){ | |
| x.array[i][1]+=x.array[i+1][1]; | |
| x.array.splice(i+1,1); | |
| --i; | |
| b=true; | |
| } | |
| } | |
| if (x.array[0][0]===0&&x.array[0][1]>MAX_SAFE_INTEGER){ | |
| if (x.array.length>=2&&x.array[1][0]==1){ | |
| x.array[1][1]++; | |
| }else{ | |
| x.array.splice(1,0,[1,1]); | |
| } | |
| x.array[0][1]=Math.log10(x.array[0][1]); | |
| b=true; | |
| } | |
| while (x.array.length>=2&&x.array[0][0]===0&&x.array[0][1]<MAX_E&&x.array[1][0]==1&&x.array[1][1]){ | |
| x.array[0][1]=Math.pow(10,x.array[0][1]); | |
| if (x.array[1][1]>1){ | |
| x.array[1][1]--; | |
| }else{ | |
| x.array.splice(1,1); | |
| } | |
| b=true; | |
| } | |
| while (x.array.length>=2&&x.array[0][0]===0&&x.array[0][1]==1&&x.array[1][1]){ | |
| if (x.array[1][1]>1){ | |
| x.array[1][1]--; | |
| }else{ | |
| x.array.splice(1,1); | |
| } | |
| x.array[0][1]=10; | |
| } | |
| if (x.array.length>=2&&x.array[0][0]===0&&x.array[1][0]!=1){ | |
| var p=1; | |
| if (Math.floor(x.array[0][1])) x.array.splice(1,0,[x.array[1][0]-1,Math.floor(x.array[0][1])]),p++; | |
| x.array[0][1]=Math.pow(10,x.array[0][1]-Math.floor(x.array[0][1])); | |
| if (x.array[p][1]>1){ | |
| x.array[p][1]--; | |
| }else{ | |
| x.array.splice(p,1); | |
| } | |
| b=true; | |
| } | |
| for (i=0;i<x.array.length;++i){ | |
| if (x.array[i][1]>MAX_SAFE_INTEGER){ | |
| if (i!=x.array.length-1&&x.array[i+1][0]==x.array[i][0]+1){ | |
| x.array[i+1][1]++; | |
| }else{ | |
| x.array.splice(i+1,0,[x.array[i][0]+1,1]); | |
| } | |
| x.array.splice(0,i+1,[0,x.array[i][1]+1]); | |
| b=true; | |
| } | |
| } | |
| }while(b); | |
| if (!x.array.length) x.array=[[0,0]]; | |
| return x; | |
| }; | |
| var standardizeMessageSent=false; | |
| P.standardize=function (){ | |
| if (!standardizeMessageSent) console.warn(expantaNumError+"'standardize' method is being deprecated in favor of 'normalize' and will be removed in the future!"),standardizeMessageSent=true; | |
| return this.normalize(); | |
| } | |
| P.toNumber=function (){ | |
| //console.log(this.array); | |
| if (this.sign==-1) return -1*this.abs(); | |
| if (this.layer>0||this.array.length>=2&&(this.array[1][0]>=2||this.array[1][1]>=2||this.array[1][1]==1&&this.array[0][1]>Math.log10(Number.MAX_VALUE))) return Infinity; | |
| if (this.array.length>=2&&this.array[1][1]==1) return Math.pow(10,this.array[0][1]); | |
| return this.array[0][1]; | |
| }; | |
| P.toString=function (){ | |
| if (this.sign==-1) return "-"+this.abs(); | |
| if (isNaN(this.array[0][1])) return "NaN"; | |
| if (!isFinite(this.array[0][1])) return "Infinity"; | |
| var s=""; | |
| if (!this.layer) s+=""; | |
| else if (this.layer<3) s+="J".repeat(this.layer); | |
| else s+="J^"+this.layer+" "; | |
| if (this.array.length>=3||this.array.length==2&&this.array[1][0]>=2){ | |
| for (var i=this.array.length-1;i>=2;--i){ | |
| var e=this.array[i]; | |
| var q=e[0]>=5?"{"+e[0]+"}":"^".repeat(e[0]); | |
| if (e[1]>1) s+="(10"+q+")^"+e[1]+" "; | |
| else if (e[1]==1) s+="10"+q; | |
| } | |
| } | |
| var op0=this.operator(0); | |
| var op1=this.operator(1); | |
| if (!op1) s+=String(op0); | |
| else if (op1<3) s+="e".repeat(op1-1)+Math.pow(10,op0-Math.floor(op0))+"e"+Math.floor(op0); | |
| else if (op1<8) s+="e".repeat(op1)+op0; | |
| else s+="(10^)^"+op1+" "+op0; | |
| return s; | |
| }; | |
| //from break_eternity.js | |
| var decimalPlaces=function decimalPlaces(value,places){ | |
| var len=places+1; | |
| var numDigits=Math.ceil(Math.log10(Math.abs(value))); | |
| if (numDigits<100) numDigits=0; //A hack-y solution to https://github.com/Naruyoko/ExpantaNum.js/issues/22 | |
| var rounded=Math.round(value*Math.pow(10,len-numDigits))*Math.pow(10,numDigits-len); | |
| return parseFloat(rounded.toFixed(Math.max(len-numDigits,0))); | |
| }; | |
| P.toStringWithDecimalPlaces=function (places,applyToOpNums){ | |
| if (this.sign==-1) return "-"+this.abs(); | |
| if (isNaN(this.array[0][1])) return "NaN"; | |
| if (!isFinite(this.array[0][1])) return "Infinity"; | |
| var b=0; | |
| var s=""; | |
| var m=Math.pow(10,places); | |
| if (!this.layer) s+=""; | |
| else if (this.layer<3) s+="J".repeat(this.layer); | |
| else s+="J^"+this.layer+" "; | |
| if (this.array.length>=3||this.array.length==2&&this.array[1][0]>=2){ | |
| for (var i=this.array.length-1;!b&&i>=2;--i){ | |
| var e=this.array[i]; | |
| var w=e[0]; | |
| var x=e[1]; | |
| if (applyToOpNums&&x>=m){ | |
| ++w; | |
| b=x; | |
| x=1; | |
| }else if (applyToOpNums&&this.array[i-1][0]==w-1&&this.array[i-1][1]>=m){ | |
| ++x; | |
| b=this.array[i-1][1]; | |
| } | |
| var q=w>=5?"{"+w+"}":"^".repeat(w); | |
| if (x>1) s+="(10"+q+")^"+x+" "; | |
| else if (x==1) s+="10"+q; | |
| } | |
| } | |
| var k=this.operator(0); | |
| var l=this.operator(1); | |
| if (k>m){ | |
| k=Math.log10(k); | |
| ++l; | |
| } | |
| if (b) s+=decimalPlaces(b,places); | |
| else if (!l) s+=String(decimalPlaces(k,places)); | |
| else if (l<3) s+="e".repeat(l-1)+decimalPlaces(Math.pow(10,k-Math.floor(k)),places)+"e"+decimalPlaces(Math.floor(k),places); | |
| else if (l<8) s+="e".repeat(l)+decimalPlaces(k,places); | |
| else if (applyToOpNums) s+="(10^)^"+decimalPlaces(l,places)+" "+decimalPlaces(k,places); | |
| else s+="(10^)^"+l+" "+decimalPlaces(k,places); | |
| return s; | |
| }; | |
| //these are from break_eternity.js as well | |
| P.toExponential=function (places,applyToOpNums){ | |
| if (this.array.length==1) return (this.sign*this.array[0][1]).toExponential(places); | |
| return this.toStringWithDecimalPlaces(places,applyToOpNums); | |
| }; | |
| P.toFixed=function (places,applyToOpNums){ | |
| if (this.array.length==1) return (this.sign*this.array[0][1]).toFixed(places); | |
| return this.toStringWithDecimalPlaces(places,applyToOpNums); | |
| }; | |
| P.toPrecision=function (places,applyToOpNums){ | |
| if (this.array[0][1]===0) return (this.sign*this.array[0][1]).toFixed(places-1,applyToOpNums); | |
| if (this.array.length==1&&this.array[0][1]<1e-6) return this.toExponential(places-1,applyToOpNums); | |
| if (this.array.length==1&&places>Math.log10(this.array[0][1])) return this.toFixed(places-Math.floor(Math.log10(this.array[0][1]))-1,applyToOpNums); | |
| return this.toExponential(places-1,applyToOpNums); | |
| }; | |
| P.valueOf=function (){ | |
| return this.toString(); | |
| }; | |
| //Note: toArray() would be impossible without changing the layout of the array or lose the information about the sign | |
| P.toJSON=function (){ | |
| if (ExpantaNum.serializeMode==ExpantaNum.JSON){ | |
| var a=[]; | |
| for (var i=0;i<this.array.length;++i) a.push([this.array[i][0],this.array[i][1]]); | |
| return { | |
| array:a, | |
| layer:this.layer, | |
| sign:this.sign | |
| }; | |
| }else if (ExpantaNum.serializeMode==ExpantaNum.STRING){ | |
| return this.toString(); | |
| } | |
| }; | |
| P.toHyperE=function (){ | |
| if (this.layer) throw Error(expantaNumError+"Sorry, but this prototype doesn't support correct Hyper-E notation for numbers larger than 10{MSI}10"); | |
| if (this.sign==-1) return "-"+this.abs().toHyperE(); | |
| if (isNaN(this.array[0][1])) return "NaN"; | |
| if (!isFinite(this.array[0][1])) return "Infinity"; | |
| if (this.lt(ExpantaNum.MAX_SAFE_INTEGER)) return String(this.array[0][1]); | |
| if (this.lt(ExpantaNum.E_MAX_SAFE_INTEGER)) return "E"+this.array[0][1]; | |
| var r="E"+this.operator(0)+"#"+this.operator(1); | |
| var l=1; | |
| for (var i=Math.ceil(this.getOperatorIndex(2));i<this.array.length;++i){ | |
| if (l+1<this.array[i][0]) r+="#1".repeat(this.array[i][0]-l-1); | |
| l=this.array[i][0]; | |
| r+="#"+(this.array[i][1]+1); | |
| } | |
| if (!this.layer) r=""+r; | |
| else if (this.layer<3) r="J".repeat(this.layer)+r; | |
| else r="J^"+this.layer+" "+r; | |
| return r; | |
| }; | |
| Q.fromNumber=function (input){ | |
| if (typeof input!="number") throw Error(invalidArgument+"Expected Number"); | |
| var x=new ExpantaNum(); | |
| x.array[0][1]=Math.abs(input); | |
| x.sign=input<0?-1:1; | |
| x.normalize(); | |
| return x; | |
| }; | |
| var log10PosBigInt=function log10PosBigInt(input){ | |
| var exp=BigInt(64); | |
| while (input>=BigInt(1)<<exp) exp*=BigInt(2); | |
| var expdel=exp/BigInt(2); | |
| while (expdel>BigInt(0)){ | |
| if (input>=BigInt(1)<<exp) exp+=expdel; | |
| else exp-=expdel; | |
| expdel/=BigInt(2); | |
| } | |
| var cutbits=exp-BigInt(54); | |
| var firstbits=input>>cutbits; | |
| return Math.log10(Number(firstbits))+Math.LOG10E/Math.LOG2E*Number(cutbits); | |
| } | |
| Q.fromBigInt=function (input){ | |
| if (typeof input!="bigint") throw Error(invalidArgument+"Expected BigInt"); | |
| var x=new ExpantaNum(); | |
| var abs=input<BigInt(0)?-input:input; | |
| x.sign=input<BigInt(0)?-1:1; | |
| if (abs<=MAX_SAFE_INTEGER) x.array[0][1]=Number(abs); | |
| else x.array=[[0,log10PosBigInt(abs)],[1,1]]; | |
| x.normalize(); | |
| return x; | |
| } | |
| var LONG_STRING_MIN_LENGTH=17; | |
| var log10LongString=function log10LongString(str){ | |
| return Math.log10(Number(str.substring(0,LONG_STRING_MIN_LENGTH)))+(str.length-LONG_STRING_MIN_LENGTH); | |
| } | |
| Q.fromString=function (input){ | |
| if (typeof input!="string") throw Error(invalidArgument+"Expected String"); | |
| var isJSON=false; | |
| if (typeof input=="string"&&(input[0]=="["||input[0]=="{")){ | |
| try { | |
| JSON.parse(input); | |
| } catch {} finally { | |
| isJSON=true; | |
| } | |
| } | |
| if (isJSON){ | |
| return ExpantaNum.fromJSON(input); | |
| } | |
| var x=new ExpantaNum(); | |
| x.array=[[0,0]]; | |
| if (!isExpantaNum.test(input)){ | |
| console.warn(expantaNumError+"Malformed input: "+input); | |
| x.array=[[0,NaN]]; | |
| return x; | |
| } | |
| var negateIt=false; | |
| if (input[0]=="-"||input[0]=="+"){ | |
| var numSigns=input.search(/[^-\+]/); | |
| var signs=input.substring(0,numSigns); | |
| negateIt=signs.match(/-/g).length%2==1; | |
| input=input.substring(numSigns); | |
| } | |
| if (input=="NaN") x.array=[[0,NaN]]; | |
| else if (input=="Infinity") x.array=[[0,Infinity]]; | |
| else{ | |
| var a,b,c,d,i; | |
| if (input[0]=="J"){ | |
| if (input[1]=="^"){ | |
| a=input.substring(2).search(/[^0-9]/)+2; | |
| x.layer=Number(input.substring(2,a)); | |
| input=input.substring(a+1); | |
| }else{ | |
| a=input.search(/[^J]/); | |
| x.layer=a; | |
| input=input.substring(a); | |
| } | |
| } | |
| while (input){ | |
| if (/^\(?10[\^\{]/.test(input)){ | |
| if (input[0]=="("){ | |
| input=input.substring(1); | |
| } | |
| var arrows; | |
| if (input[2]=="^"){ | |
| a=input.substring(2).search(/[^\^]/); | |
| arrows=a; | |
| b=a+2; | |
| }else{ | |
| a=input.indexOf("}"); | |
| arrows=Number(input.substring(3,a)); | |
| b=a+1; | |
| } | |
| input=input.substring(b); | |
| if (input[0]==")"){ | |
| a=input.indexOf(" "); | |
| c=Number(input.substring(2,a)); | |
| input=input.substring(a+1); | |
| }else{ | |
| c=1; | |
| } | |
| if (arrows==1){ | |
| if (x.array.length>=2&&x.array[1][0]==1){ | |
| x.array[1][1]+=c; | |
| }else{ | |
| x.array.splice(1,0,[1,c]); | |
| } | |
| }else if (arrows==2){ | |
| a=x.array.length>=2&&x.array[1][0]==1?x.array[1][1]:0; | |
| b=x.array[0][1]; | |
| if (b>=1e10) ++a; | |
| if (b>=10) ++a; | |
| x.array[0][1]=a; | |
| if (x.array.length>=2&&x.array[1][0]==1) x.array.splice(1,1); | |
| d=x.getOperatorIndex(2); | |
| if (Number.isInteger(d)) x.array[d][1]+=c; | |
| else x.array.splice(Math.ceil(d),0,[2,c]); | |
| }else{ | |
| a=x.operator(arrows-1); | |
| b=x.operator(arrows-2); | |
| if (b>=10) ++a; | |
| d=x.getOperatorIndex(arrows); | |
| x.array.splice(1,Math.ceil(d)-1); | |
| x.array[0][1]=a; | |
| if (Number.isInteger(d)) x.array[1][1]+=c; | |
| else x.array.splice(1,0,[arrows,c]); | |
| } | |
| }else{ | |
| break; | |
| } | |
| } | |
| a=input.split(/[Ee]/); | |
| b=[x.array[0][1],0]; | |
| c=1; | |
| for (i=a.length-1;i>=0;--i){ | |
| //The things that are already there | |
| if (b[0]<MAX_E&&b[1]===0){ | |
| b[0]=Math.pow(10,c*b[0]); | |
| }else if (c==-1){ | |
| if (b[1]===0){ | |
| b[0]=Math.pow(10,c*b[0]); | |
| }else if (b[1]==1&&b[0]<=Math.log10(Number.MAX_VALUE)){ | |
| b[0]=Math.pow(10,c*Math.pow(10,b[0])); | |
| }else{ | |
| b[0]=0; | |
| } | |
| b[1]=0; | |
| }else{ | |
| b[1]++; | |
| } | |
| //Multiplying coefficient | |
| var decimalPointPos=a[i].indexOf("."); | |
| var intPartLen=decimalPointPos==-1?a[i].length:decimalPointPos; | |
| if (b[1]===0){ | |
| if (intPartLen>=LONG_STRING_MIN_LENGTH) b[0]=Math.log10(b[0])+log10LongString(a[i].substring(0,intPartLen)),b[1]=1; | |
| else if (a[i]) b[0]*=Number(a[i]); | |
| }else{ | |
| d=intPartLen>=LONG_STRING_MIN_LENGTH?log10LongString(a[i].substring(0,intPartLen)):a[i]?Math.log10(Number(a[i])):0; | |
| if (b[1]==1){ | |
| b[0]+=d; | |
| }else if (b[1]==2&&b[0]<MAX_E+Math.log10(d)){ | |
| b[0]+=Math.log10(1+Math.pow(10,Math.log10(d)-b[0])); | |
| } | |
| } | |
| //Carrying | |
| if (b[0]<MAX_E&&b[1]){ | |
| b[0]=Math.pow(10,b[0]); | |
| b[1]--; | |
| }else if (b[0]>MAX_SAFE_INTEGER){ | |
| b[0]=Math.log10(b[0]); | |
| b[1]++; | |
| } | |
| } | |
| x.array[0][1]=b[0]; | |
| if (b[1]){ | |
| if (x.array.length>=2&&x.array[1][0]==1) x.array[1][1]+=b[1]; | |
| else x.array.splice(1,0,[1,b[1]]); | |
| } | |
| } | |
| if (negateIt) x.sign*=-1; | |
| x.normalize(); | |
| return x; | |
| }; | |
| Q.fromArray=function (input1,input2,input3){ | |
| var array,layer,sign; | |
| if (input1 instanceof Array&&(input2===undefined||typeof input2=="number")&&(input3===undefined||typeof input3=="number")){ | |
| array=input1; | |
| sign=input2; | |
| layer=input3||0; | |
| }else if (typeof input1=="number"&&input2 instanceof Array&&(input3===undefined||typeof input3=="number")){ | |
| array=input2; | |
| sign=input1; | |
| layer=input3||0; | |
| }else if (typeof input1=="number"&&typeof input2=="number"&&input3 instanceof Array){ | |
| array=input3; | |
| sign=input1; | |
| layer=input2; | |
| }else{ | |
| throw Error(invalidArgument+"Expected an Array [and 1 or 2 Number]"); | |
| } | |
| var x=new ExpantaNum(); | |
| var i; | |
| if (!array.length) x.array=[[0,0]]; | |
| else if (typeof array[0]=="number"){ | |
| x.array=[]; | |
| for (i=0;i<array.length;i++){ | |
| if (typeof array[i]!="number") throw Error(invalidArgument+"Expected Array of Number"); | |
| x.array.push([i,array[i]]); | |
| } | |
| }else if (array[0] instanceof Array){ | |
| x.array=[]; | |
| for (i=0;i<array.length;i++){ | |
| if (!(array[i] instanceof Array)||typeof array[i][0]!="number"||typeof array[i][1]!="number") throw Error(invalidArgument+"Expected Array of pair of Number"); | |
| x.array.push([array[i][0],array[i][1]]); | |
| } | |
| }else throw Error(invalidArgument+"Expected Array of Number or Array of pair of Number"); | |
| if (sign) x.sign=Number(sign); | |
| else x.sign=1; | |
| x.normalize(); | |
| return x; | |
| }; | |
| Q.fromObject=function (input){ | |
| if (typeof input!="object") return ExpantaNum.ZERO.clone(); | |
| if (input===null) return ExpantaNum.ZERO.clone(); | |
| if (input instanceof Array) return ExpantaNum.fromArray(input); | |
| if (input instanceof ExpantaNum) return new ExpantaNum(input); | |
| if (!(input.array instanceof Array)) throw Error(invalidArgument+"Expected that property 'array' exists"); | |
| if (input.sign!==undefined&&typeof input.sign!="number") throw Error(invalidArgument+"Expected that property 'sign' is Number"); | |
| if (input.layer!==undefined&&typeof input.layer!="number") throw Error(invalidArgument+"Expected that property 'layer' is Number"); | |
| return ExpantaNum.fromArray(input.array,input.sign,input.layer); | |
| /*var x=new ExpantaNum(); | |
| x.array=[]; | |
| for (var i=0;i<input.array.length;i++) x.array.push([input.array[i][0],input.array[i][1]]); | |
| x.sign=Number(input.sign)||1; | |
| x.layer=Number(input.layer)||0; | |
| x.normalize(); | |
| return x;*/ | |
| }; | |
| Q.fromJSON=function (input){ | |
| if (typeof input=="object") return ExpantaNum.fromObject(parsedObject); | |
| if (typeof input!="string") throw Error(invalidArgument+"Expected String"); | |
| var parsedObject,x; | |
| try{ | |
| parsedObject=JSON.parse(input); | |
| }catch(e){ | |
| parsedObject=null; | |
| throw e; | |
| }finally{ | |
| x=ExpantaNum.fromObject(parsedObject); | |
| } | |
| parsedObject=null; | |
| return x; | |
| }; | |
| Q.fromHyperE=function (input){ | |
| if (typeof input!="string") throw Error(invalidArgument+"Expected String"); | |
| var x=new ExpantaNum(); | |
| x.array=[[0,0]]; | |
| if (!/^[-\+]*(0|[1-9]\d*(\.\d*)?|Infinity|NaN|E[1-9]\d*(\.\d*)?(#[1-9]\d*)*)$/.test(input)){ | |
| console.warn(expantaNumError+"Malformed input: "+input); | |
| x.array=[[0,NaN]]; | |
| return x; | |
| } | |
| var negateIt=false; | |
| if (input[0]=="-"||input[0]=="+"){ | |
| var numSigns=input.search(/[^-\+]/); | |
| var signs=input.substring(0,numSigns); | |
| negateIt=signs.match(/-/g).length%2===0; | |
| input=input.substring(numSigns); | |
| } | |
| if (input=="NaN") x.array=[[0,NaN]]; | |
| else if (input=="Infinity") x.array=[[0,Infinity]]; | |
| else if (input[0]!="E"){ | |
| x.array[0][1]=Number(input); | |
| }else if (input.indexOf("#")==-1){ | |
| x.array[0][1]=Number(input.substring(1)); | |
| x.array[1]=[1,1]; | |
| }else{ | |
| var array=input.substring(1).split("#"); | |
| for (var i=0;i<array.length;++i){ | |
| var t=Number(array[i]); | |
| if (i>=2){ | |
| --t; | |
| } | |
| x.array[i]=[i,t]; | |
| } | |
| } | |
| if (negateIt) x.sign*=-1; | |
| x.normalize(); | |
| return x; | |
| }; | |
| P.getOperatorIndex=function (i){ | |
| if (typeof i!="number") i=Number(i); | |
| if (!isFinite(i)) throw Error(invalidArgument+"Index out of range."); | |
| var a=this.array; | |
| var min=0,max=a.length-1; | |
| if (a[max][0]<i) return max+0.5; | |
| if (a[min][0]>i) return -0.5; | |
| while (min!=max){ | |
| if (a[min][0]==i) return min; | |
| if (a[max][0]==i) return max; | |
| var mid=Math.floor((min+max)/2); | |
| if (min==mid||a[mid][0]==i){ | |
| min=mid; | |
| break; | |
| } | |
| if (a[mid][0]<i) min=mid; | |
| if (a[mid][0]>i) max=mid; | |
| } | |
| return a[min][0]==i?min:min+0.5; | |
| }; | |
| P.getOperator=function (i){ | |
| if (typeof i!="number") i=Number(i); | |
| if (!isFinite(i)) throw Error(invalidArgument+"Index out of range."); | |
| var ai=this.getOperatorIndex(i); | |
| if (Number.isInteger(ai)) return this.array[ai][1]; | |
| else return i===0?10:0; | |
| }; | |
| P.setOperator=function (i,value){ | |
| if (typeof i!="number") i=Number(i); | |
| if (!isFinite(i)) throw Error(invalidArgument+"Index out of range."); | |
| var ai=this.getOperatorIndex(i); | |
| if (Number.isInteger(ai)) this.array[ai][1]=value; | |
| else{ | |
| ai=Math.ceil(ai); | |
| this.array.splice(ai,0,[i,value]); | |
| } | |
| this.normalize(); | |
| }; | |
| P.operator=function (i,value){ | |
| if (value===undefined) return this.getOperator(i); | |
| else this.setOperator(i,value); | |
| }; | |
| P.clone=function (){ | |
| var temp=new ExpantaNum(); | |
| var array=[]; | |
| for (var i=0;i<this.array.length;++i) array.push([this.array[i][0],this.array[i][1]]); | |
| temp.array=array; | |
| temp.sign=this.sign; | |
| temp.layer=this.layer; | |
| return temp; | |
| }; | |
| // ExpantaNum methods | |
| /* | |
| * clone | |
| * config/set | |
| */ | |
| /* | |
| * Create and return a ExpantaNum constructor with the same configuration properties as this ExpantaNum constructor. | |
| * | |
| */ | |
| function clone(obj) { | |
| var i, p, ps; | |
| function ExpantaNum(input,input2) { | |
| var x=this; | |
| if (!(x instanceof ExpantaNum)) return new ExpantaNum(input,input2); | |
| x.constructor=ExpantaNum; | |
| var parsedObject=null; | |
| if (typeof input=="string"&&(input[0]=="["||input[0]=="{")){ | |
| try { | |
| parsedObject=JSON.parse(input); | |
| }catch(e){ | |
| //lol just keep going | |
| } | |
| } | |
| var temp,temp2,temp3; | |
| if (typeof input=="number"&&!(input2 instanceof Array)){ | |
| temp=ExpantaNum.fromNumber(input); | |
| }else if (typeof input=="bigint"){ | |
| temp=ExpantaNum.fromBigInt(input); | |
| }else if (parsedObject){ | |
| temp=ExpantaNum.fromObject(parsedObject); | |
| }else if (typeof input=="string"&&input[0]=="E"){ | |
| temp=ExpantaNum.fromHyperE(input); | |
| }else if (typeof input=="string"){ | |
| temp=ExpantaNum.fromString(input); | |
| }else if (input instanceof Array||input2 instanceof Array){ | |
| temp=ExpantaNum.fromArray(input,input2); | |
| }else if (input instanceof ExpantaNum){ | |
| temp=[]; | |
| for (var i=0;i<input.array.length;++i) temp.push([input.array[i][0],input.array[i][1]]); | |
| temp2=input.sign; | |
| temp3=input.layer; | |
| }else if (typeof input=="object"){ | |
| temp=ExpantaNum.fromObject(input); | |
| }else{ | |
| temp=[[0,NaN]]; | |
| temp2=1; | |
| temp3=0; | |
| } | |
| if (typeof temp2=="undefined"){ | |
| x.array=temp.array; | |
| x.sign=temp.sign; | |
| x.layer=temp.layer; | |
| }else{ | |
| x.array=temp; | |
| x.sign=temp2; | |
| x.layer=temp3; | |
| } | |
| return x; | |
| } | |
| ExpantaNum.prototype = P; | |
| ExpantaNum.JSON = 0; | |
| ExpantaNum.STRING = 1; | |
| ExpantaNum.NONE = 0; | |
| ExpantaNum.NORMAL = 1; | |
| ExpantaNum.ALL = 2; | |
| ExpantaNum.clone=clone; | |
| ExpantaNum.config=ExpantaNum.set=config; | |
| //ExpantaNum=Object.assign(ExpantaNum,Q); | |
| for (var prop in Q){ | |
| if (Q.hasOwnProperty(prop)){ | |
| ExpantaNum[prop]=Q[prop]; | |
| } | |
| } | |
| if (obj === void 0) obj = {}; | |
| if (obj) { | |
| ps = ['maxOps', 'serializeMode', 'debug']; | |
| for (i = 0; i < ps.length;) if (!obj.hasOwnProperty(p = ps[i++])) obj[p] = this[p]; | |
| } | |
| ExpantaNum.config(obj); | |
| return ExpantaNum; | |
| } | |
| function defineConstants(obj){ | |
| for (var prop in R){ | |
| if (R.hasOwnProperty(prop)){ | |
| if (Object.defineProperty){ | |
| Object.defineProperty(obj,prop,{ | |
| configurable: false, | |
| enumerable: true, | |
| writable: false, | |
| value: new ExpantaNum(R[prop]) | |
| }); | |
| }else{ | |
| obj[prop]=new ExpantaNum(R[prop]); | |
| } | |
| } | |
| } | |
| return obj; | |
| } | |
| /* | |
| * Configure global settings for a ExpantaNum constructor. | |
| * | |
| * `obj` is an object with one or more of the following properties, | |
| * | |
| * precision {number} | |
| * rounding {number} | |
| * toExpNeg {number} | |
| * toExpPos {number} | |
| * | |
| * E.g. ExpantaNum.config({ precision: 20, rounding: 4 }) | |
| * | |
| */ | |
| function config(obj){ | |
| if (!obj||typeof obj!=='object') { | |
| throw Error(expantaNumError+'Object expected'); | |
| } | |
| var i,p,v, | |
| ps = [ | |
| 'maxOps',1,Number.MAX_SAFE_INTEGER, | |
| 'serializeMode',0,1, | |
| 'debug',0,2 | |
| ]; | |
| for (i = 0; i < ps.length; i += 3) { | |
| if ((v = obj[p = ps[i]]) !== void 0) { | |
| if (Math.floor(v) === v && v >= ps[i + 1] && v <= ps[i + 2]) this[p] = v; | |
| else throw Error(invalidArgument + p + ': ' + v); | |
| } | |
| } | |
| return this; | |
| } | |
| // Create and configure initial ExpantaNum constructor. | |
| ExpantaNum=clone(ExpantaNum); | |
| ExpantaNum=defineConstants(ExpantaNum); | |
| ExpantaNum['default']=ExpantaNum.ExpantaNum=ExpantaNum; | |
| // Export. | |
| // AMD. | |
| if (typeof define == 'function' && define.amd) { | |
| define(function () { | |
| return ExpantaNum; | |
| }); | |
| // Node and other environments that support module.exports. | |
| } else if (typeof module != 'undefined' && module.exports) { | |
| module.exports = ExpantaNum; | |
| // Browser. | |
| } else { | |
| if (!globalScope) { | |
| globalScope = typeof self != 'undefined' && self && self.self == self | |
| ? self : Function('return this')(); | |
| } | |
| globalScope.ExpantaNum = ExpantaNum; | |
| } | |
| })(this); |