2020-08-26 14:16:23 +00:00
( function ( global , factory ) {
typeof exports === 'object' && typeof module !== 'undefined' ? module . exports = factory ( ) :
typeof define === 'function' && define . amd ? define ( factory ) :
( global = global || self , global . Decimal = factory ( ) ) ;
} ( this , function ( ) { 'use strict' ;
var padEnd = function ( string , maxLength , fillString ) {
if ( string === null || maxLength === null ) {
return string ;
}
var result = String ( string ) ;
var targetLen = typeof maxLength === 'number'
? maxLength
: parseInt ( maxLength , 10 ) ;
if ( isNaN ( targetLen ) || ! isFinite ( targetLen ) ) {
return result ;
}
var length = result . length ;
if ( length >= targetLen ) {
return result ;
}
var filled = fillString === null ? '' : String ( fillString ) ;
if ( filled === '' ) {
filled = ' ' ;
}
var fillLen = targetLen - length ;
while ( filled . length < fillLen ) {
filled += filled ;
}
var truncated = filled . length > fillLen ? filled . substr ( 0 , fillLen ) : filled ;
return result + truncated ;
} ;
var MAX _SIGNIFICANT _DIGITS = 17 ; //Maximum number of digits of precision to assume in Number
var EXP _LIMIT = 9e15 ; //If we're ABOVE this value, increase a layer. (9e15 is close to the largest integer that can fit in a Number.)
var LAYER _DOWN = Math . log10 ( 9e15 ) ; //If we're BELOW this value, drop down a layer. About 15.954.
var FIRST _NEG _LAYER = 1 / 9e15 ; //At layer 0, smaller non-zero numbers than this become layer 1 numbers with negative mag. After that the pattern continues as normal.
var NUMBER _EXP _MAX = 308 ; //The largest exponent that can appear in a Number, though not all mantissas are valid here.
var NUMBER _EXP _MIN = - 324 ; //The smallest exponent that can appear in a Number, though not all mantissas are valid here.
var MAX _ES _IN _A _ROW = 5 ; //For default toString behaviour, when to swap from eee... to (e^n) syntax.
var powerOf10 = function ( ) {
// We need this lookup table because Math.pow(10, exponent)
// when exponent's absolute value is large is slightly inaccurate.
// You can fix it with the power of math... or just make a lookup table.
// Faster AND simpler
var powersOf10 = [ ] ;
for ( var i = NUMBER _EXP _MIN + 1 ; i <= NUMBER _EXP _MAX ; i ++ ) {
powersOf10 . push ( Number ( "1e" + i ) ) ;
}
var indexOf0InPowersOf10 = 323 ;
return function ( power ) {
return powersOf10 [ power + indexOf0InPowersOf10 ] ;
} ;
} ( ) ;
var D = function D ( value ) {
return Decimal . fromValue _noAlloc ( value ) ;
} ;
var FC = function FC ( sign , layer , mag ) {
return Decimal . fromComponents ( sign , layer , mag ) ;
} ;
var FC _NN = function FC _NN ( sign , layer , mag ) {
return Decimal . fromComponents _noNormalize ( sign , layer , mag ) ;
} ;
var ME = function ME ( mantissa , exponent ) {
return Decimal . fromMantissaExponent ( mantissa , exponent ) ;
} ;
var ME _NN = function ME _NN ( mantissa , exponent ) {
return Decimal . fromMantissaExponent _noNormalize ( mantissa , exponent ) ;
} ;
var decimalPlaces = function decimalPlaces ( value , places ) {
var len = places + 1 ;
var numDigits = Math . ceil ( Math . log10 ( Math . abs ( value ) ) ) ;
var rounded = Math . round ( value * Math . pow ( 10 , len - numDigits ) ) * Math . pow ( 10 , numDigits - len ) ;
return parseFloat ( rounded . toFixed ( Math . max ( len - numDigits , 0 ) ) ) ;
} ;
var f _maglog10 = function ( n ) {
return Math . sign ( n ) * Math . log10 ( Math . abs ( n ) ) ;
}
//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 = l + ( n + 0.5 ) * Math . log ( n ) ;
l = l - n ;
var n2 = n * n ;
var np = n ;
l = l + 1 / ( 12 * np ) ;
np = np * n2 ;
l = l + 1 / ( 360 * np ) ;
np = np * n2 ;
l = l + 1 / ( 1260 * np ) ;
np = np * n2 ;
l = l + 1 / ( 1680 * np ) ;
np = np * n2 ;
l = l + 1 / ( 1188 * np ) ;
np = np * n2 ;
l = l + 691 / ( 360360 * np ) ;
np = np * n2 ;
l = l + 7 / ( 1092 * np ) ;
np = np * n2 ;
l = l + 3617 / ( 122400 * np ) ;
return Math . exp ( l ) / scal1 ;
} ;
var twopi = 6.2831853071795864769252842 ; // 2*pi
var EXPN1 = 0.36787944117144232159553 ; // exp(-1)
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 = 1e-10 ) {
var w ;
var wn ;
if ( ! Number . isFinite ( z ) ) { return z ; }
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 ) ) ;
}
for ( var i = 0 ; i < 100 ; ++ i )
{
wn = ( z * Math . exp ( - w ) + w * w ) / ( w + 1 ) ;
if ( Math . abs ( wn - w ) < tol * Math . abs ( wn ) )
{
return wn ;
}
else
{
w = wn ;
}
}
throw Error ( "Iteration failed to converge: " + z ) ;
//return Number.NaN;
}
var Decimal =
/** @class */
function ( ) {
function Decimal ( value ) {
this . sign = Number . NaN ;
this . layer = Number . NaN ;
this . mag = Number . NaN ;
if ( value instanceof Decimal ) {
this . fromDecimal ( value ) ;
} else if ( typeof value === "number" ) {
this . fromNumber ( value ) ;
} else if ( typeof value === "string" ) {
this . fromString ( value ) ;
} else {
this . sign = 0 ;
this . layer = 0 ;
this . mag = 0 ;
}
}
Object . defineProperty ( Decimal . prototype , "m" , {
get : function get ( ) {
if ( this . sign === 0 )
{
return 0 ;
}
else if ( this . layer === 0 )
{
var exp = Math . floor ( Math . log10 ( this . mag ) ) ;
//handle special case 5e-324
var man ;
if ( this . mag === 5e-324 )
{
man = 5 ;
}
else
{
man = this . mag / powerOf10 ( exp ) ;
}
return this . sign * man ;
}
else if ( this . layer === 1 )
{
var residue = this . mag - Math . floor ( this . mag ) ;
return this . sign * Math . pow ( 10 , residue ) ;
}
else
{
//mantissa stops being relevant past 1e9e15 / ee15.954
return this . sign ;
}
} ,
set : function set ( value ) {
if ( this . layer <= 2 )
{
this . fromMantissaExponent ( value , this . e ) ;
}
else
{
//don't even pretend mantissa is meaningful
this . sign = Math . sign ( value ) ;
if ( this . sign === 0 ) { this . layer === 0 ; this . exponent === 0 ; }
}
} ,
enumerable : true ,
configurable : true
} ) ;
Object . defineProperty ( Decimal . prototype , "e" , {
get : function get ( ) {
if ( this . sign === 0 )
{
return 0 ;
}
else if ( this . layer === 0 )
{
return Math . floor ( Math . log10 ( this . mag ) ) ;
}
else if ( this . layer === 1 )
{
return Math . floor ( this . mag ) ;
}
else if ( this . layer === 2 )
{
return Math . floor ( Math . sign ( this . mag ) * Math . pow ( 10 , Math . abs ( this . mag ) ) ) ;
}
else
{
return this . mag * Number . POSITIVE _INFINITY ;
}
} ,
set : function set ( value ) {
this . fromMantissaExponent ( this . m , value ) ;
} ,
enumerable : true ,
configurable : true
} ) ;
Object . defineProperty ( Decimal . prototype , "s" , {
get : function get ( ) {
return this . sign ;
} ,
set : function set ( value ) {
if ( value === 0 ) {
this . sign = 0 ;
this . layer = 0 ;
this . mag = 0 ;
}
else
{
this . sign = value ;
}
} ,
enumerable : true ,
configurable : true
} ) ;
Object . defineProperty ( Decimal . prototype , "mantissa" , {
get : function get ( ) {
return this . m ;
} ,
set : function set ( value ) {
this . m = value ;
} ,
enumerable : true ,
configurable : true
} ) ;
Object . defineProperty ( Decimal . prototype , "exponent" , {
get : function get ( ) {
return this . e ;
} ,
set : function set ( value ) {
this . e = value ;
} ,
enumerable : true ,
configurable : true
} ) ;
Decimal . fromComponents = function ( sign , layer , mag ) {
return new Decimal ( ) . fromComponents ( sign , layer , mag ) ;
} ;
Decimal . fromComponents _noNormalize = function ( sign , layer , mag ) {
return new Decimal ( ) . fromComponents _noNormalize ( sign , layer , mag ) ;
} ;
Decimal . fromMantissaExponent = function ( mantissa , exponent ) {
return new Decimal ( ) . fromMantissaExponent ( mantissa , exponent ) ;
} ;
Decimal . fromMantissaExponent _noNormalize = function ( mantissa , exponent ) {
return new Decimal ( ) . fromMantissaExponent _noNormalize ( mantissa , exponent ) ;
} ;
Decimal . fromDecimal = function ( value ) {
return new Decimal ( ) . fromDecimal ( value ) ;
} ;
Decimal . fromNumber = function ( value ) {
return new Decimal ( ) . fromNumber ( value ) ;
} ;
Decimal . fromString = function ( value ) {
return new Decimal ( ) . fromString ( value ) ;
} ;
Decimal . fromValue = function ( value ) {
return new Decimal ( ) . fromValue ( value ) ;
} ;
Decimal . fromValue _noAlloc = function ( value ) {
return value instanceof Decimal ? value : new Decimal ( value ) ;
} ;
Decimal . abs = function ( value ) {
return D ( value ) . abs ( ) ;
} ;
Decimal . neg = function ( value ) {
return D ( value ) . neg ( ) ;
} ;
Decimal . negate = function ( value ) {
return D ( value ) . neg ( ) ;
} ;
Decimal . negated = function ( value ) {
return D ( value ) . neg ( ) ;
} ;
Decimal . sign = function ( value ) {
return D ( value ) . sign ( ) ;
} ;
Decimal . sgn = function ( value ) {
return D ( value ) . sign ( ) ;
} ;
Decimal . round = function ( value ) {
return D ( value ) . round ( ) ;
} ;
Decimal . floor = function ( value ) {
return D ( value ) . floor ( ) ;
} ;
Decimal . ceil = function ( value ) {
return D ( value ) . ceil ( ) ;
} ;
Decimal . trunc = function ( value ) {
return D ( value ) . trunc ( ) ;
} ;
Decimal . add = function ( value , other ) {
return D ( value ) . add ( other ) ;
} ;
Decimal . plus = function ( value , other ) {
return D ( value ) . add ( other ) ;
} ;
Decimal . sub = function ( value , other ) {
return D ( value ) . sub ( other ) ;
} ;
Decimal . subtract = function ( value , other ) {
return D ( value ) . sub ( other ) ;
} ;
Decimal . minus = function ( value , other ) {
return D ( value ) . sub ( other ) ;
} ;
Decimal . mul = function ( value , other ) {
return D ( value ) . mul ( other ) ;
} ;
Decimal . multiply = function ( value , other ) {
return D ( value ) . mul ( other ) ;
} ;
Decimal . times = function ( value , other ) {
return D ( value ) . mul ( other ) ;
} ;
Decimal . div = function ( value , other ) {
return D ( value ) . div ( other ) ;
} ;
Decimal . divide = function ( value , other ) {
return D ( value ) . div ( other ) ;
} ;
Decimal . recip = function ( value ) {
return D ( value ) . recip ( ) ;
} ;
Decimal . reciprocal = function ( value ) {
return D ( value ) . recip ( ) ;
} ;
Decimal . reciprocate = function ( value ) {
return D ( value ) . reciprocate ( ) ;
} ;
Decimal . cmp = function ( value , other ) {
return D ( value ) . cmp ( other ) ;
} ;
Decimal . cmpabs = function ( value , other ) {
return D ( value ) . cmpabs ( other ) ;
} ;
Decimal . compare = function ( value , other ) {
return D ( value ) . cmp ( other ) ;
} ;
Decimal . eq = function ( value , other ) {
return D ( value ) . eq ( other ) ;
} ;
Decimal . equals = function ( value , other ) {
return D ( value ) . eq ( other ) ;
} ;
Decimal . neq = function ( value , other ) {
return D ( value ) . neq ( other ) ;
} ;
Decimal . notEquals = function ( value , other ) {
return D ( value ) . notEquals ( other ) ;
} ;
Decimal . lt = function ( value , other ) {
return D ( value ) . lt ( other ) ;
} ;
Decimal . lte = function ( value , other ) {
return D ( value ) . lte ( other ) ;
} ;
Decimal . gt = function ( value , other ) {
return D ( value ) . gt ( other ) ;
} ;
Decimal . gte = function ( value , other ) {
return D ( value ) . gte ( other ) ;
} ;
Decimal . max = function ( value , other ) {
return D ( value ) . max ( other ) ;
} ;
Decimal . min = function ( value , other ) {
return D ( value ) . min ( other ) ;
} ;
Decimal . minabs = function ( value , other ) {
return D ( value ) . minabs ( other ) ;
} ;
Decimal . maxabs = function ( value , other ) {
return D ( value ) . maxabs ( other ) ;
} ;
Decimal . clamp = function ( value , min , max ) {
return D ( value ) . clamp ( min , max ) ;
}
Decimal . clampMin = function ( value , min ) {
return D ( value ) . clampMin ( min ) ;
}
Decimal . clampMax = function ( value , max ) {
return D ( value ) . clampMax ( max ) ;
}
Decimal . cmp _tolerance = function ( value , other , tolerance ) {
return D ( value ) . cmp _tolerance ( other , tolerance ) ;
} ;
Decimal . compare _tolerance = function ( value , other , tolerance ) {
return D ( value ) . cmp _tolerance ( other , tolerance ) ;
} ;
Decimal . eq _tolerance = function ( value , other , tolerance ) {
return D ( value ) . eq _tolerance ( other , tolerance ) ;
} ;
Decimal . equals _tolerance = function ( value , other , tolerance ) {
return D ( value ) . eq _tolerance ( other , tolerance ) ;
} ;
Decimal . neq _tolerance = function ( value , other , tolerance ) {
return D ( value ) . neq _tolerance ( other , tolerance ) ;
} ;
Decimal . notEquals _tolerance = function ( value , other , tolerance ) {
return D ( value ) . notEquals _tolerance ( other , tolerance ) ;
} ;
Decimal . lt _tolerance = function ( value , other , tolerance ) {
return D ( value ) . lt _tolerance ( other , tolerance ) ;
} ;
Decimal . lte _tolerance = function ( value , other , tolerance ) {
return D ( value ) . lte _tolerance ( other , tolerance ) ;
} ;
Decimal . gt _tolerance = function ( value , other , tolerance ) {
return D ( value ) . gt _tolerance ( other , tolerance ) ;
} ;
Decimal . gte _tolerance = function ( value , other , tolerance ) {
return D ( value ) . gte _tolerance ( other , tolerance ) ;
} ;
Decimal . pLog10 = function ( value ) {
return D ( value ) . pLog10 ( ) ;
} ;
Decimal . absLog10 = function ( value ) {
return D ( value ) . absLog10 ( ) ;
} ;
Decimal . log10 = function ( value ) {
return D ( value ) . log10 ( ) ;
} ;
Decimal . log = function ( value , base ) {
return D ( value ) . log ( base ) ;
} ;
Decimal . log2 = function ( value ) {
return D ( value ) . log2 ( ) ;
} ;
Decimal . ln = function ( value ) {
return D ( value ) . ln ( ) ;
} ;
Decimal . logarithm = function ( value , base ) {
return D ( value ) . logarithm ( base ) ;
} ;
Decimal . pow = function ( value , other ) {
return D ( value ) . pow ( other ) ;
} ;
Decimal . pow10 = function ( value ) {
return D ( value ) . pow10 ( ) ;
} ;
Decimal . root = function ( value , other ) {
return D ( value ) . root ( other ) ;
} ;
Decimal . factorial = function ( value , other ) {
return D ( value ) . factorial ( ) ;
} ;
Decimal . gamma = function ( value , other ) {
return D ( value ) . gamma ( ) ;
} ;
Decimal . lngamma = function ( value , other ) {
return D ( value ) . lngamma ( ) ;
} ;
Decimal . exp = function ( value ) {
return D ( value ) . exp ( ) ;
} ;
Decimal . sqr = function ( value ) {
return D ( value ) . sqr ( ) ;
} ;
Decimal . sqrt = function ( value ) {
return D ( value ) . sqrt ( ) ;
} ;
Decimal . cube = function ( value ) {
return D ( value ) . cube ( ) ;
} ;
Decimal . cbrt = function ( value ) {
return D ( value ) . cbrt ( ) ;
} ;
Decimal . tetrate = function ( value , height = 2 , payload = FC _NN ( 1 , 0 , 1 ) ) {
return D ( value ) . tetrate ( height , payload ) ;
}
Decimal . iteratedexp = function ( value , height = 2 , payload = FC _NN ( 1 , 0 , 1 ) ) {
return D ( value ) . iteratedexp ( height , payload ) ;
}
Decimal . iteratedlog = function ( value , base = 10 , times = 1 ) {
return D ( value ) . iteratedlog ( base , times ) ;
}
Decimal . layeradd10 = function ( value , diff ) {
return D ( value ) . layeradd10 ( diff ) ;
}
Decimal . layeradd = function ( value , diff , base = 10 ) {
return D ( value ) . layeradd ( diff , base ) ;
}
Decimal . slog = function ( value , base = 10 ) {
return D ( value ) . slog ( base ) ;
}
Decimal . lambertw = function ( value ) {
return D ( value ) . lambertw ( ) ;
}
Decimal . ssqrt = function ( value ) {
return D ( value ) . ssqrt ( ) ;
}
Decimal . pentate = function ( value , height = 2 , payload = FC _NN ( 1 , 0 , 1 ) ) {
return D ( value ) . pentate ( height , payload ) ;
}
/ * *
* If you 're willing to spend ' resourcesAvailable ' and want to buy something
* with exponentially increasing cost each purchase ( start at priceStart ,
* multiply by priceRatio , already own currentOwned ) , how much of it can you buy ?
* Adapted from Trimps source code .
* /
Decimal . affordGeometricSeries = function ( resourcesAvailable , priceStart , priceRatio , currentOwned ) {
return this . affordGeometricSeries _core ( D ( resourcesAvailable ) , D ( priceStart ) , D ( priceRatio ) , currentOwned ) ;
} ;
/ * *
* How much resource would it cost to buy ( numItems ) items if you already have currentOwned ,
* the initial price is priceStart and it multiplies by priceRatio each purchase ?
* /
Decimal . sumGeometricSeries = function ( numItems , priceStart , priceRatio , currentOwned ) {
return this . sumGeometricSeries _core ( numItems , D ( priceStart ) , D ( priceRatio ) , currentOwned ) ;
} ;
/ * *
* If you 're willing to spend ' resourcesAvailable ' and want to buy something with additively
* increasing cost each purchase ( start at priceStart , add by priceAdd , already own currentOwned ) ,
* how much of it can you buy ?
* /
Decimal . affordArithmeticSeries = function ( resourcesAvailable , priceStart , priceAdd , currentOwned ) {
return this . affordArithmeticSeries _core ( D ( resourcesAvailable ) , D ( priceStart ) , D ( priceAdd ) , D ( currentOwned ) ) ;
} ;
/ * *
* How much resource would it cost to buy ( numItems ) items if you already have currentOwned ,
* the initial price is priceStart and it adds priceAdd each purchase ?
* Adapted from http : //www.mathwords.com/a/arithmetic_series.htm
* /
Decimal . sumArithmeticSeries = function ( numItems , priceStart , priceAdd , currentOwned ) {
return this . sumArithmeticSeries _core ( D ( numItems ) , D ( priceStart ) , D ( priceAdd ) , D ( currentOwned ) ) ;
} ;
/ * *
* When comparing two purchases that cost ( resource ) and increase your resource / sec by ( deltaRpS ) ,
* the lowest efficiency score is the better one to purchase .
* From Frozen Cookies :
* http : //cookieclicker.wikia.com/wiki/Frozen_Cookies_(JavaScript_Add-on)#Efficiency.3F_What.27s_that.3F
* /
Decimal . efficiencyOfPurchase = function ( cost , currentRpS , deltaRpS ) {
return this . efficiencyOfPurchase _core ( D ( cost ) , D ( currentRpS ) , D ( deltaRpS ) ) ;
} ;
Decimal . randomDecimalForTesting = function ( maxLayers ) {
// NOTE: This doesn't follow any kind of sane random distribution, so use this for testing purposes only.
//5% of the time, return 0
if ( Math . random ( ) * 20 < 1 ) {
return FC _NN ( 0 , 0 , 0 ) ;
}
var randomsign = Math . random ( ) > 0.5 ? 1 : - 1 ;
//5% of the time, return 1 or -1
if ( Math . random ( ) * 20 < 1 ) {
return FC _NN ( randomsign , 0 , 1 ) ;
}
//pick a random layer
var layer = Math . floor ( Math . random ( ) * ( maxLayers + 1 ) ) ;
var randomexp = layer === 0 ? Math . random ( ) * 616 - 308 : Math . random ( ) * 16 ;
//10% of the time, make it a simple power of 10
if ( Math . random ( ) > 0.9 ) { randomexp = Math . trunc ( randomexp ) ; }
var randommag = Math . pow ( 10 , randomexp ) ;
//10% of the time, trunc mag
if ( Math . random ( ) > 0.9 ) { randommag = Math . trunc ( randommag ) ; }
return FC ( randomsign , layer , randommag ) ;
} ;
Decimal . affordGeometricSeries _core = function ( resourcesAvailable , priceStart , priceRatio , currentOwned ) {
var actualStart = priceStart . mul ( priceRatio . pow ( currentOwned ) ) ;
return Decimal . floor ( resourcesAvailable . div ( actualStart ) . mul ( priceRatio . sub ( 1 ) ) . add ( 1 ) . log10 ( ) . div ( priceRatio . log10 ( ) ) ) ;
} ;
Decimal . sumGeometricSeries _core = function ( numItems , priceStart , priceRatio , currentOwned ) {
return priceStart . mul ( priceRatio . pow ( currentOwned ) ) . mul ( Decimal . sub ( 1 , priceRatio . pow ( numItems ) ) ) . div ( Decimal . sub ( 1 , priceRatio ) ) ;
} ;
Decimal . affordArithmeticSeries _core = function ( resourcesAvailable , priceStart , priceAdd , currentOwned ) {
// n = (-(a-d/2) + sqrt((a-d/2)^2+2dS))/d
// where a is actualStart, d is priceAdd and S is resourcesAvailable
// then floor it and you're done!
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 ( ) ;
} ;
Decimal . sumArithmeticSeries _core = function ( numItems , priceStart , priceAdd , currentOwned ) {
var actualStart = priceStart . add ( currentOwned . mul ( priceAdd ) ) ; // (n/2)*(2*a+(n-1)*d)
return numItems . div ( 2 ) . mul ( actualStart . mul ( 2 ) . plus ( numItems . sub ( 1 ) . mul ( priceAdd ) ) ) ;
} ;
Decimal . efficiencyOfPurchase _core = function ( cost , currentRpS , deltaRpS ) {
return cost . div ( currentRpS ) . add ( cost . div ( deltaRpS ) ) ;
} ;
Decimal . prototype . normalize = function ( ) {
/ *
PSEUDOCODE :
Whenever we are partially 0 ( sign is 0 or mag and layer is 0 ) , make it fully 0.
Whenever we are at or hit layer 0 , extract sign from negative mag .
If layer === 0 and mag < FIRST _NEG _LAYER ( 1 / 9e15 ) , shift to 'first negative layer' ( add layer , log10 mag ) .
While abs ( mag ) > EXP _LIMIT ( 9e15 ) , layer += 1 , mag = maglog10 ( mag ) .
While abs ( mag ) < LAYER _DOWN ( 15.954 ) and layer > 0 , layer -= 1 , mag = pow ( 10 , mag ) .
When we ' re done , all of the following should be true OR one of the numbers is not IsFinite OR layer is not IsInteger ( error state ) :
Any 0 is totally zero ( 0 , 0 , 0 ) .
Anything layer 0 has mag 0 OR mag > 1 / 9e15 and < 9e15 .
Anything layer 1 or higher has abs ( mag ) >= 15.954 and < 9e15 .
We will assume in calculations that all Decimals are either erroneous or satisfy these criteria . ( Otherwise : Garbage in , garbage out . )
* /
if ( this . sign === 0 || ( this . mag === 0 && this . layer === 0 ) )
{
this . sign = 0 ;
this . mag = 0 ;
this . layer = 0 ;
return this ;
}
if ( this . layer === 0 && this . mag < 0 )
{
//extract sign from negative mag at layer 0
this . mag = - this . mag ;
this . sign = - this . sign ;
}
//Handle shifting from layer 0 to negative layers.
if ( this . layer === 0 && this . mag < FIRST _NEG _LAYER )
{
this . layer += 1 ;
this . mag = Math . log10 ( this . mag ) ;
return this ;
}
var absmag = Math . abs ( this . mag ) ;
var signmag = Math . sign ( this . mag ) ;
if ( absmag >= EXP _LIMIT )
{
this . layer += 1 ;
this . mag = signmag * Math . log10 ( absmag ) ;
return this ;
}
else
{
while ( absmag < LAYER _DOWN && this . layer > 0 )
{
this . layer -= 1 ;
if ( this . layer === 0 )
{
this . mag = Math . pow ( 10 , this . mag ) ;
}
else
{
this . mag = signmag * Math . pow ( 10 , absmag ) ;
absmag = Math . abs ( this . mag ) ;
signmag = Math . sign ( this . mag ) ;
}
}
if ( this . layer === 0 )
{
if ( this . mag < 0 )
{
//extract sign from negative mag at layer 0
this . mag = - this . mag ;
this . sign = - this . sign ;
}
else if ( this . mag === 0 )
{
//excessive rounding can give us all zeroes
this . sign = 0 ;
}
}
}
return this ;
} ;
Decimal . prototype . fromComponents = function ( sign , layer , mag ) {
this . sign = sign ;
this . layer = layer ;
this . mag = mag ;
this . normalize ( ) ;
return this ;
} ;
Decimal . prototype . fromComponents _noNormalize = function ( sign , layer , mag ) {
this . sign = sign ;
this . layer = layer ;
this . mag = mag ;
return this ;
} ;
Decimal . prototype . fromMantissaExponent = function ( mantissa , exponent ) {
this . layer = 1 ;
this . sign = Math . sign ( mantissa ) ;
mantissa = Math . abs ( mantissa ) ;
this . mag = exponent + Math . log10 ( mantissa ) ;
this . normalize ( ) ;
return this ;
} ;
Decimal . prototype . fromMantissaExponent _noNormalize = function ( mantissa , exponent ) {
//The idea of 'normalizing' a break_infinity.js style Decimal doesn't really apply. So just do the same thing.
this . fromMantissaExponent ( mantissa , exponent ) ;
return this ;
} ;
Decimal . prototype . fromDecimal = function ( value ) {
this . sign = value . sign ;
this . layer = value . layer ;
this . mag = value . mag ;
return this ;
} ;
Decimal . prototype . fromNumber = function ( value ) {
this . mag = Math . abs ( value ) ;
this . sign = Math . sign ( value ) ;
this . layer = 0 ;
this . normalize ( ) ;
return this ;
} ;
var IGNORE _COMMAS = true ;
var COMMAS _ARE _DECIMAL _POINTS = false ;
Decimal . prototype . fromString = function ( value ) {
if ( IGNORE _COMMAS ) { value = value . replace ( "," , "" ) ; }
else if ( COMMAS _ARE _DECIMAL _POINTS ) { value = value . replace ( "," , "." ) ; }
//Handle x^^^y format.
var pentationparts = value . split ( "^^^" ) ;
if ( pentationparts . length === 2 )
{
var base = parseFloat ( pentationparts [ 0 ] ) ;
var height = parseFloat ( pentationparts [ 1 ] ) ;
var payload = 1 ;
var heightparts = pentationparts [ 1 ] . split ( ";" ) ;
if ( heightparts . length === 2 )
{
var payload = parseFloat ( heightparts [ 1 ] ) ;
if ( ! isFinite ( payload ) ) { payload = 1 ; }
}
if ( isFinite ( base ) && isFinite ( height ) )
{
var result = Decimal . pentate ( base , height , payload ) ;
this . sign = result . sign ;
this . layer = result . layer ;
this . mag = result . mag ;
return this ;
}
}
//Handle x^^y format.
var tetrationparts = value . split ( "^^" ) ;
if ( tetrationparts . length === 2 )
{
var base = parseFloat ( tetrationparts [ 0 ] ) ;
var height = parseFloat ( tetrationparts [ 1 ] ) ;
var heightparts = tetrationparts [ 1 ] . split ( ";" ) ;
if ( heightparts . length === 2 )
{
var payload = parseFloat ( heightparts [ 1 ] ) ;
if ( ! isFinite ( payload ) ) { payload = 1 ; }
}
if ( isFinite ( base ) && isFinite ( height ) )
{
var result = Decimal . tetrate ( base , height , payload ) ;
this . sign = result . sign ;
this . layer = result . layer ;
this . mag = result . mag ;
return this ;
}
}
//Handle x^y format.
var powparts = value . split ( "^" ) ;
if ( powparts . length === 2 )
{
var base = parseFloat ( powparts [ 0 ] ) ;
var exponent = parseFloat ( powparts [ 1 ] ) ;
if ( isFinite ( base ) && isFinite ( exponent ) )
{
var result = Decimal . pow ( base , exponent ) ;
this . sign = result . sign ;
this . layer = result . layer ;
this . mag = result . mag ;
return this ;
}
}
//Handle various cases involving it being a Big Number.
value = value . trim ( ) . toLowerCase ( ) ;
//handle X PT Y format.
var ptparts = value . split ( "pt" ) ;
if ( ptparts . length === 2 )
{
base = 10 ;
height = parseFloat ( ptparts [ 0 ] ) ;
ptparts [ 1 ] = ptparts [ 1 ] . replace ( "(" , "" ) ;
ptparts [ 1 ] = ptparts [ 1 ] . replace ( ")" , "" ) ;
var payload = parseFloat ( ptparts [ 1 ] ) ;
if ( ! isFinite ( payload ) ) { payload = 1 ; }
if ( isFinite ( base ) && isFinite ( height ) )
{
var result = Decimal . tetrate ( base , height , payload ) ;
this . sign = result . sign ;
this . layer = result . layer ;
this . mag = result . mag ;
return this ;
}
}
//handle XpY format (it's the same thing just with p).
var ptparts = value . split ( "p" ) ;
if ( ptparts . length === 2 )
{
base = 10 ;
height = parseFloat ( ptparts [ 0 ] ) ;
ptparts [ 1 ] = ptparts [ 1 ] . replace ( "(" , "" ) ;
ptparts [ 1 ] = ptparts [ 1 ] . replace ( ")" , "" ) ;
var payload = parseFloat ( ptparts [ 1 ] ) ;
if ( ! isFinite ( payload ) ) { payload = 1 ; }
if ( isFinite ( base ) && isFinite ( height ) )
{
var result = Decimal . tetrate ( base , height , payload ) ;
this . sign = result . sign ;
this . layer = result . layer ;
this . mag = result . mag ;
return this ;
}
}
var parts = value . split ( "e" ) ;
var ecount = parts . length - 1 ;
//Handle numbers that are exactly floats (0 or 1 es).
if ( ecount === 0 )
{
var numberAttempt = parseFloat ( value ) ;
if ( isFinite ( numberAttempt ) )
{
return this . fromNumber ( numberAttempt ) ;
}
}
else if ( ecount === 1 )
{
//Very small numbers ("2e-3000" and so on) may look like valid floats but round to 0.
var numberAttempt = parseFloat ( value ) ;
if ( isFinite ( numberAttempt ) && numberAttempt !== 0 )
{
return this . fromNumber ( numberAttempt ) ;
}
}
//Handle new (e^N)X format.
var newparts = value . split ( "e^" ) ;
if ( newparts . length === 2 )
{
this . sign = 1 ;
if ( newparts [ 0 ] . charAt ( 0 ) == "-" )
{
this . sign = - 1 ;
}
var layerstring = "" ;
for ( var i = 0 ; i < newparts [ 1 ] . length ; ++ i )
{
var chrcode = newparts [ 1 ] . charCodeAt ( i ) ;
if ( ( chrcode >= 43 && chrcode <= 57 ) || chrcode === 101 ) //is "0" to "9" or "+" or "-" or "." or "e" (or "," or "/")
{
layerstring += newparts [ 1 ] . charAt ( i ) ;
}
else //we found the end of the layer count
{
this . layer = parseFloat ( layerstring ) ;
this . mag = parseFloat ( newparts [ 1 ] . substr ( i + 1 ) ) ;
this . normalize ( ) ;
return this ;
}
}
}
if ( ecount < 1 ) { this . sign = 0 ; this . layer = 0 ; this . mag = 0 ; return this ; }
var mantissa = parseFloat ( parts [ 0 ] ) ;
if ( mantissa === 0 ) { this . sign = 0 ; this . layer = 0 ; this . mag = 0 ; return this ; }
var exponent = parseFloat ( parts [ parts . length - 1 ] ) ;
//handle numbers like AeBeC and AeeeeBeC
if ( ecount >= 2 )
{
var me = parseFloat ( parts [ parts . length - 2 ] ) ;
if ( isFinite ( me ) )
{
exponent *= Math . sign ( me ) ;
exponent += f _maglog10 ( me ) ;
}
}
//Handle numbers written like eee... (N es) X
if ( ! isFinite ( mantissa ) )
{
this . sign = ( parts [ 0 ] === "-" ) ? - 1 : 1 ;
this . layer = ecount ;
this . mag = exponent ;
}
//Handle numbers written like XeY
else if ( ecount === 1 )
{
this . sign = Math . sign ( mantissa ) ;
this . layer = 1 ;
//Example: 2e10 is equal to 10^log10(2e10) which is equal to 10^(10+log10(2))
this . mag = exponent + Math . log10 ( Math . abs ( mantissa ) ) ;
}
//Handle numbers written like Xeee... (N es) Y
else
{
this . sign = Math . sign ( mantissa ) ;
this . layer = ecount ;
if ( ecount === 2 )
{
var result = Decimal . mul ( FC ( 1 , 2 , exponent ) , D ( mantissa ) ) ;
this . sign = result . sign ;
this . layer = result . layer ;
this . mag = result . mag ;
return this ;
}
else
{
//at eee and above, mantissa is too small to be recognizable!
this . mag = exponent ;
}
}
this . normalize ( ) ;
return this ;
} ;
Decimal . prototype . fromValue = function ( value ) {
if ( value instanceof Decimal ) {
return this . fromDecimal ( value ) ;
}
if ( typeof value === "number" ) {
return this . fromNumber ( value ) ;
}
if ( typeof value === "string" ) {
return this . fromString ( value ) ;
}
this . sign = 0 ;
this . layer = 0 ;
this . mag = 0 ;
return this ;
} ;
Decimal . prototype . toNumber = function ( ) {
if ( ! Number . isFinite ( this . layer ) ) { return Number . NaN ; }
if ( this . layer === 0 )
{
return this . sign * this . mag ;
}
else if ( this . layer === 1 )
{
return this . sign * Math . pow ( 10 , this . mag ) ;
}
else //overflow for any normalized Decimal
{
return this . mag > 0 ? ( this . sign > 0 ? Number . POSITIVE _INFINITY : Number . NEGATIVE _INFINITY ) : 0 ;
}
} ;
Decimal . prototype . mantissaWithDecimalPlaces = function ( places ) {
// https://stackoverflow.com/a/37425022
if ( isNaN ( this . m ) ) {
return Number . NaN ;
}
if ( this . m === 0 ) {
return 0 ;
}
return decimalPlaces ( this . m , places ) ;
} ;
Decimal . prototype . magnitudeWithDecimalPlaces = function ( places ) {
// https://stackoverflow.com/a/37425022
if ( isNaN ( this . mag ) ) {
return Number . NaN ;
}
if ( this . mag === 0 ) {
return 0 ;
}
return decimalPlaces ( this . mag , places ) ;
} ;
Decimal . prototype . toString = function ( ) {
if ( this . layer === 0 )
{
if ( ( this . mag < 1e21 && this . mag > 1e-7 ) || this . mag === 0 )
{
return ( this . sign * this . mag ) . toString ( ) ;
}
return this . m + "e" + this . e ;
}
else if ( this . layer === 1 )
{
return this . m + "e" + this . e ;
}
else
{
//layer 2+
if ( this . layer <= MAX _ES _IN _A _ROW )
{
return ( this . sign === - 1 ? "-" : "" ) + "e" . repeat ( this . layer ) + this . mag ;
}
else
{
return ( this . sign === - 1 ? "-" : "" ) + "(e^" + this . layer + ")" + this . mag ;
}
}
} ;
Decimal . prototype . toExponential = function ( places ) {
if ( this . layer === 0 )
{
return ( this . sign * this . mag ) . toExponential ( places ) ;
}
return this . toStringWithDecimalPlaces ( places ) ;
} ;
Decimal . prototype . toFixed = function ( places ) {
if ( this . layer === 0 )
{
return ( this . sign * this . mag ) . toFixed ( places ) ;
}
return this . toStringWithDecimalPlaces ( places ) ;
} ;
Decimal . prototype . toPrecision = function ( places ) {
if ( this . e <= - 7 ) {
return this . toExponential ( places - 1 ) ;
}
if ( places > this . e ) {
return this . toFixed ( places - this . exponent - 1 ) ;
}
return this . toExponential ( places - 1 ) ;
} ;
Decimal . prototype . valueOf = function ( ) {
return this . toString ( ) ;
} ;
Decimal . prototype . toJSON = function ( ) {
return this . toString ( ) ;
} ;
Decimal . prototype . toStringWithDecimalPlaces = function ( places ) {
if ( this . layer === 0 )
{
if ( ( this . mag < 1e21 && this . mag > 1e-7 ) || this . mag === 0 )
{
return ( this . sign * this . mag ) . toFixed ( places ) ;
}
return decimalPlaces ( this . m , places ) + "e" + decimalPlaces ( this . e , places ) ;
}
else if ( this . layer === 1 )
{
return decimalPlaces ( this . m , places ) + "e" + decimalPlaces ( this . e , places ) ;
}
else
{
//layer 2+
if ( this . layer <= MAX _ES _IN _A _ROW )
{
return ( this . sign === - 1 ? "-" : "" ) + "e" . repeat ( this . layer ) + decimalPlaces ( this . mag , places ) ;
}
else
{
return ( this . sign === - 1 ? "-" : "" ) + "(e^" + this . layer + ")" + decimalPlaces ( this . mag , places ) ;
}
}
} ;
Decimal . prototype . abs = function ( ) {
return FC _NN ( this . sign === 0 ? 0 : 1 , this . layer , this . mag ) ;
} ;
Decimal . prototype . neg = function ( ) {
return FC _NN ( - this . sign , this . layer , this . mag ) ;
} ;
Decimal . prototype . negate = function ( ) {
return this . neg ( ) ;
} ;
Decimal . prototype . negated = function ( ) {
return this . neg ( ) ;
} ;
Decimal . prototype . sign = function ( ) {
return this . sign ;
} ;
Decimal . prototype . sgn = function ( ) {
return this . sign ;
} ;
Decimal . prototype . round = function ( ) {
if ( this . mag < 0 )
{
return Decimal . dZero ;
}
if ( this . layer === 0 )
{
return FC ( this . sign , 0 , Math . round ( this . mag ) ) ;
}
return this ;
} ;
Decimal . prototype . floor = function ( ) {
if ( this . mag < 0 )
{
return Decimal . dZero ;
}
if ( this . layer === 0 )
{
return FC ( this . sign , 0 , Math . floor ( this . mag ) ) ;
}
return this ;
} ;
Decimal . prototype . ceil = function ( ) {
if ( this . mag < 0 )
{
return Decimal . dZero ;
}
if ( this . layer === 0 )
{
return FC ( this . sign , 0 , Math . ceil ( this . mag ) ) ;
}
return this ;
} ;
Decimal . prototype . trunc = function ( ) {
if ( this . mag < 0 )
{
return Decimal . dZero ;
}
if ( this . layer === 0 )
{
return FC ( this . sign , 0 , Math . trunc ( this . mag ) ) ;
}
return this ;
} ;
Decimal . prototype . add = function ( value ) {
var decimal = D ( value ) ;
//inf/nan check
if ( ! Number . isFinite ( this . layer ) ) { return this ; }
if ( ! Number . isFinite ( decimal . layer ) ) { return decimal ; }
//Special case - if one of the numbers is 0, return the other number.
if ( this . sign === 0 ) { return decimal ; }
if ( decimal . sign === 0 ) { return this ; }
//Special case - Adding a number to its negation produces 0, no matter how large.
if ( this . sign === - ( decimal . sign ) && this . layer === decimal . layer && this . mag === decimal . mag ) { return FC _NN ( 0 , 0 , 0 ) ; }
var a ;
var b ;
//Special case: If one of the numbers is layer 2 or higher, just take the bigger number.
if ( ( this . layer >= 2 || decimal . layer >= 2 ) ) { return this . maxabs ( decimal ) ; }
if ( Decimal . cmpabs ( this , decimal ) > 0 )
{
a = this ;
b = decimal ;
}
else
{
a = decimal ;
b = this ;
}
if ( a . layer === 0 && b . layer === 0 ) { return D ( a . sign * a . mag + b . sign * b . mag ) ; }
var layera = a . layer * Math . sign ( a . mag ) ;
var layerb = b . layer * Math . sign ( b . mag ) ;
//If one of the numbers is 2+ layers higher than the other, just take the bigger number.
if ( layera - layerb >= 2 ) { return a ; }
if ( layera === 0 && layerb === - 1 )
{
if ( Math . abs ( b . mag - Math . log10 ( a . mag ) ) > MAX _SIGNIFICANT _DIGITS )
{
return a ;
}
else
{
var magdiff = Math . pow ( 10 , Math . log10 ( a . mag ) - b . mag ) ;
var mantissa = ( b . sign ) + ( a . sign * magdiff ) ;
return FC ( Math . sign ( mantissa ) , 1 , b . mag + Math . log10 ( Math . abs ( mantissa ) ) ) ;
}
}
if ( layera === 1 && layerb === 0 )
{
if ( Math . abs ( a . mag - Math . log10 ( b . mag ) ) > MAX _SIGNIFICANT _DIGITS )
{
return a ;
}
else
{
var magdiff = Math . pow ( 10 , a . mag - Math . log10 ( b . mag ) ) ;
var mantissa = ( b . sign ) + ( a . sign * magdiff ) ;
return FC ( Math . sign ( mantissa ) , 1 , Math . log10 ( b . mag ) + Math . log10 ( Math . abs ( mantissa ) ) ) ;
}
}
if ( Math . abs ( a . mag - b . mag ) > MAX _SIGNIFICANT _DIGITS )
{
return a ;
}
else
{
var magdiff = Math . pow ( 10 , a . mag - b . mag ) ;
var mantissa = ( b . sign ) + ( a . sign * magdiff ) ;
return FC ( Math . sign ( mantissa ) , 1 , b . mag + Math . log10 ( Math . abs ( mantissa ) ) ) ;
}
throw Error ( "Bad arguments to add: " + this + ", " + value ) ;
} ;
Decimal . prototype . plus = function ( value ) {
return this . add ( value ) ;
} ;
Decimal . prototype . sub = function ( value ) {
return this . add ( D ( value ) . neg ( ) ) ;
} ;
Decimal . prototype . subtract = function ( value ) {
return this . sub ( value ) ;
} ;
Decimal . prototype . minus = function ( value ) {
return this . sub ( value ) ;
} ;
Decimal . prototype . mul = function ( value ) {
var decimal = D ( value ) ;
//inf/nan check
if ( ! Number . isFinite ( this . layer ) ) { return this ; }
if ( ! Number . isFinite ( decimal . layer ) ) { return decimal ; }
//Special case - if one of the numbers is 0, return 0.
if ( this . sign === 0 || decimal . sign === 0 ) { return FC _NN ( 0 , 0 , 0 ) ; }
//Special case - Multiplying a number by its own reciprocal yields +/- 1, no matter how large.
if ( this . layer === decimal . layer && this . mag === - decimal . mag ) { return FC _NN ( this . sign * decimal . sign , 0 , 1 ) ; }
var a ;
var b ;
//Which number is bigger in terms of its multiplicative distance from 1?
if ( ( this . layer > decimal . layer ) || ( this . layer == decimal . layer && Math . abs ( this . mag ) > Math . abs ( decimal . mag ) ) )
{
a = this ;
b = decimal ;
}
else
{
a = decimal ;
b = this ;
}
if ( a . layer === 0 && b . layer === 0 ) { return D ( a . sign * b . sign * a . mag * b . mag ) ; }
//Special case: If one of the numbers is layer 3 or higher or one of the numbers is 2+ layers bigger than the other, just take the bigger number.
if ( a . layer >= 3 || ( a . layer - b . layer >= 2 ) ) { return FC ( a . sign * b . sign , a . layer , a . mag ) ; }
if ( a . layer === 1 && b . layer === 0 )
{
return FC ( a . sign * b . sign , 1 , a . mag + Math . log10 ( b . mag ) ) ;
}
if ( a . layer === 1 && b . layer === 1 )
{
return FC ( a . sign * b . sign , 1 , a . mag + b . mag ) ;
}
if ( a . layer === 2 && b . layer === 1 )
{
var newmag = FC ( Math . sign ( a . mag ) , a . layer - 1 , Math . abs ( a . mag ) ) . add ( FC ( Math . sign ( b . mag ) , b . layer - 1 , Math . abs ( b . mag ) ) ) ;
return FC ( a . sign * b . sign , newmag . layer + 1 , newmag . sign * newmag . mag ) ;
}
if ( a . layer === 2 && b . layer === 2 )
{
var newmag = FC ( Math . sign ( a . mag ) , a . layer - 1 , Math . abs ( a . mag ) ) . add ( FC ( Math . sign ( b . mag ) , b . layer - 1 , Math . abs ( b . mag ) ) ) ;
return FC ( a . sign * b . sign , newmag . layer + 1 , newmag . sign * newmag . mag ) ;
}
throw Error ( "Bad arguments to mul: " + this + ", " + value ) ;
} ;
Decimal . prototype . multiply = function ( value ) {
return this . mul ( value ) ;
} ;
Decimal . prototype . times = function ( value ) {
return this . mul ( value ) ;
} ;
Decimal . prototype . div = function ( value ) {
var decimal = D ( value ) ;
return this . mul ( decimal . recip ( ) ) ;
} ;
Decimal . prototype . divide = function ( value ) {
return this . div ( value ) ;
} ;
Decimal . prototype . divideBy = function ( value ) {
return this . div ( value ) ;
} ;
Decimal . prototype . dividedBy = function ( value ) {
return this . div ( value ) ;
} ;
Decimal . prototype . recip = function ( ) {
if ( this . mag === 0 )
{
return Decimal . dNaN ;
}
else if ( this . layer === 0 )
{
return FC ( this . sign , 0 , 1 / this . mag ) ;
}
else
{
return FC ( this . sign , this . layer , - this . mag ) ;
}
} ;
Decimal . prototype . reciprocal = function ( ) {
return this . recip ( ) ;
} ;
Decimal . prototype . reciprocate = function ( ) {
return this . recip ( ) ;
} ;
/ * *
* - 1 for less than value , 0 for equals value , 1 for greater than value
* /
Decimal . prototype . cmp = function ( value ) {
var decimal = D ( value ) ;
if ( this . sign > decimal . sign ) { return 1 ; }
if ( this . sign < decimal . sign ) { return - 1 ; }
return this . sign * this . cmpabs ( value ) ;
} ;
Decimal . prototype . cmpabs = function ( value ) {
var decimal = D ( value ) ;
var layera = this . mag > 0 ? this . layer : - this . layer ;
var layerb = decimal . mag > 0 ? decimal . layer : - decimal . layer ;
if ( layera > layerb ) { return 1 ; }
if ( layera < layerb ) { return - 1 ; }
if ( this . mag > decimal . mag ) { return 1 ; }
if ( this . mag < decimal . mag ) { return - 1 ; }
return 0 ;
} ;
Decimal . prototype . compare = function ( value ) {
return this . cmp ( value ) ;
} ;
Decimal . prototype . eq = function ( value ) {
var decimal = D ( value ) ;
return this . sign === decimal . sign && this . layer === decimal . layer && this . mag === decimal . mag ;
} ;
Decimal . prototype . equals = function ( value ) {
return this . eq ( value ) ;
} ;
Decimal . prototype . neq = function ( value ) {
return ! this . eq ( value ) ;
} ;
Decimal . prototype . notEquals = function ( value ) {
return this . neq ( value ) ;
} ;
Decimal . prototype . lt = function ( value ) {
var decimal = D ( value ) ;
return this . cmp ( value ) === - 1 ;
} ;
Decimal . prototype . lte = function ( value ) {
return ! this . gt ( value ) ;
} ;
Decimal . prototype . gt = function ( value ) {
var decimal = D ( value ) ;
return this . cmp ( value ) === 1 ;
} ;
Decimal . prototype . gte = function ( value ) {
return ! this . lt ( value ) ;
} ;
Decimal . prototype . max = function ( value ) {
var decimal = D ( value ) ;
return this . lt ( decimal ) ? decimal : this ;
} ;
Decimal . prototype . min = function ( value ) {
var decimal = D ( value ) ;
return this . gt ( decimal ) ? decimal : this ;
} ;
Decimal . prototype . maxabs = function ( value ) {
var decimal = D ( value ) ;
return this . cmpabs ( decimal ) < 0 ? decimal : this ;
} ;
Decimal . prototype . minabs = function ( value ) {
var decimal = D ( value ) ;
return this . cmpabs ( decimal ) > 0 ? decimal : this ;
} ;
Decimal . prototype . clamp = function ( min , max ) {
return this . max ( min ) . min ( max ) ;
}
Decimal . prototype . clampMin = function ( min ) {
return this . max ( min ) ;
}
Decimal . prototype . clampMax = function ( max ) {
return this . min ( max ) ;
}
Decimal . prototype . cmp _tolerance = function ( value , tolerance ) {
var decimal = D ( value ) ;
return this . eq _tolerance ( decimal , tolerance ) ? 0 : this . cmp ( decimal ) ;
} ;
Decimal . prototype . compare _tolerance = function ( value , tolerance ) {
return this . cmp _tolerance ( value , tolerance ) ;
} ;
/ * *
* Tolerance is a relative tolerance , multiplied by the greater of the magnitudes of the two arguments .
* For example , if you put in 1e-9 , then any number closer to the
* larger number than ( larger number ) * 1e-9 will be considered equal .
* /
Decimal . prototype . eq _tolerance = function ( value , tolerance ) {
var decimal = D ( value ) ; // https://stackoverflow.com/a/33024979
if ( tolerance == null ) { tolerance = 1e-7 ; }
//Numbers that are too far away are never close.
if ( this . sign !== decimal . sign ) { return false ; }
if ( Math . abs ( this . layer - decimal . layer ) > 1 ) { return false ; }
// return abs(a-b) <= tolerance * max(abs(a), abs(b))
var magA = this . mag ;
var magB = decimal . mag ;
if ( this . layer > decimal . layer ) { magB = f _maglog10 ( magB ) ; }
if ( this . layer < decimal . layer ) { magA = f _maglog10 ( magA ) ; }
return Math . abs ( magA - magB ) <= tolerance * Math . max ( Math . abs ( magA ) , Math . abs ( magB ) ) ;
} ;
Decimal . prototype . equals _tolerance = function ( value , tolerance ) {
return this . eq _tolerance ( value , tolerance ) ;
} ;
Decimal . prototype . neq _tolerance = function ( value , tolerance ) {
return ! this . eq _tolerance ( value , tolerance ) ;
} ;
Decimal . prototype . notEquals _tolerance = function ( value , tolerance ) {
return this . neq _tolerance ( value , tolerance ) ;
} ;
Decimal . prototype . lt _tolerance = function ( value , tolerance ) {
var decimal = D ( value ) ;
return ! this . eq _tolerance ( decimal , tolerance ) && this . lt ( decimal ) ;
} ;
Decimal . prototype . lte _tolerance = function ( value , tolerance ) {
var decimal = D ( value ) ;
return this . eq _tolerance ( decimal , tolerance ) || this . lt ( decimal ) ;
} ;
Decimal . prototype . gt _tolerance = function ( value , tolerance ) {
var decimal = D ( value ) ;
return ! this . eq _tolerance ( decimal , tolerance ) && this . gt ( decimal ) ;
} ;
Decimal . prototype . gte _tolerance = function ( value , tolerance ) {
var decimal = D ( value ) ;
return this . eq _tolerance ( decimal , tolerance ) || this . gt ( decimal ) ;
} ;
Decimal . prototype . pLog10 = function ( ) {
if ( this . lt ( Decimal . dZero ) ) { return Decimal . dZero ; }
return this . log10 ( ) ;
}
Decimal . prototype . absLog10 = function ( ) {
if ( this . sign === 0 )
{
return Decimal . dNaN ;
}
else if ( this . layer > 0 )
{
return FC ( Math . sign ( this . mag ) , this . layer - 1 , Math . abs ( this . mag ) ) ;
}
else
{
return FC ( 1 , 0 , Math . log10 ( this . mag ) ) ;
}
} ;
Decimal . prototype . log10 = function ( ) {
if ( this . sign <= 0 )
{
return Decimal . dNaN ;
}
else if ( this . layer > 0 )
{
return FC ( Math . sign ( this . mag ) , this . layer - 1 , Math . abs ( this . mag ) ) ;
}
else
{
return FC ( this . sign , 0 , Math . log10 ( this . mag ) ) ;
}
} ;
Decimal . prototype . log = function ( base ) {
base = D ( base ) ;
if ( this . sign <= 0 )
{
return Decimal . dNaN ;
}
if ( base . sign <= 0 )
{
return Decimal . dNaN ;
}
if ( base . sign === 1 && base . layer === 0 && base . mag === 1 )
{
return Decimal . dNaN ;
}
else if ( this . layer === 0 && base . layer === 0 )
{
return FC ( this . sign , 0 , Math . log ( this . mag ) / Math . log ( base . mag ) ) ;
}
return Decimal . div ( this . log10 ( ) , base . log10 ( ) ) ;
} ;
Decimal . prototype . log2 = function ( ) {
if ( this . sign <= 0 )
{
return Decimal . dNaN ;
}
else if ( this . layer === 0 )
{
return FC ( this . sign , 0 , Math . log2 ( this . mag ) ) ;
}
else if ( this . layer === 1 )
{
return FC ( Math . sign ( this . mag ) , 0 , Math . abs ( this . mag ) * 3.321928094887362 ) ; //log2(10)
}
else if ( this . layer === 2 )
{
return FC ( Math . sign ( this . mag ) , 1 , Math . abs ( this . mag ) + 0.5213902276543247 ) ; //-log10(log10(2))
}
else
{
return FC ( Math . sign ( this . mag ) , this . layer - 1 , Math . abs ( this . mag ) ) ;
}
} ;
Decimal . prototype . ln = function ( ) {
if ( this . sign <= 0 )
{
return Decimal . dNaN ;
}
else if ( this . layer === 0 )
{
return FC ( this . sign , 0 , Math . log ( this . mag ) ) ;
}
else if ( this . layer === 1 )
{
return FC ( Math . sign ( this . mag ) , 0 , Math . abs ( this . mag ) * 2.302585092994046 ) ; //ln(10)
}
else if ( this . layer === 2 )
{
return FC ( Math . sign ( this . mag ) , 1 , Math . abs ( this . mag ) + 0.36221568869946325 ) ; //log10(log10(e))
}
else
{
return FC ( Math . sign ( this . mag ) , this . layer - 1 , Math . abs ( this . mag ) ) ;
}
} ;
Decimal . prototype . logarithm = function ( base ) {
return this . log ( base ) ;
} ;
Decimal . prototype . pow = function ( value ) {
var decimal = D ( value ) ;
var a = this ;
var b = decimal ;
2021-09-08 03:53:54 +00:00
//special case: if a is 0, then return 0 (UNLESS b is 0, then return 1)
if ( a . sign === 0 ) { return b . eq ( 0 ) ? FC _NN ( 1 , 0 , 1 ) : a ; }
2020-08-26 14:16:23 +00:00
//special case: if a is 1, then return 1
if ( a . sign === 1 && a . layer === 0 && a . mag === 1 ) { return a ; }
//special case: if b is 0, then return 1
if ( b . sign === 0 ) { return FC _NN ( 1 , 0 , 1 ) ; }
//special case: if b is 1, then return a
if ( b . sign === 1 && b . layer === 0 && b . mag === 1 ) { return a ; }
var result = ( a . absLog10 ( ) . mul ( b ) ) . pow10 ( ) ;
2021-09-08 03:53:54 +00:00
if ( this . sign === - 1 && Math . abs ( b . toNumber ( ) % 2 ) === 1 ) {
2020-08-26 14:16:23 +00:00
return result . neg ( ) ;
}
return result ;
} ;
Decimal . prototype . pow10 = function ( ) {
/ *
There are four cases we need to consider :
1 ) positive sign , positive mag ( e15 , ee15 ) : + 1 layer ( e . g . 10 ^ 15 becomes e15 , 10 ^ e15 becomes ee15 )
2 ) negative sign , positive mag ( - e15 , - ee15 ) : + 1 layer but sign and mag sign are flipped ( e . g . 10 ^ - 15 becomes e - 15 , 10 ^ - e15 becomes ee - 15 )
3 ) positive sign , negative mag ( e - 15 , ee - 15 ) : layer 0 case would have been handled in the Math . pow check , so just return 1
4 ) negative sign , negative mag ( - e - 15 , - ee - 15 ) : layer 0 case would have been handled in the Math . pow check , so just return 1
* /
if ( ! Number . isFinite ( this . layer ) || ! Number . isFinite ( this . mag ) ) { return Decimal . dNaN ; }
var a = this ;
//handle layer 0 case - if no precision is lost just use Math.pow, else promote one layer
if ( a . layer === 0 )
{
var newmag = Math . pow ( 10 , a . sign * a . mag ) ;
if ( Number . isFinite ( newmag ) && Math . abs ( newmag ) > 0.1 ) { return FC ( 1 , 0 , newmag ) ; }
else
{
if ( a . sign === 0 ) { return Decimal . dOne ; }
else { a = FC _NN ( a . sign , a . layer + 1 , Math . log10 ( a . mag ) ) ; }
}
}
//handle all 4 layer 1+ cases individually
if ( a . sign > 0 && a . mag > 0 )
{
return FC ( a . sign , a . layer + 1 , a . mag ) ;
}
if ( a . sign < 0 && a . mag > 0 )
{
return FC ( - a . sign , a . layer + 1 , - a . mag ) ;
}
//both the negative mag cases are identical: one +/- rounding error
return Decimal . dOne ;
}
Decimal . prototype . pow _base = function ( value ) {
return D ( value ) . pow ( this ) ;
} ;
Decimal . prototype . root = function ( value ) {
var decimal = D ( value ) ;
return this . pow ( decimal . recip ( ) ) ;
}
Decimal . prototype . factorial = function ( ) {
if ( this . mag < 0 )
{
return this . toNumber ( ) . add ( 1 ) . gamma ( ) ;
}
else if ( this . layer === 0 )
{
return this . add ( 1 ) . gamma ( ) ;
}
else if ( this . layer === 1 )
{
return Decimal . exp ( Decimal . mul ( this , Decimal . ln ( this ) . sub ( 1 ) ) ) ;
}
else
{
return Decimal . exp ( this ) ;
}
} ;
//from HyperCalc source code
Decimal . prototype . gamma = function ( ) {
if ( this . mag < 0 )
{
return this . recip ( ) ;
}
else if ( this . layer === 0 )
{
if ( this . lt ( FC _NN ( 1 , 0 , 24 ) ) )
{
return D ( f _gamma ( this . sign * this . mag ) ) ;
}
var t = this . mag - 1 ;
var l = 0.9189385332046727 ; //0.5*Math.log(2*Math.PI)
l = ( l + ( ( t + 0.5 ) * Math . log ( t ) ) ) ;
l = 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 Decimal . exp ( l ) ;
}
l = l2 ;
np = np * n2 ;
lm = 360 * np ;
adj = 1 / lm ;
l2 = l - adj ;
if ( l2 === l )
{
return Decimal . exp ( l ) ;
}
l = l2 ;
np = np * n2 ;
lm = 1260 * np ;
var lt = 1 / lm ;
l = l + lt ;
np = np * n2 ;
lm = 1680 * np ;
lt = 1 / lm ;
l = l - lt ;
return Decimal . exp ( l ) ;
}
else if ( this . layer === 1 )
{
return Decimal . exp ( Decimal . mul ( this , Decimal . ln ( this ) . sub ( 1 ) ) ) ;
}
else
{
return Decimal . exp ( this ) ;
}
} ;
Decimal . prototype . lngamma = function ( ) {
return this . gamma ( ) . ln ( ) ;
}
Decimal . prototype . exp = function ( ) {
if ( this . mag < 0 ) { return Decimal . dOne ; }
if ( this . layer === 0 && this . mag <= 709.7 ) { return D ( Math . exp ( this . sign * this . mag ) ) ; }
else if ( this . layer === 0 ) { return FC ( 1 , 1 , this . sign * Math . log10 ( Math . E ) * this . mag ) ; }
else if ( this . layer === 1 ) { return FC ( 1 , 2 , this . sign * ( Math . log10 ( 0.4342944819032518 ) + this . mag ) ) ; }
else { return FC ( 1 , this . layer + 1 , this . sign * this . mag ) ; }
} ;
Decimal . prototype . sqr = function ( ) {
return this . pow ( 2 ) ;
} ;
Decimal . prototype . sqrt = function ( ) {
if ( this . layer === 0 ) { return D ( Math . sqrt ( this . sign * this . mag ) ) ; }
else if ( this . layer === 1 ) { return FC ( 1 , 2 , Math . log10 ( this . mag ) - 0.3010299956639812 ) ; }
else
{
var result = Decimal . div ( FC _NN ( this . sign , this . layer - 1 , this . mag ) , FC _NN ( 1 , 0 , 2 ) ) ;
result . layer += 1 ;
result . normalize ( ) ;
return result ;
}
} ;
Decimal . prototype . cube = function ( ) {
return this . pow ( 3 ) ;
} ;
Decimal . prototype . cbrt = function ( ) {
return this . pow ( 1 / 3 ) ;
} ;
//Tetration/tetrate: The result of exponentiating 'this' to 'this' 'height' times in a row. https://en.wikipedia.org/wiki/Tetration
//If payload != 1, then this is 'iterated exponentiation', the result of exping (payload) to base (this) (height) times. https://andydude.github.io/tetration/archives/tetration2/ident.html
//Works with negative and positive real heights.
Decimal . prototype . tetrate = function ( height = 2 , payload = FC _NN ( 1 , 0 , 1 ) ) {
if ( height === Number . POSITIVE _INFINITY )
{
//Formula for infinite height power tower.
var negln = Decimal . ln ( this ) . neg ( ) ;
return negln . lambertw ( ) . div ( negln ) ;
}
if ( height < 0 )
{
return Decimal . iteratedlog ( payload , this , - height ) ;
}
payload = D ( payload ) ;
var oldheight = height ;
height = Math . trunc ( height ) ;
var fracheight = oldheight - height ;
if ( fracheight !== 0 )
{
if ( payload . eq ( Decimal . dOne ) )
{
++ height ;
payload = new Decimal ( fracheight ) ;
}
else
{
if ( this . eq ( 10 ) )
{
payload = payload . layeradd10 ( fracheight ) ;
}
else
{
payload = payload . layeradd ( fracheight , this ) ;
}
}
}
for ( var i = 0 ; i < height ; ++ i )
{
payload = this . pow ( payload ) ;
//bail if we're NaN
if ( ! isFinite ( payload . layer ) || ! isFinite ( payload . mag ) ) { return payload ; }
//shortcut
if ( payload . layer - this . layer > 3 ) { return FC _NN ( payload . sign , payload . layer + ( height - i - 1 ) , payload . mag ) ; }
//give up after 100 iterations if nothing is happening
if ( i > 100 ) { return payload ; }
}
return payload ;
}
//iteratedexp/iterated exponentiation: - all cases handled in tetrate, so just call it
Decimal . prototype . iteratedexp = function ( height = 2 , payload = FC _NN ( 1 , 0 , 1 ) ) {
return this . tetrate ( height , payload ) ;
}
//iterated log/repeated log: The result of applying log(base) 'times' times in a row. Approximately equal to subtracting (times) from the number's slog representation. Equivalent to tetrating to a negative height.
//Works with negative and positive real heights.
Decimal . prototype . iteratedlog = function ( base = 10 , times = 1 ) {
if ( times < 0 )
{
return Decimal . tetrate ( base , - times , this ) ;
}
base = D ( base ) ;
var result = D ( this ) ;
var fulltimes = times ;
times = Math . trunc ( times ) ;
var fraction = fulltimes - times ;
if ( result . layer - base . layer > 3 )
{
var layerloss = Math . min ( times , ( result . layer - base . layer - 3 ) ) ;
times -= layerloss ;
result . layer -= layerloss ;
}
for ( var i = 0 ; i < times ; ++ i )
{
result = result . log ( base ) ;
//bail if we're NaN
if ( ! isFinite ( result . layer ) || ! isFinite ( result . mag ) ) { return result ; }
//give up after 100 iterations if nothing is happening
if ( i > 100 ) { return result ; }
}
//handle fractional part
if ( fraction > 0 && fraction < 1 )
{
if ( base . eq ( 10 ) )
{
result = result . layeradd10 ( - fraction ) ;
}
else
{
result = result . layeradd ( - fraction , base ) ;
}
}
return result ;
}
//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.
// https://en.wikipedia.org/wiki/Super-logarithm
Decimal . prototype . slog = function ( base = 10 ) {
if ( this . mag < 0 ) { return Decimal . dNegOne ; }
base = D ( base ) ;
var result = 0 ;
var copy = D ( this ) ;
if ( copy . layer - base . layer > 3 )
{
var layerloss = ( copy . layer - base . layer - 3 ) ;
result += layerloss ;
copy . layer -= layerloss ;
}
for ( var i = 0 ; i < 100 ; ++ i )
{
if ( copy . lt ( Decimal . dZero ) )
{
copy = Decimal . pow ( base , copy ) ;
result -= 1 ;
}
else if ( copy . lte ( Decimal . dOne ) )
{
return D ( result + copy . toNumber ( ) - 1 ) ; //<-- THIS IS THE CRITICAL FUNCTION
//^ Also have to change tetrate payload handling and layeradd10 if this is changed!
}
else
{
result += 1 ;
copy = Decimal . log ( copy , base ) ;
}
}
return D ( result ) ;
}
//Approximations taken from the excellent paper https://web.archive.org/web/20090201164836/http://tetration.itgo.com/paper.html !
//Not using for now unless I can figure out how to use it in all the related functions.
/ * v a r s l o g _ c r i t i c a l f u n c t i o n _ 1 = f u n c t i o n ( x , z ) {
z = z . toNumber ( ) ;
return - 1 + z ;
}
var slog _criticalfunction _2 = function ( x , z ) {
z = z . toNumber ( ) ;
var lnx = x . ln ( ) ;
if ( lnx . layer === 0 )
{
lnx = lnx . toNumber ( ) ;
return - 1 + z * 2 * lnx / ( 1 + lnx ) - z * z * ( 1 - lnx ) / ( 1 + lnx ) ;
}
else
{
var term1 = lnx . mul ( z * 2 ) . div ( lnx . add ( 1 ) ) ;
var term2 = Decimal . sub ( 1 , lnx ) . mul ( z * z ) . div ( lnx . add ( 1 ) ) ;
Decimal . dNegOne . add ( Decimal . sub ( term1 , term2 ) ) ;
}
}
var slog _criticalfunction _3 = function ( x , z ) {
z = z . toNumber ( ) ;
var lnx = x . ln ( ) ;
var lnx2 = lnx . sqr ( ) ;
var lnx3 = lnx . cube ( ) ;
if ( lnx . layer === 0 && lnx2 . layer === 0 && lnx3 . layer === 0 )
{
lnx = lnx . toNumber ( ) ;
lnx2 = lnx2 . toNumber ( ) ;
lnx3 = lnx3 . toNumber ( ) ;
var term1 = 6 * z * ( lnx + lnx3 ) ;
var term2 = 3 * z * z * ( 3 * lnx2 - 2 * lnx3 ) ;
var term3 = 2 * z * z * z * ( 1 - lnx - 2 * lnx2 + lnx3 ) ;
var top = term1 + term2 + term3 ;
var bottom = 2 + 4 * lnx + 5 * lnx2 + 2 * lnx3 ;
return - 1 + top / bottom ;
}
else
{
var term1 = ( lnx . add ( lnx3 ) ) . mul ( 6 * z ) ;
var term2 = ( lnx2 . mul ( 3 ) . sub ( lnx3 . mul ( 2 ) ) ) . mul ( 3 * z * z ) ;
var term3 = ( Decimal . dOne . sub ( lnx ) . sub ( lnx2 . mul ( 2 ) ) . add ( lnx3 ) ) . mul ( 2 * z * z * z ) ;
var top = term1 . add ( term2 ) . add ( term3 ) ;
var bottom = new Decimal ( 2 ) . add ( lnx . mul ( 4 ) ) . add ( lnx2 . mul ( 5 ) ) . add ( lnx3 . mul ( 2 ) ) ;
return Decimal . dNegOne . add ( top . div ( bottom ) ) ;
}
} * /
//Function for adding/removing layers from a Decimal, even fractional layers (e.g. its slog10 representation).
//Everything continues to use the linear approximation ATM.
Decimal . prototype . layeradd10 = function ( diff ) {
diff = Decimal . fromValue _noAlloc ( diff ) . toNumber ( ) ;
var result = D ( this ) ;
if ( diff >= 1 )
{
var layeradd = Math . trunc ( diff ) ;
diff -= layeradd ;
result . layer += layeradd ;
}
if ( diff <= - 1 )
{
var layeradd = Math . trunc ( diff ) ;
diff -= layeradd ;
result . layer += layeradd ;
if ( result . layer < 0 )
{
for ( var i = 0 ; i < 100 ; ++ i )
{
result . layer ++ ;
result . mag = Math . log10 ( result . mag ) ;
if ( ! isFinite ( result . mag ) ) { return result ; }
if ( result . layer >= 0 ) { break ; }
}
}
}
//layeradd10: like adding 'diff' to the number's slog(base) representation. Very similar to tetrate base 10 and iterated log base 10. Also equivalent to adding a fractional amount to the number's layer in its break_eternity.js representation.
if ( diff > 0 )
{
var subtractlayerslater = 0 ;
//Ironically, this edge case would be unnecessary if we had 'negative layers'.
while ( Number . isFinite ( result . mag ) && result . mag < 10 )
{
result . mag = Math . pow ( 10 , result . mag ) ;
++ subtractlayerslater ;
}
//A^(10^B) === C, solve for B
//B === log10(logA(C))
if ( result . mag > 1e10 )
{
result . mag = Math . log10 ( result . mag ) ;
result . layer ++ ;
}
//Note that every integer slog10 value, the formula changes, so if we're near such a number, we have to spend exactly enough layerdiff to hit it, and then use the new formula.
var diffToNextSlog = Math . log10 ( Math . log ( 1e10 ) / Math . log ( result . mag ) , 10 ) ;
if ( diffToNextSlog < diff )
{
result . mag = Math . log10 ( 1e10 ) ;
result . layer ++ ;
diff -= diffToNextSlog ;
}
result . mag = Math . pow ( result . mag , Math . pow ( 10 , diff ) ) ;
while ( subtractlayerslater > 0 )
{
result . mag = Math . log10 ( result . mag ) ;
-- subtractlayerslater ;
}
}
else if ( diff < 0 )
{
var subtractlayerslater = 0 ;
while ( Number . isFinite ( result . mag ) && result . mag < 10 )
{
result . mag = Math . pow ( 10 , result . mag ) ;
++ subtractlayerslater ;
}
if ( result . mag > 1e10 )
{
result . mag = Math . log10 ( result . mag ) ;
result . layer ++ ;
}
var diffToNextSlog = Math . log10 ( 1 / Math . log10 ( result . mag ) ) ;
if ( diffToNextSlog > diff )
{
result . mag = 1e10 ;
result . layer -- ;
diff -= diffToNextSlog ;
}
result . mag = Math . pow ( result . mag , Math . pow ( 10 , diff ) ) ;
while ( subtractlayerslater > 0 )
{
result . mag = Math . log10 ( result . mag ) ;
-- subtractlayerslater ;
}
}
while ( result . layer < 0 )
{
result . layer ++ ;
result . mag = Math . log10 ( result . mag ) ;
}
result . normalize ( ) ;
return result ;
}
//layeradd: like adding 'diff' to the number's slog(base) representation. Very similar to tetrate base 'base' and iterated log base 'base'.
Decimal . prototype . layeradd = function ( diff , base ) {
var slogthis = this . slog ( base ) . toNumber ( ) ;
var slogdest = slogthis + diff ;
if ( slogdest >= 0 )
{
return Decimal . tetrate ( base , slogdest ) ;
}
else if ( ! Number . isFinite ( slogdest ) )
{
return Decimal . dNaN ;
}
else if ( slogdest >= - 1 )
{
return Decimal . log ( Decimal . tetrate ( base , slogdest + 1 ) , base ) ;
}
else
{
Decimal . log ( Decimal . log ( Decimal . tetrate ( base , slogdest + 2 ) , base ) , base ) ;
}
}
//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
Decimal . prototype . lambertw = function ( ) {
if ( this . lt ( - 0.3678794411710499 ) )
{
throw Error ( "lambertw is unimplemented for results less than -1, sorry!" ) ;
}
else if ( this . mag < 0 )
{
return D ( f _lambertw ( this . toNumber ( ) ) ) ;
}
else if ( this . layer === 0 )
{
return D ( f _lambertw ( this . sign * this . mag ) ) ;
}
else if ( this . layer === 1 )
{
return d _lambertw ( this ) ;
}
else if ( this . layer === 2 )
{
return d _lambertw ( this ) ;
}
if ( this . layer >= 3 )
{
return FC _NN ( this . sign , this . layer - 1 , this . mag ) ;
}
}
//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 = 1e-10 ) {
var w ;
var ew , wew , wewz , wn ;
if ( ! Number . isFinite ( z . mag ) ) { return z ; }
if ( z === 0 )
{
return z ;
}
if ( z === 1 )
{
//Split out this case because the asymptotic series blows up
return OMEGA ;
}
var absz = Decimal . abs ( z ) ;
//Get an initial guess for Halley's method
w = Decimal . ln ( z ) ;
//Halley's method; see 5.9 in [1]
for ( var i = 0 ; i < 100 ; ++ i )
{
ew = Decimal . exp ( - w ) ;
wewz = w . sub ( z . mul ( ew ) ) ;
wn = w . sub ( wewz . div ( w . add ( 1 ) . sub ( ( w . add ( 2 ) ) . mul ( wewz ) . div ( ( Decimal . mul ( 2 , w ) . add ( 2 ) ) ) ) ) ) ;
if ( Decimal . abs ( wn . sub ( w ) ) . lt ( Decimal . abs ( wn ) . mul ( tol ) ) )
{
return wn ;
}
else
{
w = wn ;
}
}
throw Error ( "Iteration failed to converge: " + z ) ;
//return Decimal.dNaN;
}
//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
Decimal . prototype . ssqrt = function ( ) {
if ( this . sign == 1 && this . layer >= 3 )
{
return FC _NN ( this . sign , this . layer - 1 , this . mag )
}
var lnx = this . ln ( ) ;
return lnx . div ( lnx . lambertw ( ) ) ;
}
/ *
Unit tests for tetrate / iteratedexp / iteratedlog / layeradd10 / layeradd / slog :
for ( var i = 0 ; i < 1000 ; ++ i )
{
var first = Math . random ( ) * 100 ;
var both = Math . random ( ) * 100 ;
var expected = first + both + 1 ;
var result = new Decimal ( 10 ) . layeradd10 ( first ) . layeradd10 ( both ) . slog ( ) ;
if ( Number . isFinite ( result . mag ) && ! Decimal . eq _tolerance ( expected , result ) )
{
console . log ( first + ", " + both ) ;
}
}
for ( var i = 0 ; i < 1000 ; ++ i )
{
var first = Math . random ( ) * 100 ;
var both = Math . random ( ) * 100 ;
first += both ;
var expected = first - both + 1 ;
var result = new Decimal ( 10 ) . layeradd10 ( first ) . layeradd10 ( - both ) . slog ( ) ;
if ( Number . isFinite ( result . mag ) && ! Decimal . eq _tolerance ( expected , result ) )
{
console . log ( first + ", " + both ) ;
}
}
for ( var i = 0 ; i < 1000 ; ++ i )
{
var first = Math . random ( ) * 100 ;
var both = Math . random ( ) * 100 ;
var base = Math . random ( ) * 8 + 2 ;
var expected = first + both + 1 ;
var result = new Decimal ( base ) . layeradd ( first , base ) . layeradd ( both , base ) . slog ( base ) ;
if ( Number . isFinite ( result . mag ) && ! Decimal . eq _tolerance ( expected , result ) )
{
console . log ( first + ", " + both ) ;
}
}
for ( var i = 0 ; i < 1000 ; ++ i )
{
var first = Math . random ( ) * 100 ;
var both = Math . random ( ) * 100 ;
var base = Math . random ( ) * 8 + 2 ;
first += both ;
var expected = first - both + 1 ;
var result = new Decimal ( base ) . layeradd ( first , base ) . layeradd ( - both , base ) . slog ( base ) ;
if ( Number . isFinite ( result . mag ) && ! Decimal . eq _tolerance ( expected , result ) )
{
console . log ( first + ", " + both ) ;
}
}
for ( var i = 0 ; i < 1000 ; ++ i )
{
var first = Math . round ( ( Math . random ( ) * 30 ) ) / 10 ;
var both = Math . round ( ( Math . random ( ) * 30 ) ) / 10 ;
var tetrateonly = Decimal . tetrate ( 10 , first ) ;
var tetrateandlog = Decimal . tetrate ( 10 , first + both ) . iteratedlog ( 10 , both ) ;
if ( ! Decimal . eq _tolerance ( tetrateonly , tetrateandlog ) )
{
console . log ( first + ", " + both ) ;
}
}
for ( var i = 0 ; i < 1000 ; ++ i )
{
var first = Math . round ( ( Math . random ( ) * 30 ) ) / 10 ;
var both = Math . round ( ( Math . random ( ) * 30 ) ) / 10 ;
var base = Math . random ( ) * 8 + 2 ;
var tetrateonly = Decimal . tetrate ( base , first ) ;
var tetrateandlog = Decimal . tetrate ( base , first + both ) . iteratedlog ( base , both ) ;
if ( ! Decimal . eq _tolerance ( tetrateonly , tetrateandlog ) )
{
console . log ( first + ", " + both ) ;
}
}
for ( var i = 0 ; i < 1000 ; ++ i )
{
var first = Math . round ( ( Math . random ( ) * 30 ) ) / 10 ;
var both = Math . round ( ( Math . random ( ) * 30 ) ) / 10 ;
var base = Math . random ( ) * 8 + 2 ;
var tetrateonly = Decimal . tetrate ( base , first , base ) ;
var tetrateandlog = Decimal . tetrate ( base , first + both , base ) . iteratedlog ( base , both ) ;
if ( ! Decimal . eq _tolerance ( tetrateonly , tetrateandlog ) )
{
console . log ( first + ", " + both ) ;
}
}
for ( var i = 0 ; i < 1000 ; ++ i )
{
var xex = new Decimal ( - 0.3678794411710499 + Math . random ( ) * 100 ) ;
var x = Decimal . lambertw ( xex ) ;
if ( ! Decimal . eq _tolerance ( xex , x . mul ( Decimal . exp ( x ) ) ) )
{
console . log ( xex ) ;
}
}
for ( var i = 0 ; i < 1000 ; ++ i )
{
var xex = new Decimal ( - 0.3678794411710499 + Math . exp ( Math . random ( ) * 100 ) ) ;
var x = Decimal . lambertw ( xex ) ;
if ( ! Decimal . eq _tolerance ( xex , x . mul ( Decimal . exp ( x ) ) ) )
{
console . log ( xex ) ;
}
}
for ( var i = 0 ; i < 1000 ; ++ i )
{
var a = Decimal . randomDecimalForTesting ( Math . random ( ) > 0.5 ? 0 : 1 ) ;
var b = Decimal . randomDecimalForTesting ( Math . random ( ) > 0.5 ? 0 : 1 ) ;
if ( Math . random ( ) > 0.5 ) { a = a . recip ( ) ; }
if ( Math . random ( ) > 0.5 ) { b = b . recip ( ) ; }
var c = a . add ( b ) . toNumber ( ) ;
if ( Number . isFinite ( c ) && ! Decimal . eq _tolerance ( c , a . toNumber ( ) + b . toNumber ( ) ) )
{
console . log ( a + ", " + b ) ;
}
}
for ( var i = 0 ; i < 100 ; ++ i )
{
var a = Decimal . randomDecimalForTesting ( Math . round ( Math . random ( ) * 4 ) ) ;
var b = Decimal . randomDecimalForTesting ( Math . round ( Math . random ( ) * 4 ) ) ;
if ( Math . random ( ) > 0.5 ) { a = a . recip ( ) ; }
if ( Math . random ( ) > 0.5 ) { b = b . recip ( ) ; }
var c = a . mul ( b ) . toNumber ( ) ;
if ( Number . isFinite ( c ) && Number . isFinite ( a . toNumber ( ) ) && Number . isFinite ( b . toNumber ( ) ) && a . toNumber ( ) != 0 && b . toNumber ( ) != 0 && c != 0 && ! Decimal . eq _tolerance ( c , a . toNumber ( ) * b . toNumber ( ) ) )
{
console . log ( "Test 1: " + a + ", " + b ) ;
}
else if ( ! Decimal . mul ( a . recip ( ) , b . recip ( ) ) . eq _tolerance ( Decimal . mul ( a , b ) . recip ( ) ) )
{
console . log ( "Test 3: " + a + ", " + b ) ;
}
}
for ( var i = 0 ; i < 10 ; ++ i )
{
var a = Decimal . randomDecimalForTesting ( Math . round ( Math . random ( ) * 4 ) ) ;
var b = Decimal . randomDecimalForTesting ( Math . round ( Math . random ( ) * 4 ) ) ;
if ( Math . random ( ) > 0.5 && a . sign !== 0 ) { a = a . recip ( ) ; }
if ( Math . random ( ) > 0.5 && b . sign !== 0 ) { b = b . recip ( ) ; }
var c = a . pow ( b ) ;
var d = a . root ( b . recip ( ) ) ;
var e = a . pow ( b . recip ( ) ) ;
var f = a . root ( b ) ;
if ( ! c . eq _tolerance ( d ) && a . sign !== 0 && b . sign !== 0 )
{
console . log ( "Test 1: " + a + ", " + b ) ;
}
if ( ! e . eq _tolerance ( f ) && a . sign !== 0 && b . sign !== 0 )
{
console . log ( "Test 2: " + a + ", " + b ) ;
}
}
for ( var i = 0 ; i < 10 ; ++ i )
{
var a = Math . round ( Math . random ( ) * 18 - 9 ) ;
var b = Math . round ( Math . random ( ) * 100 - 50 ) ;
var c = Math . round ( Math . random ( ) * 18 - 9 ) ;
var d = Math . round ( Math . random ( ) * 100 - 50 ) ;
console . log ( "Decimal.pow(Decimal.fromMantissaExponent(" + a + ", " + b + "), Decimal.fromMantissaExponent(" + c + ", " + d + ")).toString()" ) ;
}
* /
//Pentation/pentate: The result of tetrating 'height' times in a row. An absurdly strong operator - Decimal.pentate(2, 4.28) and Decimal.pentate(10, 2.37) are already too huge for break_eternity.js!
// https://en.wikipedia.org/wiki/Pentation
Decimal . prototype . pentate = function ( height = 2 , payload = FC _NN ( 1 , 0 , 1 ) ) {
payload = D ( payload ) ;
var oldheight = height ;
height = Math . trunc ( height ) ;
var fracheight = oldheight - height ;
//I have no idea if this is a meaningful approximation for pentation to continuous heights, but it is monotonic and continuous.
if ( fracheight !== 0 )
{
if ( payload . eq ( Decimal . dOne ) )
{
++ height ;
payload = new Decimal ( fracheight ) ;
}
else
{
if ( this . eq ( 10 ) )
{
payload = payload . layeradd10 ( fracheight ) ;
}
else
{
payload = payload . layeradd ( fracheight , this ) ;
}
}
}
for ( var i = 0 ; i < height ; ++ i )
{
payload = this . tetrate ( payload ) ;
//bail if we're NaN
if ( ! isFinite ( payload . layer ) || ! isFinite ( payload . mag ) ) { return payload ; }
//give up after 10 iterations if nothing is happening
if ( i > 10 ) { return payload ; }
}
return payload ;
}
// trig functions!
Decimal . prototype . sin = function ( ) {
if ( this . mag < 0 ) { return this ; }
if ( this . layer === 0 ) { return D ( Math . sin ( this . sign * this . mag ) ) ; }
return FC _NN ( 0 , 0 , 0 ) ;
} ;
Decimal . prototype . cos = function ( ) {
if ( this . mag < 0 ) { return Decimal . dOne ; }
if ( this . layer === 0 ) { return D ( Math . cos ( this . sign * this . mag ) ) ; }
return FC _NN ( 0 , 0 , 0 ) ;
} ;
Decimal . prototype . tan = function ( ) {
if ( this . mag < 0 ) { return this ; }
if ( this . layer === 0 ) { return D ( Math . tan ( this . sign * this . mag ) ) ; }
return FC _NN ( 0 , 0 , 0 ) ;
} ;
Decimal . prototype . asin = function ( ) {
if ( this . mag < 0 ) { return this ; }
if ( this . layer === 0 ) { return D ( Math . asin ( this . sign * this . mag ) ) ; }
return FC _NN ( Number . NaN , Number . NaN , Number . NaN ) ;
} ;
Decimal . prototype . acos = function ( ) {
if ( this . mag < 0 ) { return D ( Math . acos ( this . toNumber ( ) ) ) ; }
if ( this . layer === 0 ) { return D ( Math . acos ( this . sign * this . mag ) ) ; }
return FC _NN ( Number . NaN , Number . NaN , Number . NaN ) ;
} ;
Decimal . prototype . atan = function ( ) {
if ( this . mag < 0 ) { return this ; }
if ( this . layer === 0 ) { return D ( Math . atan ( this . sign * this . mag ) ) ; }
return D ( Math . atan ( this . sign * 1.8 e308 ) ) ;
} ;
Decimal . prototype . sinh = function ( ) {
return this . exp ( ) . sub ( this . negate ( ) . exp ( ) ) . div ( 2 ) ;
} ;
Decimal . prototype . cosh = function ( ) {
return this . exp ( ) . add ( this . negate ( ) . exp ( ) ) . div ( 2 ) ;
} ;
Decimal . prototype . tanh = function ( ) {
return this . sinh ( ) . div ( this . cosh ( ) ) ;
} ;
Decimal . prototype . asinh = function ( ) {
return Decimal . ln ( this . add ( this . sqr ( ) . add ( 1 ) . sqrt ( ) ) ) ;
} ;
Decimal . prototype . acosh = function ( ) {
return Decimal . ln ( this . add ( this . sqr ( ) . sub ( 1 ) . sqrt ( ) ) ) ;
} ;
Decimal . prototype . atanh = function ( ) {
if ( this . abs ( ) . gte ( 1 ) ) {
return FC _NN ( Number . NaN , Number . NaN , Number . NaN ) ;
}
return Decimal . ln ( this . add ( 1 ) . div ( D ( 1 ) . sub ( this ) ) ) . div ( 2 ) ;
} ;
/ * *
* Joke function from Realm Grinder
* /
Decimal . prototype . ascensionPenalty = function ( ascensions ) {
if ( ascensions === 0 ) {
return this ;
}
return this . root ( Decimal . pow ( 10 , ascensions ) ) ;
} ;
/ * *
* Joke function from Cookie Clicker . It 's ' egg '
* /
Decimal . prototype . egg = function ( ) {
return this . add ( 9 ) ;
} ;
Decimal . prototype . lessThanOrEqualTo = function ( other ) {
return this . cmp ( other ) < 1 ;
} ;
Decimal . prototype . lessThan = function ( other ) {
return this . cmp ( other ) < 0 ;
} ;
Decimal . prototype . greaterThanOrEqualTo = function ( other ) {
return this . cmp ( other ) > - 1 ;
} ;
Decimal . prototype . greaterThan = function ( other ) {
return this . cmp ( other ) > 0 ;
} ;
return Decimal ;
} ( ) ;
Decimal . dZero = FC _NN ( 0 , 0 , 0 ) ;
Decimal . dOne = FC _NN ( 1 , 0 , 1 ) ;
Decimal . dNegOne = FC _NN ( - 1 , 0 , 1 ) ;
Decimal . dTwo = FC _NN ( 1 , 0 , 2 ) ;
Decimal . dTen = FC _NN ( 1 , 0 , 10 ) ;
Decimal . dNaN = FC _NN ( Number . NaN , Number . NaN , Number . NaN ) ;
Decimal . dInf = FC _NN ( 1 , Number . POSITIVE _INFINITY , Number . POSITIVE _INFINITY ) ;
Decimal . dNegInf = FC _NN ( - 1 , Number . NEGATIVE _INFINITY , Number . NEGATIVE _INFINITY ) ;
Decimal . dNumberMax = FC ( 1 , 0 , Number . MAX _VALUE ) ;
Decimal . dNumberMin = FC ( 1 , 0 , Number . MIN _VALUE ) ;
return Decimal ;
2021-09-08 03:53:54 +00:00
} ) ) ;