import BigNumber , { bn } from '../big-number' ; const ONE_18 = bn ( '1000000000000000000' ) ; const ONE_20 = bn ( '100000000000000000000' ) ; const ONE_36 = bn ( '1000000000000000000000000000000000000' ) ; const MAX_NATURAL_EXPONENT = bn ( '130000000000000000000' ) ; const MIN_NATURAL_EXPONENT = bn ( '-41000000000000000000' ) ; const LN_36_LOWER_BOUND = ONE_18 . minus ( bn ( '100000000000000000' ) ) ; const LN_36_UPPER_BOUND = ONE_18 . plus ( bn ( '100000000000000000' ) ) ; const MILD_EXPONENT_BOUND = bn ( 2 ) . pow ( 254 ) . idiv ( ONE_20 ) ; const x0 = bn ( '128000000000000000000' ) ; const a0 = bn ( '38877084059945950922200000000000000000000000000000000000' ) ; const x1 = bn ( '64000000000000000000' ) ; const a1 = bn ( '6235149080811616882910000000' ) ; const x2 = bn ( '3200000000000000000000' ) ; const a2 = bn ( '7896296018268069516100000000000000' ) ; const x3 = bn ( '1600000000000000000000' ) ; const a3 = bn ( '888611052050787263676000000' ) ; const x4 = bn ( '800000000000000000000' ) ; const a4 = bn ( '298095798704172827474000' ) ; const x5 = bn ( '400000000000000000000' ) ; const a5 = bn ( '5459815003314423907810' ) ; const x6 = bn ( '200000000000000000000' ) ; const a6 = bn ( '738905609893065022723' ) ; const x7 = bn ( '100000000000000000000' ) ; const a7 = bn ( '271828182845904523536' ) ; const x8 = bn ( '50000000000000000000' ) ; const a8 = bn ( '164872127070012814685' ) ; const x9 = bn ( '25000000000000000000' ) ; const a9 = bn ( '128402541668774148407' ) ; const x10 = bn ( '12500000000000000000' ) ; const a10 = bn ( '113314845306682631683' ) ; const x11 = bn ( '6250000000000000000' ) ; const a11 = bn ( '106449445891785942956' ) ; export const pow = ( x , y ) : BigNumber => { if ( y . isZero ( ) ) { return ONE_18 ; } if ( x . isZero ( ) ) { return bn ( 0 ) ; } if ( x . gte ( bn ( 2 ) . pow ( 255 ) ) ) { throw new Error ( 'X_OUT_OF_BOUNDS' ) ; } if ( y . gte ( MILD_EXPONENT_BOUND ) ) { throw new Error ( 'Y_OUT_OF_BOUNDS' ) ; } let logx_times_y ; if ( LN_36_LOWER_BOUND . lt ( x ) && x . lt ( LN_36_UPPER_BOUND ) ) { let ln_36_x = _ln_36 ( x ) ; logx_times_y = ln_36_x . idiv ( ONE_18 ) . times ( y ) . plus ( ln_36_x . mod ( ONE_18 ) . times ( y ) . idiv ( ONE_18 ) ) ; } else { logx_times_y = _ln ( x ) . times ( y ) ; } logx_times_y = logx_times_y . idiv ( ONE_18 ) ; if ( logx_times_y . lt ( MIN_NATURAL_EXPONENT ) || logx_times_y . gt ( MAX_NATURAL_EXPONENT ) ) { throw new Error ( 'PRODUCT_OUT_OF_BOUNDS' ) ; } return exp ( logx_times_y ) ; } ; export const exp = ( x ) : BigNumber => { if ( x . lt ( MIN_NATURAL_EXPONENT ) || x . gt ( MAX_NATURAL_EXPONENT ) ) { throw new Error ( 'INVALID_EXPONENT' ) ; } if ( x . lt ( 0 ) ) { return ONE_18 . times ( ONE_18 ) . idiv ( exp ( x . negated ( ) ) ) ; } let firstAN ; if ( x . gte ( x0 ) ) { x = x . minus ( x0 ) ; firstAN = a0 ; } else if ( x . gte ( x1 ) ) { x = x . minus ( x1 ) ; firstAN = a1 ; } else { firstAN = bn ( 1 ) ; } x = x . times ( 100 ) ; let product = ONE_20 ; if ( x . gte ( x2 ) ) { x = x . minus ( x2 ) ; product = product . times ( a2 ) . idiv ( ONE_20 ) ; } if ( x . gte ( x3 ) ) { x = x . minus ( x3 ) ; product = product . times ( a3 ) . idiv ( ONE_20 ) ; } if ( x . gte ( x4 ) ) { x = x . minus ( x4 ) ; product = product . times ( a4 ) . idiv ( ONE_20 ) ; } if ( x . gte ( x5 ) ) { x = x . minus ( x5 ) ; product = product . times ( a5 ) . idiv ( ONE_20 ) ; } if ( x . gte ( x6 ) ) { x = x . minus ( x6 ) ; product = product . times ( a6 ) . idiv ( ONE_20 ) ; } if ( x . gte ( x7 ) ) { x = x . minus ( x7 ) ; product = product . times ( a7 ) . idiv ( ONE_20 ) ; } if ( x . gte ( x8 ) ) { x = x . minus ( x8 ) ; product = product . times ( a8 ) . idiv ( ONE_20 ) ; } if ( x . gte ( x9 ) ) { x = x . minus ( x9 ) ; product = product . times ( a9 ) . idiv ( ONE_20 ) ; } let seriesSum = ONE_20 ; let term ; term = x ; seriesSum = seriesSum . plus ( term ) ; term = term . times ( x ) . idiv ( ONE_20 ) . idiv ( 2 ) ; seriesSum = seriesSum . plus ( term ) ; term = term . times ( x ) . idiv ( ONE_20 ) . idiv ( 3 ) ; seriesSum = seriesSum . plus ( term ) ; term = term . times ( x ) . idiv ( ONE_20 ) . idiv ( 4 ) ; seriesSum = seriesSum . plus ( term ) ; term = term . times ( x ) . idiv ( ONE_20 ) . idiv ( 5 ) ; seriesSum = seriesSum . plus ( term ) ; term = term . times ( x ) . idiv ( ONE_20 ) . idiv ( 6 ) ; seriesSum = seriesSum . plus ( term ) ; term = term . times ( x ) . idiv ( ONE_20 ) . idiv ( 7 ) ; seriesSum = seriesSum . plus ( term ) ; term = term . times ( x ) . idiv ( ONE_20 ) . idiv ( 8 ) ; seriesSum = seriesSum . plus ( term ) ; term = term . times ( x ) . idiv ( ONE_20 ) . idiv ( 9 ) ; seriesSum = seriesSum . plus ( term ) ; term = term . times ( x ) . idiv ( ONE_20 ) . idiv ( 10 ) ; seriesSum = seriesSum . plus ( term ) ; term = term . times ( x ) . idiv ( ONE_20 ) . idiv ( 11 ) ; seriesSum = seriesSum . plus ( term ) ; term = term . times ( x ) . idiv ( ONE_20 ) . idiv ( 12 ) ; seriesSum = seriesSum . plus ( term ) ; return product . times ( seriesSum ) . idiv ( ONE_20 ) . times ( firstAN ) . idiv ( 100 ) ; } ; export const log = ( arg , base ) : BigNumber => { let logBase ; if ( LN_36_LOWER_BOUND . lt ( base ) && base . lt ( LN_36_UPPER_BOUND ) ) { logBase = _ln_36 ( base ) ; } else { logBase = _ln ( base ) . times ( ONE_18 ) ; } let logArg ; if ( LN_36_LOWER_BOUND . lt ( arg ) && arg . lt ( LN_36_UPPER_BOUND ) ) { logArg = _ln_36 ( arg ) ; } else { logArg = _ln ( arg ) . times ( ONE_18 ) ; } return logArg . times ( ONE_18 ) . idiv ( logBase ) ; } ; export const ln = ( a ) : BigNumber => { if ( a . lte ( 0 ) ) { throw new Error ( 'OUT_OF_BOUNDS' ) ; } if ( LN_36_LOWER_BOUND . lt ( a ) && a . lt ( LN_36_UPPER_BOUND ) ) { return _ln_36 ( a ) . idiv ( ONE_18 ) ; } else { return _ln ( a ) ; } } ; const _ln = ( a ) : BigNumber => { if ( a . lt ( ONE_18 ) ) { return _ln ( ONE_18 . times ( ONE_18 ) . idiv ( a ) ) . negated ( ) ; } let sum = bn ( 0 ) ; if ( a . gte ( a0 . times ( ONE_18 ) ) ) { a = a . idiv ( a0 ) ; sum = sum . plus ( x0 ) ; } if ( a . gte ( a1 . times ( ONE_18 ) ) ) { a = a . idiv ( a1 ) ; sum = sum . plus ( x1 ) ; } sum = sum . times ( 100 ) ; a = a . times ( 100 ) ; if ( a . gte ( a2 ) ) { a = a . times ( ONE_20 ) . idiv ( a2 ) ; sum = sum . plus ( x2 ) ; } if ( a . gte ( a3 ) ) { a = a . times ( ONE_20 ) . idiv ( a3 ) ; sum = sum . plus ( x3 ) ; } if ( a . gte ( a4 ) ) { a = a . times ( ONE_20 ) . idiv ( a4 ) ; sum = sum . plus ( x4 ) ; } if ( a . gte ( a5 ) ) { a = a . times ( ONE_20 ) . idiv ( a5 ) ; sum = sum . plus ( x5 ) ; } if ( a . gte ( a6 ) ) { a = a . times ( ONE_20 ) . idiv ( a6 ) ; sum = sum . plus ( x6 ) ; } if ( a . gte ( a7 ) ) { a = a . times ( ONE_20 ) . idiv ( a7 ) ; sum = sum . plus ( x7 ) ; } if ( a . gte ( a8 ) ) { a = a . times ( ONE_20 ) . idiv ( a8 ) ; sum = sum . plus ( x8 ) ; } if ( a . gte ( a9 ) ) { a = a . times ( ONE_20 ) . idiv ( a9 ) ; sum = sum . plus ( x9 ) ; } if ( a . gte ( a10 ) ) { a = a . times ( ONE_20 ) . idiv ( a10 ) ; sum = sum . plus ( x10 ) ; } if ( a . gte ( a11 ) ) { a = a . times ( ONE_20 ) . idiv ( a11 ) ; sum = sum . plus ( x11 ) ; } const z = a . minus ( ONE_20 ) . times ( ONE_20 ) . idiv ( a . plus ( ONE_20 ) ) ; const z_squared = z . times ( z ) . idiv ( ONE_20 ) ; let num = z ; let seriesSum = num ; num = num . times ( z_squared ) . idiv ( ONE_20 ) ; seriesSum = seriesSum . plus ( num . idiv ( 3 ) ) ; num = num . times ( z_squared ) . idiv ( ONE_20 ) ; seriesSum = seriesSum . plus ( num . idiv ( 5 ) ) ; num = num . times ( z_squared ) . idiv ( ONE_20 ) ; seriesSum = seriesSum . plus ( num . idiv ( 7 ) ) ; num = num . times ( z_squared ) . idiv ( ONE_20 ) ; seriesSum = seriesSum . plus ( num . idiv ( 9 ) ) ; num = num . times ( z_squared ) . idiv ( ONE_20 ) ; seriesSum = seriesSum . plus ( num . idiv ( 11 ) ) ; seriesSum = seriesSum . times ( 2 ) ; return sum . plus ( seriesSum ) . idiv ( 100 ) ; } ; const _ln_36 = ( x ) : BigNumber => { x = x . times ( ONE_18 ) ; const z = x . minus ( ONE_36 ) . times ( ONE_36 ) . idiv ( x . plus ( ONE_36 ) ) ; const z_squared = z . times ( z ) . idiv ( ONE_36 ) ; let num = z ; let seriesSum = num ; num = num . times ( z_squared ) . idiv ( ONE_36 ) ; seriesSum = seriesSum . plus ( num . idiv ( 3 ) ) ; num = num . times ( z_squared ) . idiv ( ONE_36 ) ; seriesSum = seriesSum . plus ( num . idiv ( 5 ) ) ; num = num . times ( z_squared ) . idiv ( ONE_36 ) ; seriesSum = seriesSum . plus ( num . idiv ( 7 ) ) ; num = num . times ( z_squared ) . idiv ( ONE_36 ) ; seriesSum = seriesSum . plus ( num . idiv ( 9 ) ) ; num = num . times ( z_squared ) . idiv ( ONE_36 ) ; seriesSum = seriesSum . plus ( num . idiv ( 11 ) ) ; num = num . times ( z_squared ) . idiv ( ONE_36 ) ; seriesSum = seriesSum . plus ( num . idiv ( 13 ) ) ; num = num . times ( z_squared ) . idiv ( ONE_36 ) ; seriesSum = seriesSum . plus ( num . idiv ( 15 ) ) ; return seriesSum . times ( 2 ) ; } ;