From e02587a173afec9258acc442649db9b5e3601f03 Mon Sep 17 00:00:00 2001 From: Michael Mclaughlin Date: Wed, 4 Jun 2014 23:59:07 +0100 Subject: [PATCH] v3.0.0 --- README.md | 15 +- decimal.js | 2068 +++++++++++++++++++-------------- decimal.min.js | 4 +- doc/API.html | 123 +- package.json | 4 +- test/browser/single-test.html | 1 - test/random.js | 130 +-- test/toFixed.js | 30 +- 8 files changed, 1321 insertions(+), 1054 deletions(-) diff --git a/README.md b/README.md index 6cd382c..c336d34 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ An arbitrary-precision Decimal type for JavaScript. - Simple API but full-featured - Replicates the `toExponential`, `toFixed`, `toPrecision` and `toString` methods of JavaScript's Number type - Includes a `toFraction` and correctly-rounded `exp`, `ln`, `log` and `sqrt` functions - - Supports non-integer powers (although performance is limited) + - Supports non-integer powers - Works with numbers with or without fraction digits in bases from 2 to 64 inclusive - Stores values in an accessible decimal floating-point format - No dependencies @@ -136,12 +136,12 @@ Many of the methods of JavaScript's Math object are also replicated Decimal.sqrt('6.98372465832e+9823') // '8.3568682281821340204e+4911' Decimal.pow(2, 0.0979843) // '1.0702770511687781839' -The value of a Decimal is stored in a decimal floating point format in terms of a coefficient, exponent and sign. +The value of a Decimal is stored in a floating point format in terms of a coefficient, exponent and sign. - x = new Decimal(-123.456); - x.c // '1,2,3,4,5,6' coefficient (i.e. significand) - x.e // 2 exponent - x.s // -1 sign + x = new Decimal(-12345.67); + x.c // [ 12345, 6700000 ] coefficient (base 10000) + x.e // 4 exponent (base 10) + x.s // -1 sign For further information see the [API](http://mikemcl.github.io/decimal.js/) reference in the *doc* directory. @@ -198,6 +198,9 @@ See LICENCE. ## Change Log +####3.0.0 +* 4/06/2014 `random` simplified. Major internal changes mean the properties of a Decimal must now be considered read-only. + ####2.1.0 * 4/06/2014 Amend UMD diff --git a/decimal.js b/decimal.js index 52ee4dc..fd638fb 100644 --- a/decimal.js +++ b/decimal.js @@ -1,10 +1,10 @@ -/*! decimal.js v2.1.0 https://github.com/MikeMcl/decimal.js/LICENCE */ +/*! decimal.js v3.0.0 https://github.com/MikeMcl/decimal.js/LICENCE */ ;(function (global) { 'use strict'; /* - * decimal.js v2.1.0 + * decimal.js v3.0.0 * An arbitrary-precision Decimal type for JavaScript. * https://github.com/MikeMcl/decimal.js * Copyright (c) 2014 Michael Mclaughlin @@ -17,25 +17,29 @@ outOfRange, id = 0, external = true, + mathfloor = Math.floor, + mathpow = Math.pow, + BASE = 1e7, + LOGBASE = 7, NUMERALS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_', P = {}, /* The maximum exponent magnitude. - The limit on the value of #toExpNeg, #toExpPos, #minE and #maxE. + The limit on the value of toExpNeg, toExpPos, minE and maxE. */ EXP_LIMIT = 9e15, // 0 to 9e15 /* - The limit on the value of #precision, and on the argument to #toDecimalPlaces, - #toExponential, #toFixed, #toFormat, #toPrecision and #toSignificantDigits. + The limit on the value of precision, and on the argument to toDecimalPlaces, + toExponential, toFixed, toFormat, toPrecision and toSignificantDigits. */ MAX_DIGITS = 1E9, // 0 to 1e+9 /* To decide whether or not to calculate x.pow(integer y) using the 'exponentiation by squaring' algorithm or by exp(y*ln(x)), the number of significant digits of x is multiplied - by y. If this number is less than #INT_POW_LIMIT then the former algorithm is used. + by y. If this number is less than INT_POW_LIMIT then the former algorithm is used. */ INT_POW_LIMIT = 3000, // 0 to 5000 @@ -139,10 +143,25 @@ * Return the number of decimal places of the value of this Decimal. * */ - P['decimalPlaces'] = P['dp'] = function () { - var x = this; + P['decimalPlaces'] = P['dp'] = function () { + var c, v, + n = null; - return x['c'] ? Math.max( x['c'].length - x['e'] - 1, 0 ) : null; + if ( c = this['c'] ) { + n = ( ( v = c.length - 1 ) - mathfloor( this['e'] / LOGBASE ) ) * LOGBASE; + + if ( v = c[v] ) { + + // Subtract the number of trailing zeros of the last number. + for ( ; v % 10 == 0; v /= 10, n-- ); + } + + if ( n < 0 ) { + n = 0; + } + } + + return n; }; @@ -164,7 +183,7 @@ * I / I = N * * Return a new Decimal whose value is the value of this Decimal divided by Decimal(y, b), - * rounded to #precision significant digits using rounding mode #rounding. + * rounded to precision significant digits using rounding mode rounding. * */ P['dividedBy'] = P['div'] = function ( y, b ) { @@ -176,8 +195,8 @@ /* * Return a new Decimal whose value is the integer part of dividing the value of this Decimal by - * the value of Decimal(y, b), rounded to #precision significant digits using rounding mode - * #rounding. + * the value of Decimal(y, b), rounded to precision significant digits using rounding mode + * rounding. * */ P['dividedToIntegerBy'] = P['divToInt'] = function ( y, b ) { @@ -205,8 +224,8 @@ /* * Return a new Decimal whose value is the exponential of the value of this Decimal, i.e. the - * base e raised to the power the value of this Decimal, rounded to #precision significant digits - * using rounding mode #rounding. + * base e raised to the power the value of this Decimal, rounded to precision significant digits + * using rounding mode rounding. * */ P['exponential'] = P['exp'] = function () { @@ -267,7 +286,7 @@ */ P['isInteger'] = P['isInt'] = function () { - return !!this['c'] && this['e'] > this['c'].length - 2; + return !!this['c'] && mathfloor( this['e'] / LOGBASE ) > this['c'].length - 2; }; @@ -327,7 +346,7 @@ /* * Return the logarithm of the value of this Decimal to the specified base, rounded - * to #precision significant digits using rounding mode #rounding. + * to precision significant digits using rounding mode rounding. * * If no base is specified, return log[10](arg). * @@ -373,7 +392,7 @@ base = new Decimal( base, b ); c = base['c']; - // If #base < 0 or +-Infinity/NaN or 0 or 1. + // If base < 0 or +-Infinity/NaN or 0 or 1. if ( base['s'] < 0 || !c || !c[0] || !base['e'] && c[0] == 1 && c.length == 1 ) { return new Decimal(NaN); @@ -382,27 +401,31 @@ } c = arg['c']; - // If #arg < 0 or +-Infinity/NaN or 0 or 1. + // If arg < 0 or +-Infinity/NaN or 0 or 1. if ( arg['s'] < 0 || !c || !c[0] || !arg['e'] && c[0] == 1 && c.length == 1 ) { return new Decimal( c && !c[0] ? -1 / 0 : arg['s'] != 1 ? NaN : c ? 0 : 1 / 0 ); } /* - The result will have an infinite decimal expansion if #base is 10 and #arg is not an + The result will have an infinite decimal expansion if base is 10 and arg is not an integer power of 10... */ - inf = base10 && ( c[0] != 1 || c.length > 1 ) || - - // ...or if #base last digit's evenness is not the same as #arg last digit's evenness... - ( base['c'][ base['c'].length - 1 ] & 1 ) != ( c[ c.length - 1 ] & 1 ) || 0 && - - // ...or if #base is 2 and there is more than one 1 in #arg in base 2. - base['eq'](2) && arg.toString(2).replace( /[^1]+/g, '' ) != '1'; + inf = base10 && ( i = c[0], c.length > 1 || i != 1 && i != 10 && + i != 1e2 && i != 1e3 && i != 1e4 && i != 1e5 && i != 1e6 ); + /* + // or if base last digit's evenness is not the same as arg last digit's evenness... + // (FAILS when e.g. base.c[0] = 10 and c[0] = 1) + || ( base['c'][ base['c'].length - 1 ] & 1 ) != ( c[ c.length - 1 ] & 1 ) + // or if base is 2 and there is more than one 1 in arg in base 2. + // (SLOWS the method down significantly) + || base['eq'](2) && arg.toString(2).replace( /[^1]+/g, '' ) != '1'; + */ external = false; sd = pr + guard; sd10 = sd + 10; + num = ln( arg, sd ); if (base10) { @@ -456,10 +479,7 @@ if ( !inf ) { // Check for 14 nines from the 2nd rounding digit, as the first may be 4. - for ( c = r['c']; c[++i] == 9; ) { - } - - if ( i == pr + guard + 10 ) { + if ( +coefficientToString( r['c'] ).slice( i + 1, i + 15 ) + 1 == 1e14 ) { r = rnd( r, pr + 1, 0 ); } @@ -491,7 +511,7 @@ * I - I = N * * Return a new Decimal whose value is the value of this Decimal minus Decimal(y, b), rounded - * to #precision significant digits using rounding mode #rounding. + * to precision significant digits using rounding mode rounding. * */ P['minus'] = function ( y, b ) { @@ -518,13 +538,13 @@ } var xc = x['c'], - xe = x['e'], yc = y['c'], - ye = y['e'], + e = mathfloor( y['e'] / LOGBASE ), + k = mathfloor( x['e'] / LOGBASE ), pr = Decimal['precision'], rm = Decimal['rounding']; - if ( !xe || !ye ) { + if ( !k || !e ) { // Either Infinity? if ( !xc || !yc ) { @@ -535,7 +555,7 @@ // Either zero? if ( !xc[0] || !yc[0] ) { - // Return #y if #y is non-zero, #x if #x is non-zero, or zero if both are zero. + // Return y if y is non-zero, x if x is non-zero, or zero if both are zero. x = yc[0] ? ( y['s'] = -b, y ) : new Decimal( xc[0] ? x : // IEEE 754 (2008) 6.3: n - n = -0 when rounding to -Infinity @@ -549,38 +569,37 @@ i = xc.length; // Determine which is the bigger number. Prepend zeros to equalise exponents. - if ( a = xe - ye ) { + if ( a = k - e ) { if ( xLTy = a < 0 ) { a = -a; t = xc; i = yc.length; } else { - ye = xe; + e = k; t = yc; } - if ( pr > i ) { - i = pr; + if ( ( k = Math.ceil( pr / LOGBASE ) ) > i ) { + i = k; } /* Numbers with massively different exponents would result in a massive number of zeros needing to be prepended, but this can be avoided while still ensuring correct - rounding by limiting the number of zeros to max( #precision, #i ) + 2, where #pr is - #precision and #i is the length of the coefficient of whichever is greater #x or #y. + rounding by limiting the number of zeros to max( precision, i ) + 2, where pr is + precision and i is the length of the coefficient of whichever is greater x or y. */ if ( a > ( i += 2 ) ) { a = i; t.length = 1; } - for ( t.reverse(), b = a; b--; t.push(0) ) { - } + for ( t.reverse(), b = a; b--; t.push(0) ); t.reverse(); } else { + // Exponents equal. Check digits. - // Exponents equal. Check digit by digit. if ( xLTy = i < ( j = yc.length ) ) { j = i; } @@ -595,54 +614,53 @@ } } - // #x < #y? Point #xc to the array of the bigger number. + // x < y? Point xc to the array of the bigger number. if ( xLTy ) { t = xc, xc = yc, yc = t; y['s'] = -y['s']; } /* - Append zeros to #xc if shorter. No need to add zeros to #yc if shorter as subtraction only - needs to start at #yc length. + Append zeros to xc if shorter. No need to add zeros to yc if shorter as subtraction only + needs to start at yc length. */ if ( ( b = -( ( j = xc.length ) - yc.length ) ) > 0 ) { - for ( ; b--; xc[j++] = 0 ) { - } + for ( ; b--; xc[j++] = 0 ); } - // Subtract #yc from #xc. - for ( b = yc.length; b > a; ){ + // Subtract yc from xc. + for ( k = BASE - 1, b = yc.length; b > a; ) { if ( xc[--b] < yc[b] ) { - for ( i = b; i && !xc[--i]; xc[i] = 9 ) { - } + for ( i = b; i && !xc[--i]; xc[i] = k ); --xc[i]; - xc[b] += 10; + xc[b] += BASE; } xc[b] -= yc[b]; } // Remove trailing zeros. - for ( ; xc[--j] == 0; xc.pop() ) { - } + for ( ; xc[--j] == 0; xc.pop() ); // Remove leading zeros and adjust exponent accordingly. - for ( ; xc[0] == 0; xc.shift(), --ye ) { - } + for ( ; xc[0] == 0; xc.shift(), --e ); if ( !xc[0] ) { // Zero. - xc = [ ye = 0 ]; + xc = [ e = 0 ]; // Following IEEE 754 (2008) 6.3, n - n = -0 when rounding towards -Infinity. y['s'] = rm == 3 ? -1 : 1; } y['c'] = xc; - y['e'] = ye; + + // Get the number of digits of xc[0]. + for ( a = 1, b = xc[0]; b >= 10; b /= 10, a++ ); + y['e'] = a + e * LOGBASE - 1; return external ? rnd( y, pr, rm ) : y; }; @@ -667,7 +685,7 @@ * I % I = N * * Return a new Decimal whose value is the value of this Decimal modulo Decimal(y, b), rounded - * to #precision significant digits using rounding mode #rounding. + * to precision significant digits using rounding mode rounding. * * The result depends on the modulo mode. * @@ -684,8 +702,8 @@ n = !x['c'] || !b || y['c'] && !y['c'][0]; /* - Return NaN if #x is Infinity or NaN, or #y is NaN or zero, else return #x if #y is Infinity - or #x is zero. + Return NaN if x is Infinity or NaN, or y is NaN or zero, else return x if y is Infinity + or x is zero. */ if ( n || !y['c'] || x['c'] && !x['c'][0] ) { @@ -717,7 +735,7 @@ /* * Return a new Decimal whose value is the natural logarithm of the value of this Decimal, - * rounded to #precision significant digits using rounding mode #rounding. + * rounded to precision significant digits using rounding mode rounding. * */ P['naturalLogarithm'] = P['ln'] = function () { @@ -757,7 +775,7 @@ * I + I = I * * Return a new Decimal whose value is the value of this Decimal plus Decimal(y, b), rounded - * to #precision significant digits using rounding mode #rounding. + * to precision significant digits using rounding mode rounding. * */ P['plus'] = function ( y, b ) { @@ -783,14 +801,14 @@ return x['minus'](y); } - var xe = x['e'], - xc = x['c'], - ye = y['e'], + var xc = x['c'], yc = y['c'], + e = mathfloor( y['e'] / LOGBASE ), + k = mathfloor( x['e'] / LOGBASE ), pr = Decimal['precision'], rm = Decimal['rounding']; - if ( !xe || !ye ) { + if ( !k || !e ) { // Either Infinity? if ( !xc || !yc ) { @@ -802,7 +820,7 @@ // Either zero? if ( !xc[0] || !yc[0] ) { - // Return #y if #y is non-zero, #x if #x is non-zero, or zero if both are zero. + // Return y if y is non-zero, x if x is non-zero, or zero if both are zero. x = yc[0] ? y: new Decimal( xc[0] ? x : a * 0 ); return external ? rnd( x, pr, rm ) : x; @@ -812,56 +830,57 @@ xc = xc.slice(); // Prepend zeros to equalise exponents. Note: Faster to use reverse then do unshifts. - if ( a = xe - ye ) { + if ( a = k - e ) { if ( a < 0 ) { a = -a; t = xc; b = yc.length; } else { - ye = xe; + e = k; t = yc; b = xc.length; } - if ( pr > b ) { - b = pr; + if ( ( k = Math.ceil( pr / LOGBASE ) ) > b ) { + b = k; } - // Limit number of zeros prepended to max( #pr, #b ) + 1. + // Limit number of zeros prepended to max( pr, b ) + 1. if ( a > ++b ) { a = b; t.length = 1; } - for ( t.reverse(); a--; t.push(0) ) { - } + for ( t.reverse(); a--; t.push(0) ); t.reverse(); } - // Point #xc to the longer array. + // Point xc to the longer array. if ( xc.length - yc.length < 0 ) { t = yc, yc = xc, xc = t; } - // Only start adding at yc.length - 1 as the further digits of #xc can be left as they are. - for ( a = yc.length, b = 0; a; xc[a] %= 10 ) { - b = ( xc[--a] = xc[a] + yc[a] + b ) / 10 | 0; + // Only start adding at yc.length - 1 as the further digits of xc can be left as they are. + for ( a = yc.length, b = 0, k = BASE; a; xc[a] %= k ) { + b = ( xc[--a] = xc[a] + yc[a] + b ) / k | 0; } if (b) { xc.unshift(b); - ++ye; + ++e; } - // Remove trailing zeros. - for ( a = xc.length; xc[--a] == 0; xc.pop() ) { - } + // Remove trailing zeros. + for ( a = xc.length; xc[--a] == 0; xc.pop() ); // No need to check for zero, as +x + +y != 0 && -x + -y != 0 y['c'] = xc; - y['e'] = ye; + + // Get the number of digits of xc[0]. + for ( a = 1, b = xc[0]; b >= 10; b /= 10, a++ ); + y['e'] = a + e * LOGBASE - 1; return external ? rnd( y, pr, rm ) : y; }; @@ -874,9 +893,10 @@ * */ P['precision'] = P['sd'] = function (z) { - var x = this; + var n = null, + x = this; - if ( z != null ) { + if ( z != n ) { if ( z !== !!z && z !== 1 && z !== 0 ) { @@ -885,13 +905,21 @@ } } - return x['c'] ? z ? Math.max( x['e'] + 1, x['c'].length ) : x['c'].length : null; + if ( x['c'] ) { + n = getCoeffLength( x['c'] ); + + if ( z && x['e'] + 1 > n ) { + n = x['e'] + 1; + } + } + + return n; }; /* * Return a new Decimal whose value is the value of this Decimal rounded to a whole number using - * rounding mode #rounding. + * rounding mode rounding. * */ P['round'] = function () { @@ -910,12 +938,12 @@ * sqrt( 0) = 0 * sqrt(-0) = -0 * - * Return a new Decimal whose value is the square root of this Decimal, rounded to #precision - * significant digits using rounding mode #rounding. + * Return a new Decimal whose value is the square root of this Decimal, rounded to precision + * significant digits using rounding mode rounding. * */ P['squareRoot'] = P['sqrt'] = function () { - var n, sd, r, rep, t, + var m, n, sd, r, rep, t, x = this, c = x['c'], s = x['s'], @@ -939,19 +967,23 @@ Pass x to Math.sqrt as integer, then adjust the exponent of the result. */ if ( s == 0 || s == 1 / 0 ) { - n = c.join(''); + n = coefficientToString(c); if ( ( n.length + e ) % 2 == 0 ) { n += '0'; } - r = new Decimal( Math.sqrt(n) + '' ); - // r may not be finite. - if ( !r['c'] ) { - r['c'] = [1]; + s = Math.sqrt(n); + e = mathfloor( ( e + 1 ) / 2 ) - ( e < 0 || e % 2 ); + + if ( s == 1 / 0 ) { + n = '1e' + e; + } else { + n = s.toExponential(); + n = n.slice( 0, n.indexOf('e') + 1 ) + e; } - r['e'] = Math.floor( ( e + 1 ) / 2 ) - ( e < 0 || e % 2 ); + r = new Decimal(n); } else { r = new Decimal( s.toString() ); } @@ -963,22 +995,22 @@ t = r; r = half['times']( t['plus']( div( x, t, sd + 2, 1 ) ) ); - if ( t['c'].slice( 0, sd ).join('') === r['c'].slice( 0, sd ).join('') ) { - c = r['c']; + if ( coefficientToString( t['c'] ).slice( 0, sd ) === + ( n = coefficientToString( r['c'] ) ).slice( 0, sd ) ) { + n = n.slice( sd - 3, sd + 1 ); /* The 4th rounding digit may be in error by -1 so if the 4 rounding digits are 9999 or 4999 (i.e. approaching a rounding boundary) continue the iteration. */ - if ( ( c[sd - 3] == 9 || !rep && c[sd - 3] == 4 ) && - c[sd - 2] == 9 && c[sd - 1] == 9 && c[sd] == 9 ) { + if ( n == '9999' || !rep && n == '4999' ) { /* - On the first run through, check to see if rounding up gives the exact result as - the nines may infinitely repeat. + On the first iteration only, check to see if rounding up gives the exact result + as the nines may infinitely repeat. */ if ( !rep ) { - t = rnd( t, e + 1, 0 ); + rnd( t, e + 1, 0 ); if ( t['times'](t)['eq'](x) ) { r = t; @@ -991,25 +1023,14 @@ } else { /* - If the rounding digits are null, 0000 or 5000, check for an exact result. - If not, then there are further digits so increment the 1st rounding digit - to ensure correct rounding. + If the rounding digits are null, 0{0,4} or 50{0,3}, check for an exact result. + If not, then there are further digits and m will be truthy. */ - if ( ( !c[sd - 3] || c[sd - 3] == 5 ) && !c[sd - 2] && - !c[sd - 1] && !c[sd] ) { + if ( !+n || !+n.slice(1) && n.charAt(0) == '5' ) { // Truncate to the first rounding digit. - if ( c.length > e + 1 ) { - c.length = e + 1; - } - - if ( !r['times'](r)['eq'](x) ) { - - while ( c.length < e ) { - c.push(0); - } - c[e]++; - } + rnd( r, e + 1, 1 ); + m = !r['times'](r)['eq'](x); } break; @@ -1018,7 +1039,7 @@ } external = true; - return rnd( r, e, Decimal['rounding'] ); + return rnd( r, e, Decimal['rounding'], m ); }; @@ -1039,18 +1060,18 @@ * I * N = N * I * I = I * - * Return a new Decimal whose value is this Decimal times Decimal(y), rounded to #precision - * significant digits using rounding mode #rounding. + * Return a new Decimal whose value is this Decimal times Decimal(y), rounded to precision + * significant digits using rounding mode rounding. * */ P['times'] = function ( y, b ) { - var c, + var c, e, x = this, Decimal = x['constructor'], xc = x['c'], yc = ( id = 11, y = new Decimal( y, b ), y['c'] ), - i = x['e'], - j = y['e'], + i = mathfloor( x['e'] / LOGBASE ), + j = mathfloor( y['e'] / LOGBASE ), a = x['s']; b = y['s']; @@ -1063,7 +1084,7 @@ // Either NaN? return new Decimal( !a || !b || - // #x is 0 and #y is Infinity or #y is 0 and #x is Infinity? + // x is 0 and y is Infinity or y is 0 and x is Infinity? xc && !xc[0] && !yc || yc && !yc[0] && !xc // Return NaN. @@ -1075,11 +1096,11 @@ // Return +-Infinity. ? y['s'] / 0 - // #x or #y is 0. Return +-0. + // x or y is 0. Return +-0. : y['s'] * 0 ); } - y['e'] = i + j; + e = i + j; a = xc.length; b = yc.length; @@ -1090,24 +1111,23 @@ j = a, a = b, b = j; } - for ( j = a + b, c = []; j--; c.push(0) ) { - } + for ( j = a + b, c = []; j--; c.push(0) ); // Multiply! for ( i = b - 1; i > -1; i-- ) { - for ( b = 0, j = a + i; j > i; b = b / 10 | 0 ) { + for ( b = 0, j = a + i; j > i; b = b / BASE | 0 ) { b = c[j] + yc[i] * xc[j - i - 1] + b; - c[j--] = b % 10 | 0; + c[j--] = b % BASE | 0; } if (b) { - c[j] = ( c[j] + b ) % 10; + c[j] = ( c[j] + b ) % BASE; } } if (b) { - ++y['e']; + ++e; } // Remove any leading zero. @@ -1116,19 +1136,23 @@ } // Remove trailing zeros. - for ( j = c.length; !c[--j]; c.pop() ) { - } + for ( j = c.length; !c[--j]; c.pop() ); + y['c'] = c; + // Get the number of digits of c[0]. + for ( a = 1, b = c[0]; b >= 10; b /= 10, a++ ); + y['e'] = a + e * LOGBASE - 1; + return external ? rnd( y, Decimal['precision'], Decimal['rounding'] ) : y; }; /* - * Return a new Decimal whose value is the value of this Decimal rounded to a maximum of #dp - * decimal places using rounding mode #rm or #rounding if #rm is omitted. + * Return a new Decimal whose value is the value of this Decimal rounded to a maximum of dp + * decimal places using rounding mode rm or rounding if rm is omitted. * - * If #dp is omitted, return a new Decimal whose value is the value of this Decimal. + * If dp is omitted, return a new Decimal whose value is the value of this Decimal. * * [dp] {number} Decimal places. Integer, 0 to MAX_DIGITS inclusive. * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. @@ -1150,14 +1174,14 @@ /* - * Return a string representing the value of this Decimal in exponential notation rounded to #dp - * fixed decimal places using rounding mode #rounding. + * Return a string representing the value of this Decimal in exponential notation rounded to dp + * fixed decimal places using rounding mode rounding. * * [dp] {number} Decimal places. Integer, 0 to MAX_DIGITS inclusive. * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. * - * #errors true: Throw if #dp and #rm are not undefined, null or integers in range. - * #errors false: Ignore #dp and #rm if not numbers or not in range, and truncate non-integers. + * errors true: Throw if dp and rm are not undefined, null or integers in range. + * errors false: Ignore dp and rm if not numbers or not in range, and truncate non-integers. * * 'toExponential() dp not an integer: {dp}' * 'toExponential() dp out of range: {dp}' @@ -1168,22 +1192,24 @@ P['toExponential'] = function ( dp, rm ) { var x = this; - return format( x, dp != null && checkArg( x, dp, 'toExponential' ) || !x['c'] - ? dp | 0 : x['c'].length - 1, dp != null && checkRM( x, rm, 'toExponential' ), 1 ); + return x['c'] + ? format( x, dp != null && checkArg( x, dp, 'toExponential' ) ? dp | 0 : null, + dp != null && checkRM( x, rm, 'toExponential' ), 1 ) + : x.toString(); }; /* * Return a string representing the value of this Decimal in normal (fixed-point) notation to - * #dp fixed decimal places and rounded using rounding mode #rm or #rounding if #rm is omitted. + * dp fixed decimal places and rounded using rounding mode rm or rounding if rm is omitted. * * Note: as with JS numbers, (-0).toFixed(0) is '0', but e.g. (-0.00001).toFixed(0) is '-0'. * * [dp] {number} Decimal places. Integer, -MAX_DIGITS to MAX_DIGITS inclusive. * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. * - * #errors true: Throw if #dp and #rm are not undefined, null or integers in range. - * #errors false: Ignore #dp and #rm if not numbers or not in range, and truncate non-integers. + * errors true: Throw if dp and rm are not undefined, null or integers in range. + * errors false: Ignore dp and rm if not numbers or not in range, and truncate non-integers. * * 'toFixed() dp not an integer: {dp}' * 'toFixed() dp out of range: {dp}' @@ -1199,14 +1225,14 @@ pos = Decimal['toExpPos']; if ( dp != null ) { - dp = checkArg( x, dp, str = 'toFixed', -MAX_DIGITS ) ? x['e'] + ( dp | 0 ) : null; + dp = checkArg( x, dp, str = 'toFixed' ) ? x['e'] + ( dp | 0 ) : null; rm = checkRM( x, rm, str ); } - // Prevent #toString returning exponential notation; + // Prevent toString returning exponential notation; Decimal['toExpNeg'] = -( Decimal['toExpPos'] = 1 / 0 ); - if ( dp == null ) { + if ( dp == null || !x['c'] ) { str = x.toString(); } else { str = format( x, dp, rm ); @@ -1234,9 +1260,9 @@ /* * Return a string representing the value of this Decimal in normal notation rounded using - * rounding mode #rounding to #dp fixed decimal places, with the integer part of the number - * separated into thousands by string #sep1 or ',' if #sep1 is null or undefined, and the fraction - * part separated into groups of five digits by string #sep2. + * rounding mode rounding to dp fixed decimal places, with the integer part of the number + * separated into thousands by string sep1 or ',' if sep1 is null or undefined, and the + * fraction part separated into groups of five digits by string sep2. * * [sep1] {string} The grouping separator of the integer part of the number. * [sep2] {string} The grouping separator of the fraction part of the number. @@ -1244,7 +1270,7 @@ * * Non-breaking thin-space: \u202f * - * If #dp is invalid the error message will incorrectly give the method as toFixed. + * If dp is invalid the error message will incorrectly give the method as toFixed. * */ P['toFormat'] = function ( sep1, dp, sep2 ) { @@ -1267,14 +1293,13 @@ * */ P['toFraction'] = function (maxD) { - var d0, d2, e, frac, n, n0, q, + var d0, d2, e, frac, n, n0, p, q, x = this, Decimal = x['constructor'], n1 = d0 = new Decimal( Decimal['ONE'] ), d1 = n0 = new Decimal(0), xc = x['c'], - d = new Decimal( Decimal['ONE'] ), - pr = Decimal['precision']; + d = new Decimal(d1); // NaN, Infinity. if ( !xc ) { @@ -1282,9 +1307,10 @@ return x.toString(); } - e = d['e'] = xc.length - x['e'] - 1; + e = d['e'] = getCoeffLength(xc) - x['e'] - 1; + d['c'][0] = mathpow( 10, ( p = e % LOGBASE ) < 0 ? LOGBASE + p : p ); - // If #maxD is undefined or null... + // If maxD is undefined or null... if ( maxD == null || // or NaN... @@ -1294,7 +1320,7 @@ ( outOfRange = n['cmp'](n1) < 0 || !n['c'] ) || // or not an integer... - ( Decimal['errors'] && n['e'] < n['c'].length - 1 ) ) && + ( Decimal['errors'] && mathfloor( n['e'] / LOGBASE ) < n['c'].length - 1 ) ) && // 'toFraction() max denominator not an integer: {maxD}' // 'toFraction() max denominator out of range: {maxD}' @@ -1308,10 +1334,9 @@ } external = false; - n = new Decimal( xc.join('') ); - - // #plus and #minus need #precision to be at least xc.length. - Decimal['precision'] = xc.length; + n = new Decimal( coefficientToString(xc) ); + p = Decimal['precision']; + Decimal['precision'] = e = xc.length * LOGBASE * 2; for ( ; ; ) { q = div( n, d, 0, 1, 1 ); @@ -1333,40 +1358,36 @@ d2 = div( maxD['minus'](d0), d1, 0, 1, 1 ); n0 = n0['plus']( d2['times'](n1) ); d0 = d0['plus']( d2['times'](d1) ); - n0['s'] = n1['s'] = x['s']; - // The required decimal places. - e *= 2; - - // Determine which fraction is closer to #x, #n0 /# d0 or #n1 / #d1? - frac = div( n1, d1, e, 1, 1 )['minus'](x)['abs']()['cmp']( - div( n0, d0, e, 1, 1 )['minus'](x)['abs']() ) < 1 - ? [ n1.toString(), d1.toString() ] - : [ n0.toString(), d0.toString() ]; + // Determine which fraction is closer to x, n0/d0 or n1/d1? + frac = div( n1, d1, e, 1 )['minus'](x)['abs']()['cmp']( + div( n0, d0, e, 1 )['minus'](x)['abs']() ) < 1 + ? [ n1 + '', d1 + '' ] + : [ n0 + '', d0 + '' ]; external = true; - Decimal['precision'] = pr; + Decimal['precision'] = p; return frac; }; /* - * Returns a new Decimal whose value is the nearest multiple of the magnitude of #n to the value + * Returns a new Decimal whose value is the nearest multiple of the magnitude of n to the value * of this Decimal. * - * If the value of this Decimal is equidistant from two multiples of #n, the rounding mode #rm, - * or #rounding if #rm is omitted or is null or undefined, determines the direction of the + * If the value of this Decimal is equidistant from two multiples of n, the rounding mode rm, + * or rounding if rm is omitted or is null or undefined, determines the direction of the * nearest multiple. * * In the context of this method, rounding mode 4 (ROUND_HALF_UP) is the same as rounding mode 0 * (ROUND_UP), and so on. * * The return value will always have the same sign as this Decimal, unless either this Decimal - * or #n is NaN, in which case the return value will be also be NaN. + * or n is NaN, in which case the return value will be also be NaN. * - * The return value is not rounded to #precision significant digits. + * The return value is not rounded to precision significant digits. * * n {number|string|Decimal} The magnitude to round to a multiple of. * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. @@ -1390,50 +1411,26 @@ rm = checkRM( x, rm, 'toNearest' ); } - // If #n is not NaN/+-Infinity... + // If n is finite... if ( n['c'] ) { - // If #x is not NaN/+-Infinity... + // If x is finite... if ( x['c'] ) { - external = false; - /* - 4 ROUND_HALF_UP - 5 ROUND_HALF_DOWN - 6 ROUND_HALF_EVEN - 7 ROUND_HALF_CEIL - 8 ROUND_HALF_FLOOR - */ - if ( rm < 4 ) { - rm = [4, 5, 7, 8][rm]; - } - - // If #n is a power of 10... - if ( n['c'][0] == 1 && n['c'].length == 1 ) { - x['e'] -= n['e']; - - // 0 dp - rnd( x, x['e'] + 1, rm ); - - if ( x['c'][0] ) { - x['e'] += n['e']; - } - - // else if #n is not zero... - } else if ( n['c'][0] ) { - x = div( x, n, 0, rm, 1 )['times'](n); + if ( n['c'][0] ) { + external = false; + x = div( x, n, 0, rm < 4 ? [4, 5, 7, 8][rm] : rm, 1 )['times'](n); + external = true; + rnd(x); } else { x['c'] = [ x['e'] = 0 ]; } - - external = true; - rnd(x); } - // # is NaN/+-Infinity. If #x is not NaN... + // n is NaN or +-Infinity. If x is not NaN... } else if ( x['s'] ) { - // If #n is not NaN... + // If n is +-Infinity... if ( n['s'] ) { n['s'] = x['s']; } @@ -1458,7 +1455,7 @@ /* * Return a new Decimal whose value is the value of this Decimal raised to the power - * Decimal(y, b), rounded to #precision significant digits using rounding mode #rounding. + * Decimal(y, b), rounded to precision significant digits using rounding mode rounding. * * ECMAScript compliant. * @@ -1517,13 +1514,13 @@ if ( !x['c'] || !y['c'] || ( n = !x['c'][0] ) || !y['c'][0] ) { // valueOf -0 is 0, so check for 0 then multiply it by the sign. - return new Decimal( Math.pow( n ? s * 0 : +x, yN ) ); + return new Decimal( mathpow( n ? s * 0 : +x, yN ) ); } x = new Decimal(x); a = x['c'].length; - // if #x == 1 + // if x == 1 if ( !x['e'] && x['c'][0] == x['s'] && a == 1 ) { return x; @@ -1531,22 +1528,23 @@ b = y['c'].length - 1; - // if #y == 1 + // if y == 1 if ( !y['e'] && y['c'][0] == y['s'] && !b ) { r = rnd( x, pr, rm ); } else { - n = y['e'] >= b; + e = mathfloor( y['e'] / LOGBASE ); + n = e >= b; - // If #y is not an integer and #x is negative, return NaN. + // If y is not an integer and x is negative, return NaN. if ( !n && s < 0 ) { r = new Decimal(NaN); } else { /* - If the number of significant digits of #x multiplied by abs(#y) is less than - INT_POW_LIMIT use the 'exponentiation by squaring' algorithm. + If the approximate number of significant digits of x multiplied by abs(y) is less + than INT_POW_LIMIT use the 'exponentiation by squaring' algorithm. */ - if ( n && a * i < INT_POW_LIMIT ) { + if ( n && a * LOGBASE * i < INT_POW_LIMIT ) { r = intPow( Decimal, x, i ); if ( y['s'] < 0 ) { @@ -1555,21 +1553,20 @@ } } else { - // Result is negative if #x is negative and the last digit of integer #y is odd. - s = s < 0 && y['c'][ Math.max( y['e'], b ) ] & 1 ? -1 : 1; + // Result is negative if x is negative and the last digit of integer y is odd. + s = s < 0 && y['c'][ Math.max( e, b ) ] & 1 ? -1 : 1; - b = Math.pow( +x, yN ); + b = mathpow( +x, yN ); - // Estimate result exponent. + /* + Estimate result exponent. + x^y = 10^e, where e = y * log10(x) + log10(x) = log10(x_significand) + x_exponent + log10(x_significand) = ln(x_significand) / ln(10) + */ e = b == 0 || !isFinite(b) - - /* - x^y = 10^e, where e = y * log10(x) - log10(x) = log10(x_significand) + x_exponent - log10(x_significand) = ln(x_significand) / ln(10) - */ - ? Math.floor( yN * ( - Math.log( '0.' + x['c'].join('') ) / Math.LN10 + x['e'] + 1 ) ) + ? mathfloor( yN * ( + Math.log( '0.' + coefficientToString( x['c'] ) ) / Math.LN10 + x['e'] + 1 ) ) : new Decimal( b + '' )['e']; // Estimate may be incorrect e.g.: x: 0.999999999999999999, y: 2.29, e: 0, r.e:-1 @@ -1585,8 +1582,8 @@ /* Estimate extra digits needed from ln(x) to ensure five correct rounding digits - in result (#i was unnecessary before max exponent was extended?). - Example of failure before #i was introduced: (precision: 10), + in result (i was unnecessary before max exponent was extended?). + Example of failure before i was introduced: (precision: 10), new Decimal(2.32456).pow('2087987436534566.46411') should be 1.162377823e+764914905173815, but is 1.162355823e+764914905173815 */ @@ -1612,11 +1609,7 @@ Check for 14 nines from the 2nd rounding digit (the first rounding digit may be 4 or 9). */ - for ( i = pr; r['c'][++i] == 9; ) { - } - - // If there are 14 nines round up the first rounding digit. - if ( i == pr + 15 ) { + if ( +coefficientToString( r['c'] ).slice( pr + 1, pr + 15 ) + 1 == 1e14 ) { r = rnd( r, pr + 1, 0 ); } } @@ -1635,17 +1628,17 @@ /* - * Return a string representing the value of this Decimal rounded to #sd significant digits - * using rounding mode #rounding. + * Return a string representing the value of this Decimal rounded to sd significant digits + * using rounding mode rounding. * - * Return exponential notation if #sd is less than the number of digits necessary to represent + * Return exponential notation if sd is less than the number of digits necessary to represent * the integer part of the value in normal notation. * * sd {number} Significant digits. Integer, 1 to MAX_DIGITS inclusive. * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. * - * #errors true: Throw if #sd and #rm are not undefined, null or integers in range. - * #errors false: Ignore #sd and #rm if not numbers or not in range, and truncate non-integers. + * errors true: Throw if sd and rm are not undefined, null or integers in range. + * errors false: Ignore sd and rm if not numbers or not in range, and truncate non-integers. * * 'toPrecision() sd not an integer: {sd}' * 'toPrecision() sd out of range: {sd}' @@ -1654,16 +1647,17 @@ * */ P['toPrecision'] = function ( sd, rm ) { + var x = this; - return sd != null && checkArg( this, sd, 'toPrecision', 1 ) - ? format( this, --sd | 0, checkRM( this, rm, 'toPrecision' ), 2 ) - : this.toString(); + return sd != null && checkArg( x, sd, 'toPrecision', 1 ) && x['c'] + ? format( x, --sd | 0, checkRM( x, rm, 'toPrecision' ), 2 ) + : x.toString(); }; /* - * Return a new Decimal whose value is this Decimal rounded to a maximum of #d significant - * digits using rounding mode #rm, or to #precision and #rounding respectively if omitted. + * Return a new Decimal whose value is this Decimal rounded to a maximum of d significant + * digits using rounding mode rm, or to precision and rounding respectively if omitted. * * [d] {number} Significant digits. Integer, 1 to MAX_DIGITS inclusive. * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. @@ -1687,18 +1681,18 @@ /* - * Return a string representing the value of this Decimal in base #b, or base 10 if #b is - * omitted. If a base is specified, including base 10, round to #precision significant digits - * using rounding mode #rounding. + * Return a string representing the value of this Decimal in base b, or base 10 if b is + * omitted. If a base is specified, including base 10, round to precision significant digits + * using rounding mode rounding. * * Return exponential notation if a base is not specified, and this Decimal has a positive - * exponent equal to or greater than #toExpPos, or a negative exponent equal to or less than - * #toExpNeg. + * exponent equal to or greater than toExpPos, or a negative exponent equal to or less than + * toExpNeg. * * [b] {number} Base. Integer, 2 to 64 inclusive. * */ - P['toString'] = function (b) { + P['toString'] = function (b) { var u, str, strL, x = this, Decimal = x['constructor'], @@ -1711,16 +1705,15 @@ // Exponential format? } else if ( b === u && ( xe <= Decimal['toExpNeg'] || xe >= Decimal['toExpPos'] ) ) { - return format( x, x['c'].length - 1, Decimal['rounding'], 1 ); + return format( x, null, Decimal['rounding'], 1 ); } else { - str = x['c'].join(''); + str = coefficientToString( x['c'] ); // Negative exponent? if ( xe < 0 ) { // Prepend zeros. - for ( ; ++xe; str = '0' + str ) { - } + for ( ; ++xe; str = '0' + str ); str = '0.' + str; // Positive exponent? @@ -1729,8 +1722,7 @@ if ( ++xe > strL ) { // Append zeros. - for ( xe -= strL; xe-- ; str += '0' ) { - } + for ( xe -= strL; xe-- ; str += '0' ); } else if ( xe < strL ) { str = str.slice( 0, xe ) + '.' + str.slice(xe); @@ -1785,9 +1777,9 @@ /* - * Return as #toString, but do not accept a base argument. + * Return as toString, but do not accept a base argument. * - * Ensures that JSON.stringify() uses #toString for serialization. + * Ensures that JSON.stringify() uses toString for serialization. * */ P['valueOf'] = P['toJSON'] = function () { @@ -1812,37 +1804,121 @@ /* - * #checkRoundingDigits - * #checkRM - * #checkArg - * #convertBase - * #div - * #exp - * #format - * #ifExceptionsThrow - * #intPow - * #ln - * #rnd + * coefficientToString + * checkRoundingDigits + * checkRM + * checkArg + * convertBase + * div + * exp + * format + * getCoeffLength + * ifExceptionsThrow + * intPow + * ln + * rnd */ - /* - * Check 5 rounding digits if #repeating is null, 4 otherwise. - * #repeating == null if caller is #log or #pow, - * #repeating != null if caller is #ln or #exp. - */ - function checkRoundingDigits( c, i, rm, repeating ) { + function coefficientToString(a) { + var s, z, + i = 1, + j = a.length, + r = a[0] + ''; - return ( !repeating && rm > 3 && c[i] == 4 || - ( repeating || rm < 4 ) && c[i] == 9 ) && c[i + 1] == 9 && c[i + 2] == 9 && - c[i + 3] == 9 && ( repeating != null || c[i + 4] == 9 ) || - repeating == null && ( c[i] == 5 || !c[i] ) && !c[i + 1] && !c[i + 2] && - !c[i + 3] && !c[i + 4]; + for ( ; i < j; i++ ) { + s = a[i] + ''; + + for ( z = LOGBASE - s.length; z--; ) { + s = '0' + s; + } + + r += s; + } + + for ( j = r.length; r.charAt(--j) == '0'; ); + + return r.slice( 0, j + 1 || 1 ); } /* - * Check and return rounding mode. If #rm is invalid, return rounding mode #rounding. + * Check 5 rounding digits if repeating is null, 4 otherwise. + * repeating == null if caller is log or pow, + * repeating != null if caller is ln or exp. + * + * + // Previous, much simpler implementation when coefficient was base 10. + function checkRoundingDigits( c, i, rm, repeating ) { + return ( !repeating && rm > 3 && c[i] == 4 || + ( repeating || rm < 4 ) && c[i] == 9 ) && c[i + 1] == 9 && c[i + 2] == 9 && + c[i + 3] == 9 && ( repeating != null || c[i + 4] == 9 ) || + repeating == null && ( c[i] == 5 || !c[i] ) && !c[i + 1] && !c[i + 2] && + !c[i + 3] && !c[i + 4]; + } + */ + function checkRoundingDigits( c, i, rm, repeating ) { + var ci, k, n, r, rd; + + // Get the length of the first element of the array c. + for ( k = 1, n = c[0]; n >= 10; n /= 10, k++ ); + + n = i - k; + + // Is the rounding digit in the first element of c? + if ( n < 0 ) { + n += LOGBASE; + ci = 0; + } else { + ci = Math.ceil( ( n + 1 ) / LOGBASE ); + n %= LOGBASE; + } + + k =mathpow( 10, LOGBASE - n ); + rd = c[ci] % k | 0; + + if ( repeating == null ) { + + if ( n < 3 ) { + + if ( n == 0 ) { + rd = rd / 100 | 0; + } else if ( n == 1 ) { + rd = rd / 10 | 0; + } + + r = rm < 4 && rd == 99999 || rm > 3 && rd == 49999 || rd == 50000 || rd == 0; + } else { + r = ( rm < 4 && rd + 1 == k || rm > 3 && rd + 1 == k / 2 ) && + ( c[ci + 1] / k / 100 | 0 ) == mathpow( 10, n - 2 ) - 1 || + ( rd == k / 2 || rd == 0 ) && ( c[ci + 1] / k / 100 | 0 ) == 0; + } + } else { + + if ( n < 4 ) { + + if ( n == 0 ) { + rd = rd / 1000 | 0; + } else if ( n == 1 ) { + rd = rd / 100 | 0; + } else if ( n == 2 ) { + rd = rd / 10 | 0; + } + + r = ( repeating || rm < 4 ) && rd == 9999 || !repeating && rm > 3 && rd == 4999; + } else { + r = ( ( repeating || rm < 4 ) && rd + 1 == k || + ( !repeating && rm > 3 ) && rd + 1 == k / 2 ) && + ( c[ci + 1] / k / 1000 | 0 ) == mathpow( 10, n - 3 ) - 1; + } + } + + return r; + } + + + /* + * Check and return rounding mode. If rm is invalid, return rounding mode rounding. */ function checkRM( x, rm, method ) { var Decimal = x['constructor']; @@ -1854,9 +1930,9 @@ } - /* - * Check that argument #n is in range, return true or false. - */ + /* + * Check that argument n is in range, return true or false. + */ function checkArg( x, n, method, min ) { var Decimal = x['constructor']; @@ -1872,12 +1948,12 @@ /* - * Convert a numeric string of #baseIn to a numeric string of #baseOut. + * Convert a numeric string of baseIn to a numeric string of baseOut. */ convertBase = (function () { /* - * Convert string of #baseIn to an array of numbers of #baseOut. + * Convert string of baseIn to an array of numbers of baseOut. * Eg. convertBase('255', 10, 16) returns [15, 15]. * Eg. convertBase('ff', 16, 10) returns [2, 5, 5]. */ @@ -1890,8 +1966,8 @@ for ( ; i < strL; ) { - for ( arrL = arr.length; arrL--; arr[arrL] *= baseIn ) { - } + for ( arrL = arr.length; arrL--; arr[arrL] *= baseIn ); + arr[ j = 0 ] += NUMERALS.indexOf( str.charAt( i++ ) ); for ( ; j < arr.length; j++ ) { @@ -1910,200 +1986,409 @@ return arr.reverse(); } - // #sign is needed to enable the correct rounding of the division. return function ( Decimal, str, baseOut, baseIn, sign ) { - var x, xc, yc, + var e, j, r, x, xc, y, i = str.indexOf( '.' ), - y = new Decimal(baseIn); + pr = Decimal['precision'], + rm = Decimal['rounding']; if ( baseIn < 37 ) { str = str.toLowerCase(); } - if ( i < 0 ) { - x = new Decimal(y); - yc = [1]; - } else { + // Non-integer. + if ( i >= 0 ) { + str = str.replace( '.', '' ); + y = new Decimal(baseIn); + x = intPow( Decimal, y, str.length - i ); /* - Convert the base of #str as if #str is an integer, then divide the result by its - base raised to a power such that the fraction part will be restored. - Use #toFixed to avoid possible exponential notation. + Convert str as if an integer, then divide the result by its base raised to a power + such that the fraction part will be restored. + Use toFixed to avoid possible exponential notation. */ - x = intPow( Decimal, y, str.length - i - 1 ); - yc = toBaseOut( x.toFixed(), 10, baseOut ); - str = str.replace( '.', '' ); + y['c'] = toBaseOut( x.toFixed(), 10, baseOut ); + y['e'] = y['c'].length; } - // #xc and #yc may have trailing zeros. - - y['c'] = yc; - y['e'] = yc.length; - // Convert the number as integer. xc = toBaseOut( str, baseIn, baseOut ); + e = j = xc.length; - x['c'] = xc; - x['e'] = xc.length; - x['s'] = sign; + // Remove trailing zeros. + for ( ; xc[--j] == 0; xc.pop() ); - x = div( x, y, Decimal['precision'], Decimal['rounding'], 0, baseOut ); + if ( !xc[0] ) { - // E.g. [4, 11, 15] becomes [4, b, f]. - for ( xc = x['c'], i = xc.length; i--; ) { - xc[i] = NUMERALS.charAt( xc[i] ); + return '0'; + } + + if ( i < 0 ) { + e--; + } else { + x['c'] = xc; + x['e'] = e; + + // sign is needed for correct rounding. + x['s'] = sign; + x = div( x, y, pr, rm, 0, baseOut ); + xc = x['c']; + r = x['r']; + e = x['e']; + } + + // The rounding digit, i.e. the digit after the digit that may be rounded up. + i = xc[pr]; + j = baseOut / 2; + r = r || xc[pr + 1] != null; + + if ( rm < 4 + ? ( i != null || r ) && ( rm == 0 || rm == ( x['s'] < 0 ? 3 : 2 ) ) + : i > j || i == j && ( rm == 4 || r || rm == 6 && xc[pr - 1] & 1 || + rm == ( x['s'] < 0 ? 8 : 7 ) ) ) { + + xc.length = pr; + + // Rounding up may mean the previous digit has to be rounded up and so on. + for ( --baseOut; ++xc[--pr] > baseOut; ) { + xc[pr] = 0; + + if ( !pr ) { + ++e; + xc.unshift(1); + } + } + } else { + xc.length = pr; + } + + // Determine trailing zeros. + for ( j = xc.length; !xc[--j]; ); + + // E.g. [4, 11, 15] becomes 4bf. + for ( i = 0, str = ''; i <= j; str += NUMERALS.charAt( xc[i++] ) ); + + // Negative exponent? + if ( e < 0 ) { + + // Prepend zeros. + for ( ; ++e; str = '0' + str ); + + str = '0.' + str; + + // Positive exponent? + } else { + i = str.length; + + if ( ++e > i ) { + + // Append zeros. + for ( e -= i; e-- ; str += '0' ); + + } else if ( e < i ) { + str = str.slice( 0, e ) + '.' + str.slice(e); + } } // No negative numbers: the caller will add the sign. - x['s'] = 1; - - return x.toFixed(); + return str; } })(); /* - * Perform division in the specified base. Called by #div and #convertBase. + * Perform division in the specified base. Called by div and convertBase. */ - function div( x, y, pr, rm, dp, b ) { - var Decimal = x['constructor'], - e = x['e'] - y['e'], - s = x['s'] == y['s'] ? 1 : -1, - xc = x['c'], - yc = y['c']; + var div = ( function () { - // Either NaN, Infinity or 0? - if ( !xc || !xc[0] || !yc || !yc[0] ) { + // Assumes non-zero x and k, and hence non-zero result. + function multiplyInteger( x, k, base ) { + var temp, + carry = 0, + i = x.length; - return new Decimal( - - // Return NaN if either NaN, or both Infinity or 0. - !x['s'] || !y['s'] || ( xc ? yc && xc[0] == yc[0] : !yc ) ? NaN : - - // Return +-0 if #x is 0 or #y is +-Infinity, or return +-Infinity as y is 0. - xc && xc[0] == 0 || !yc ? s * 0 : s / 0 - ); - } - - var cmp, i, n, ri, t, yL, - yz = yc.slice(), - xi = yL = yc.length, - xL = xc.length, - r = xc.slice( 0, yL ), - rL = r.length, - q = new Decimal(s), - qc = q['c'] = []; - - for ( i = s = 0; yc[i] == ( xc[i] || 0 ); i++ ) { - } - - // Result exponent may be one less then the current value of #e. - // The coefficients of the Decimals from #convertBase may have trailing zeros. - if ( yc[i] > ( xc[i] || 0 ) ) { - e--; - - /* - The result of the division has a leading zero so an extra digit will be needed to - maintain the correct precision (plus the rounding digit). - */ - s = 1; - } - - q['e'] = e; - - if ( pr == null ) { - pr = Decimal['precision']; - rm = Decimal['rounding']; - } else if (dp) { - pr += e + 1; - } - - // Default base is 10. - b = b || 10; - - if ( pr >= 0 ) { - s += pr; - - // Add zeros to make remainder as long as divisor. - for ( ; rL++ < yL; r.push(0) ) { + for ( x = x.slice(); i--; ) { + temp = x[i] * k + carry; + x[i] = temp % base | 0; + carry = temp / base | 0; } - // Create version of divisor with leading zero. - yz.unshift( i = 0 ); + if (carry) { + x.unshift(carry); + } - do { + return x; + } - // #n is how many times the divisor goes into the current remainder. - for ( n = 0; n < b; n++ ) { + function compare( a, b, aL, bL ) { + var i, cmp; - // Compare divisor and remainder. - if ( yL != ( rL = r.length ) ) { - cmp = yL > rL ? 1 : -1; - } else { + if ( aL != bL ) { + cmp = aL > bL ? 1 : -1; + } else { - for ( ri = -1, cmp = 0; ++ri < yL; ) { + for ( i = cmp = 0; i < aL; i++ ) { - if ( yc[ri] != r[ri] ) { - cmp = yc[ri] > r[ri] ? 1 : -1; - - break; - } - } - } - - // If divisor < remainder, subtract divisor from remainder. - if ( cmp < 0 ) { - - // Remainder cannot be more than one digit longer than divisor. - // Equalise lengths using divisor with extra leading zero? - for ( t = rL == yL ? yc : yz; rL; ) { - - if ( r[--rL] < t[rL] ) { - - for ( ri = rL; - ri && !r[--ri]; - r[ri] = b - 1 ) { - } - --r[ri]; - r[rL] += b; - } - r[rL] -= t[rL]; - } - - for ( ; !r[0]; r.shift() ) { - } - } else { + if ( a[i] != b[i] ) { + cmp = a[i] > b[i] ? 1 : -1; break; } } - - // Add the next digit n to the result array. - qc[i++] = cmp ? n : ++n; - - // Update the remainder. - if ( r[0] && cmp ) { - r[rL] = xc[xi] || 0; - } else { - r = [ xc[xi] ]; - } - - } while ( ( xi++ < xL || r[0] != null ) && s-- ); - - // Leading zero? Do not remove if result is simply zero, i.e. i is 1. - if ( !qc[0] && i > 1 ) { - qc.shift(); } - // No need to round if #i <= #pr, just check for underflow/overflow. - if ( i <= pr ) { - pr = null; - } + return cmp; } - // If #pr < 0, r[0] != null will be true. - return rnd( q, pr, rm, r[0] != null, b ); - } + function subtract( a, b, aL, base ) { + var i = 0; + + // Subtract b from a. + for ( ; aL--; ) { + a[aL] -= i; + i = a[aL] < b[aL] ? 1 : 0; + a[aL] = i * base + a[aL] - b[aL]; + } + + // Remove leading zeros. + for ( ; !a[0] && a.length > 1; a.shift() ); + } + + // x: dividend, y: divisor. + return function ( x, y, pr, rm, dp, base ) { + var cmp, e, i, logbase, more, n, prod, prodL, q, qc, rem, remL, rem0, t, xi, xL, yc0, + yL, yz, + Decimal = x['constructor'], + s = x['s'] == y['s'] ? 1 : -1, + xc = x['c'], + yc = y['c']; + + // Either NaN, Infinity or 0? + if ( !xc || !xc[0] || !yc || !yc[0] ) { + + return new Decimal( + + // Return NaN if either NaN, or both Infinity or 0. + !x['s'] || !y['s'] || ( xc ? yc && xc[0] == yc[0] : !yc ) ? NaN : + + // Return +-0 if x is 0 or y is +-Infinity, or return +-Infinity as y is 0. + xc && xc[0] == 0 || !yc ? s * 0 : s / 0 + ); + } + + if (base) { + logbase = 1; + e = x['e'] - y['e']; + } else { + base = BASE; + logbase = LOGBASE; + e = mathfloor( x['e'] / logbase ) - mathfloor( y['e'] / logbase ); + } + + yL = yc.length; + xL = xc.length; + q = new Decimal(s); + qc = q['c'] = []; + + // Result exponent may be one less then the current value of e. + // The coefficients of the Decimals from convertBase may have trailing zeros. + for ( i = 0; yc[i] == ( xc[i] || 0 ); i++ ); + + if ( yc[i] > ( xc[i] || 0 ) ) { + e--; + } + + if ( pr == null ) { + s = pr = Decimal['precision']; + rm = Decimal['rounding']; + } else if (dp) { + s = pr + ( x['e'] - y['e'] ) + 1; + } else { + s = pr; + } + + if ( s < 0 ) { + qc.push(1); + more = true; + } else { + + // Convert base 10 decimal places to base 1e7 decimal places. + s = s / logbase + 2 | 0; + i = 0; + + // divisor < 1e7 + if ( yL == 1 ) { + n = 0; + yc = yc[0]; + s++; + + // 'n' is the carry. + for ( ; ( i < xL || n ) && s--; i++ ) { + t = n * base + ( xc[i] || 0 ); + qc[i] = t / yc | 0; + n = t % yc | 0; + } + + more = n || i < xL; + + // divisor >= 1e7 + } else { + + // Normalise xc and yc so highest order digit of yc is >= base/2 + n = base / ( yc[0] + 1 ) | 0; + + if ( n > 1 ) { + yc = multiplyInteger( yc, n, base ); + xc = multiplyInteger( xc, n, base ); + yL = yc.length; + xL = xc.length; + } + + xi = yL; + rem = xc.slice( 0, yL ); + remL = rem.length; + + // Add zeros to make remainder as long as divisor. + for ( ; remL < yL; rem[remL++] = 0 ); + + yz = yc.slice(); + yz.unshift(0); + yc0 = yc[0]; + + if ( yc[1] >= base / 2 ) { + yc0++; + } + + do { + n = 0; + + // Compare divisor and remainder. + cmp = compare( yc, rem, yL, remL ); + + // If divisor < remainder. + if ( cmp < 0 ) { + + // Calculate trial digit, n. + rem0 = rem[0]; + + if ( yL != remL ) { + rem0 = rem0 * base + ( rem[1] || 0 ); + } + + // n will be how many times the divisor goes into the current remainder. + n = rem0 / yc0 | 0; + + /* + Algorithm: + 1. product = divisor * trial digit (n) + 2. if product > remainder: product -= divisor, n-- + 3. remainder -= product + 4. if product was < remainder at 2: + 5. compare new remainder and divisor + 6. If remainder > divisor: remainder -= divisor, n++ + */ + + if ( n > 1 ) { + + if ( n >= base ) { + n = base - 1; + } + + // product = divisor * trial digit. + prod = multiplyInteger( yc, n, base ); + prodL = prod.length; + remL = rem.length; + + // Compare product and remainder. + cmp = compare( prod, rem, prodL, remL ); + + // product > remainder. + if ( cmp == 1 ) { + n--; + + // Subtract divisor from product. + subtract( prod, yL < prodL ? yz : yc, prodL, base ); + } + } else { + + // cmp is -1. + // If n is 0, there is no need to compare yc and rem again below, so change cmp to 1 to avoid it. + // If n is 1 there IS a need to compare yc and rem again below. + if ( n == 0 ) { + cmp = n = 1; + } + prod = yc.slice(); + } + prodL = prod.length; + + if ( prodL < remL ) { + prod.unshift(0); + } + + // Subtract product from remainder. + subtract( rem, prod, remL, base ); + + // If product was < previous remainder. + if ( cmp == -1 ) { + remL = rem.length; + + // Compare divisor and new remainder. + cmp = compare( yc, rem, yL, remL ); + + // If divisor < new remainder, subtract divisor from remainder. + if ( cmp < 1 ) { + n++; + + // Subtract divisor from remainder. + subtract( rem, yL < remL ? yz : yc, remL, base ); + } + } + + remL = rem.length; + + } else if ( cmp === 0 ) { + n++; + rem = [0]; + } // if cmp === 1, n will be 0 + + // Add the next digit, n, to the result array. + qc[i++] = n; + + // Update the remainder. + if ( cmp && rem[0] ) { + rem[remL++] = xc[xi] || 0; + } else { + rem = [ xc[xi] ]; + remL = 1; + } + + } while ( ( xi++ < xL || rem[0] != null ) && s-- ); + + more = rem[0] != null; + } + + // Leading zero? + if ( !qc[0] ) { + qc.shift(); + } + } + + // If div is being used for base conversion. + if ( logbase == 1 ) { + q['e'] = e; + q['r'] = +more; + } else { + + // To calculate q.e, first get the number of digits of qc[0]. + for ( i = 1, s = qc[0]; s >= 10; s /= 10, i++ ); + q['e'] = i + e * logbase - 1; + + rnd( q, dp ? pr + q['e'] + 1 : pr, rm, more ); + } + + return q; + } + })(); /* @@ -2159,7 +2444,7 @@ e^x = 10^j, where j = x * log10(e) and log10(e) = ln(e) / ln(10) = 1 / ln(10), so j = x / ln(10) - j = Math.floor( x / Math.LN10 ); + j = mathfloor( x / Math.LN10 ); // Overflow/underflow? Estimate may be +-1 of true value. if ( j > Decimal['maxE'] + 1 || j < Decimal['minE'] - 1 ) { @@ -2188,17 +2473,19 @@ Use 2 * log10(2^k) + 5 to estimate the increase in precision necessary to ensure the first 4 rounding digits are correct. */ - guard = Math.log( Math.pow( 2, k ) ) / Math.LN10 * 2 + 5 | 0; + guard = Math.log( mathpow( 2, k ) ) / Math.LN10 * 2 + 5 | 0; sd += guard; + denom = pow = sum = new Decimal(one); Decimal['precision'] = sd; - for( ; ; ) { + for ( ; ; ) { pow = rnd( pow['times'](x), sd, 1 ); denom = denom['times'](++i); t = sum['plus']( div( pow, denom, sd, 1 ) ); - if ( t['c'].slice( 0, sd ).join('') === sum['c'].slice( 0, sd ).join('') ) { + if ( coefficientToString( t['c'] ).slice( 0, sd ) === + coefficientToString( sum['c'] ).slice( 0, sd ) ) { j = k; while ( j-- ) { @@ -2208,11 +2495,11 @@ /* Check to see if the first 4 rounding digits are [49]999. If so, repeat the summation with a higher precision, otherwise - E.g. with #precision: 18, #rounding: 1 + E.g. with precision: 18, rounding: 1 exp(18.404272462595034083567793919843761) = 98372560.1229999999 when it should be 98372560.123 - #sd - #guard is the index of first rounding digit. + sd - guard is the index of first rounding digit. */ if ( pr == null ) { @@ -2237,49 +2524,110 @@ /* - * Return a string representing the value of Decimal #n in normal or exponential notation + * Return a string representing the value of Decimal n in normal or exponential notation * rounded to the specified decimal places or significant digits. - * Called by #toString, #toExponential (#exp is 1), #toFixed, and #toPrecision (#exp is 2). - * #i is the index (with the value in normal notation) of the digit that may be rounded up. + * Called by toString, toExponential (k is 1), toFixed, and toPrecision (k is 2). + * i is the index (with the value in normal notation) of the digit that may be rounded up. + * j is the rounding mode, then the number of digits required including fraction-part trailing + * zeros. */ - function format( n, i, rm, exp ) { - var Decimal = n['constructor'], - e = ( n = new Decimal(n) )['e'], - c = n['c']; + function format( n, i, j, k ) { + var s, z, + Decimal = n['constructor'], + e = ( n = new Decimal(n) )['e']; - // +-Infinity or NaN? - if ( !c ) { + // i == null when toExponential(no arg), or toString() when x >= toExpPos etc. + if ( i == null ) { + j = 0; + } else { + rnd( n, ++i, j ); - return n.toString(); + // If toFixed, n['e'] may have changed if the value was rounded up. + j = k ? i : i + n['e'] - e; } - // Round? - if ( c.length > ++i ) { - rnd( n, i, rm ); - } - - // If #toFixed, n['e'] may have changed if the value was rounded up. - e = exp ? i : i + n['e'] - e; - - // Append zeros? - for ( ; c.length < e; c.push(0) ) { - } e = n['e']; + s = coefficientToString( n['c'] ); /* - #toPrecision returns exponential notation if the number of significant digits specified + toPrecision returns exponential notation if the number of significant digits specified is less than the number of digits necessary to represent the integer part of the value in normal notation. */ - return exp == 1 || exp == 2 && ( i <= e || e <= Decimal['toExpNeg'] ) - // Exponential notation. - ? ( n['s'] < 0 && c[0] ? '-' : '' ) + - ( c.length > 1 ? c[0] + '.' + c.slice(1).join('') : c[0] ) + - ( e < 0 ? 'e' : 'e+' ) + e + // Exponential notation. + if ( k == 1 || k == 2 && ( i <= e || e <= Decimal['toExpNeg'] ) ) { - // Normal notation. - : n.toString(); + // Append zeros? + for ( ; s.length < j; s += '0' ); + + if ( s.length > 1 ) { + s = s.charAt(0) + '.' + s.slice(1); + } + + s += ( e < 0 ? 'e' : 'e+' ) + e; + + // Normal notation. + } else { + k = s.length; + + // Negative exponent? + if ( e < 0 ) { + z = j - k; + + // Prepend zeros. + for ( ; ++e; s = '0' + s ); + s = '0.' + s; + + // Positive exponent? + } else { + + if ( ++e > k ) { + z = j - e; + + // Append zeros. + for ( e -= k; e-- ; s += '0' ); + + if ( z > 0 ) { + s += '.'; + } + + } else { + z = j - k; + + if ( e < k ) { + s = s.slice( 0, e ) + '.' + s.slice(e); + } else if ( z > 0 ) { + s += '.'; + } + } + } + + // Append more zeros? + if ( z > 0 ) { + + for ( ; z--; s += '0' ); + } + } + + return n['s'] < 0 && n['c'][0] ? '-' + s : s; + } + + + function getCoeffLength(c) { + var v = c.length - 1, + n = v * LOGBASE + 1; + + if ( v = c[v] ) { + + // Subtract the number of trailing zeros of the last number. + for ( ; v % 10 == 0; v /= 10, n-- ); + + // Add the number of digits of the first number. + for ( v = c[0]; v >= 10; v /= 10, n++ ); + } + + return n; } @@ -2306,7 +2654,7 @@ /* - * Use 'exponentiation by squaring' for small integers. Called by #convertBase and #pow. + * Use 'exponentiation by squaring' for small integers. Called by convertBase and pow. */ function intPow( Decimal, x, i ) { var r = new Decimal( Decimal['ONE'] ); @@ -2320,7 +2668,6 @@ if ( !i ) { - break; } x = x['times'](x); @@ -2344,20 +2691,20 @@ * */ function ln( y, pr ) { - var denom, e, num, rep, sd, sum, t, x1, x2, + var c, c0, denom, e, num, rep, sd, sum, t, x1, x2, n = 1, guard = 10, x = y, - c = x['c'], + xc = x['c'], Decimal = x['constructor'], one = Decimal['ONE'], rm = Decimal['rounding'], precision = Decimal['precision']; - // #x < 0 or +-Infinity/NaN or 0 or 1. - if ( x['s'] < 0 || !c || !c[0] || !x['e'] && c[0] == 1 && c.length == 1 ) { + // x < 0 or +-Infinity/NaN or 0 or 1. + if ( x['s'] < 0 || !xc || !xc[0] || !x['e'] && xc[0] == 1 && xc.length == 1 ) { - return new Decimal( c && !c[0] ? -1 / 0 : x['s'] != 1 ? NaN : c ? 0 : x ); + return new Decimal( xc && !xc[0] ? -1 / 0 : x['s'] != 1 ? NaN : xc ? 0 : x ); } if ( pr == null ) { @@ -2369,6 +2716,9 @@ Decimal['precision'] = sd += guard; + c = coefficientToString(xc); + c0 = c.charAt(0); + if ( Math.abs( e = x['e'] ) < 1.5e15 ) { /* @@ -2376,42 +2726,37 @@ The series converges faster the closer the argument is to 1, so using ln(a^b) = b * ln(a), ln(a) = ln(a^b) / b multiply the argument by itself until the leading digits of the significand are 7, 8, - 9, 10, 11, 12 or 13 recording the number of multiplications so the sum of the series + 9, 10, 11, 12 or 13, recording the number of multiplications so the sum of the series can later be divided by this number, then separate out the power of 10 using ln(a*10^b) = ln(a) + b*ln(10). */ - // max #n is 6 ( gives 0.7 - 1.3 ) - while ( c[0] < 7 && c[0] != 1 || c[0] == 1 && c[1] > 3 ) { - // max #n is 21 ( gives 0.9, 1.0 or 1.1 ) ( 9e15 / 21 = 4.2e14 ). - //while ( c[0] < 9 && c[0] != 1 || c[0] == 1 && c[1] > 1 ) { + // max n is 21 ( gives 0.9, 1.0 or 1.1 ) ( 9e15 / 21 = 4.2e14 ). + //while ( c0 < 9 && c0 != 1 || c0 == 1 && c.charAt(1) > 1 ) { + // max n is 6 ( gives 0.7 - 1.3 ) + while ( c0 < 7 && c0 != 1 || c0 == 1 && c.charAt(1) > 3 ) { x = x['times'](y); - c = x['c']; + c = coefficientToString( x['c'] ); + c0 = c.charAt(0); n++; } e = x['e']; - if ( c[0] > 1 ) { - - if ( n == 1 ) { - x = new Decimal( '0.' + c.join('') ); - } else { - x['e'] = -1; - } + if ( c0 > 1 ) { + x = new Decimal( '0.' + c ); e++; } else { - x = new Decimal( '1.' + c.slice(1).join('') ); + x = new Decimal( c0 + '.' + c.slice(1) ); } } else { /* - The argument reduction method above may result in overflow if the argument #y is a + The argument reduction method above may result in overflow if the argument y is a massive number with exponent >= 1500000000000000 ( 9e15 / 6 = 1.5e15 ), so instead recall this function using ln(x*10^e) = ln(x) + e*ln(10). */ - x = new Decimal(x); - x['e'] = 0; + x = new Decimal( c0 + '.' + c.slice(1) ); if ( sd + 2 > LN10.length ) { ifExceptionsThrow( Decimal, 1, sd + 2, 'ln' ); @@ -2426,7 +2771,7 @@ return pr == null ? rnd( x, precision, rm, external = true ) : x; } - // #x1 is #x reduced to a value near 1. + // x1 is x reduced to a value near 1. x1 = x; /* @@ -2439,15 +2784,16 @@ x2 = rnd( x['times'](x), sd, 1 ); denom = 3; - for( ; ; ) { + for ( ; ; ) { num = rnd( num['times'](x2), sd, 1 ); t = sum['plus']( div( num, new Decimal(denom), sd, 1 ) ); - if ( t['c'].slice( 0, sd ).join('') === sum['c'].slice( 0, sd ).join('') ) { + if ( coefficientToString( t['c'] ).slice( 0, sd ) === + coefficientToString( sum['c'] ).slice( 0, sd ) ) { sum = sum['times'](2); /* - Reverse the argument reduction. Check that #e is not 0 because, as well as + Reverse the argument reduction. Check that e is not 0 because, as well as preventing an unnecessary calculation, -0 + 0 = +0 and to ensure correct rounding later -0 needs to stay -0. */ @@ -2465,14 +2811,14 @@ sum = div( sum, new Decimal(n), sd, 1 ); /* - Is #rm > 3 and the first 4 rounding digits 4999, or #rm < 4 (or the summation has + Is rm > 3 and the first 4 rounding digits 4999, or rm < 4 (or the summation has been repeated previously) and the first 4 rounding digits 9999? If so, restart the summation with a higher precision, otherwise - E.g. with #precision: 12, #rounding: 1 + E.g. with precision: 12, rounding: 1 ln(135520028.6126091714265381533) = 18.7246299999 when it should be 18.72463. - #sd - #guard is the index of first rounding digit. + sd - guard is the index of first rounding digit. */ if ( pr == null ) { @@ -2499,42 +2845,108 @@ /* - * Round #x to #sd significant digits using rounding mode #rm. Check for over/under-flow. + * Round x to sd significant digits using rounding mode rm. Check for over/under-flow. */ - function rnd( x, sd, rm, r, b ) { - var rd, half, isNeg, xc, + function rnd( x, sd, rm, r ) { + var digits, i, j, k, n, rd, xc, xci, Decimal = x['constructor']; - // Don't round if #sd is null or undefined. - if ( sd != rd ) { + // Don't round if sd is null or undefined. + r: if ( sd != i ) { + // Infinity/NaN. if ( !( xc = x['c'] ) ) { return x; } - isNeg = x['s'] < 0, - half = ( b = b || 10 ) / 2; + /* + rd, the rounding digit, i.e. the digit after the digit that may be rounded up, + n, a base 1e7 number, the element of xc containing rd, + xci, the index of n within xc, + digits, the number of digits of n, + i, what would be the index of rd within n if all the numbers were 7 digits long (i.e. they had leading zeros) + j, if > 0, the actual index of rd within n (if < 0, rd is a leading zero), + nLeadingZeros, the number of leading zeros n would have if it were 7 digits long. + */ - // #rd is the rounding digit, i.e. the digit after the digit that may be rounded up. - rd = xc[sd]; - r = r || sd < 0 || xc[sd + 1] != null; + // Get the length of the first element of the coefficient array xc. + for ( digits = 1, k = xc[0]; k >= 10; k /= 10, digits++ ); + + i = sd - digits; + + // Is the rounding digit in the first element of xc? + if ( i < 0 ) { + i += LOGBASE; + j = sd; + n = xc[ xci = 0 ]; + + // Get the rounding digit at index j of n. + rd = n / mathpow( 10, digits - j - 1 ) % 10 | 0; + } else { + xci = Math.ceil( ( i + 1 ) / LOGBASE ); + + if ( xci >= xc.length ) { + + if (r) { + + // Needed by exp, ln and sqrt. + for ( ; xc.length <= xci; xc.push(0) ); + + n = rd = 0; + digits = 1; + i %= LOGBASE; + j = i - LOGBASE + 1; + } else { + + break r; + } + } else { + n = k = xc[xci]; + + // Get the number of digits of n. + for ( digits = 1; k >= 10; k /= 10, digits++ ); + + // Get the index of rd within n. + i %= LOGBASE; + + // Get the index of rd within n, adjusted for leading zeros. + // The number of leading zeros of n is given by LOGBASE - digits. + j = i - LOGBASE + digits; + + // Get the rounding digit at index j of n. + // Floor using Math.floor instead of | 0 as rd may be outside int range. + rd = j < 0 ? 0 : mathfloor( n / mathpow( 10, digits - j - 1 ) % 10 ); + } + } + + r = r || sd < 0 || + // Are there any non-zero digits after the rounding digit? + xc[xci + 1] != null || ( j < 0 ? n : n % mathpow( 10, digits - j - 1 ) ); + + /* + The expression n % mathpow( 10, digits - j - 1 ) returns all the digits of n to the + right of the digit at (left-to-right) index j, + e.g. if n is 908714 and j is 2, the expression will give 714. + */ r = rm < 4 - ? ( rd != null || r ) && ( rm == 0 || rm == 2 && !isNeg || rm == 3 && isNeg ) - : rd > half || rd == half && ( rm == 4 || r || rm == 6 && xc[sd - 1] & 1 || - rm == 7 && !isNeg || rm == 8 && isNeg ); + ? ( rd || r ) && ( rm == 0 || rm == ( x['s'] < 0 ? 3 : 2 ) ) + : rd > 5 || rd == 5 && ( rm == 4 || r || + // Check whether the digit to the left of the rounding digit is odd. + rm == 6 && ( ( i > 0 ? j > 0 ? n / mathpow( 10, digits - j ) : 0 : xc[xci - 1] ) % 10 ) & 1 || + rm == ( x['s'] < 0 ? 8 : 7 ) ); if ( sd < 1 || !xc[0] ) { xc.length = 0; if (r) { - // Convert #sd to decimal places. - sd = sd - x['e'] - 1; + // Convert sd to decimal places. + sd -= x['e'] + 1; // 1, 0.1, 0.01, 0.001, 0.0001 etc. - xc[0] = 1; + xc[0] = mathpow( 10, sd % LOGBASE ); x['e'] = -sd || 0; } else { @@ -2545,34 +2957,62 @@ return x; } - // Truncate excess digits. - if ( xc.length > sd ) { - xc.length = sd; + // Remove excess digits. + + if ( i == 0 ) { + xc.length = xci; + k = 1; + xci--; + } else { + xc.length = xci + 1; + k = mathpow( 10, LOGBASE - i ); + + // E.g. 56700 becomes 56000 if 7 is the rounding digit. + // j > 0 means i > number of leading zeros of n. + xc[xci] = j > 0 ? ( n / mathpow( 10, digits - j ) % mathpow( 10, j ) | 0 ) * k : 0; } - sd--; // Round up? if (r) { - // Set to zero any undefined elements before the digit to be rounded up. - // Only used by #ln? - for ( rd = sd; xc[rd] == null; xc[rd--] = 0 ) { - } + for ( ; ; ) { - // Rounding up may mean the previous digit has to be rounded up and so on. - for ( --b; ++xc[sd] > b; ) { - xc[sd] = 0; + // Is the digit to be rounded up in the first element of xc. + if ( xci == 0 ) { - if ( !sd-- ) { - ++x['e']; - xc.unshift(1); + // i will be the length of xc[0] before k is added. + for ( i = 1, j = xc[0]; j >= 10; j /= 10, i++ ); + + j = xc[0] += k; + + for ( k = 1; j >= 10; j /= 10, k++ ); + + // if i != k the length has increased. + if ( i != k ) { + x['e']++; + + if ( xc[0] == BASE ) { + xc[0] = 1; + } + } + + break; + } else { + xc[xci] += k; + + if ( xc[xci] != BASE ) { + + break; + } + + xc[xci--] = 0; + k = 1; } } } // Remove trailing zeros. - for ( sd = xc.length; !xc[--sd]; xc.pop() ) { - } + for ( i = xc.length; xc[--i] === 0; xc.pop() ); } if (external) { @@ -2602,26 +3042,26 @@ /* - * The following emulations or wrappers of #Math object functions are currently + * The following emulations or wrappers of Math object functions are currently * commented-out and not in the public API. * - * #abs - * #acos - * #asin - * #atan - * #atan2 - * #ceil - * #cos - * #floor - * #round - * #sin - * #tan - * #trunc + * abs + * acos + * asin + * atan + * atan2 + * ceil + * cos + * floor + * round + * sin + * tan + * trunc */ /* - * Return a new Decimal whose value is the absolute value of #n. + * Return a new Decimal whose value is the absolute value of n. * * n {number|string|Decimal} * @@ -2630,7 +3070,7 @@ /* - * Return a new Decimal whose value is the arccosine in radians of #n. + * Return a new Decimal whose value is the arccosine in radians of n. * * n {number|string|Decimal} * @@ -2639,7 +3079,7 @@ /* - * Return a new Decimal whose value is the arcsine in radians of #n. + * Return a new Decimal whose value is the arcsine in radians of n. * * n {number|string|Decimal} * @@ -2648,7 +3088,7 @@ /* - * Return a new Decimal whose value is the arctangent in radians of #n. + * Return a new Decimal whose value is the arctangent in radians of n. * * n {number|string|Decimal} * @@ -2657,7 +3097,7 @@ /* - * Return a new Decimal whose value is the arctangent in radians of #y/#x in the range + * Return a new Decimal whose value is the arctangent in radians of y/x in the range * -PI to PI (inclusive). * * y {number|string|Decimal} The y-coordinate. @@ -2668,7 +3108,7 @@ /* - * Return a new Decimal whose value is #n round to an integer using ROUND_CEIL. + * Return a new Decimal whose value is n round to an integer using ROUND_CEIL. * * n {number|string|Decimal} * @@ -2679,17 +3119,17 @@ /* * Configure global settings for a Decimal constructor. * - * #obj is an object with any of the following properties, + * obj is an object with any of the following properties, * - * #precision {number} - * #rounding {number} - * #toExpNeg {number} - * #toExpPos {number} - * #minE {number} - * #maxE {number} - * #errors {boolean|number} - * #crypto {boolean|number} - * #modulo {number} + * precision {number} + * rounding {number} + * toExpNeg {number} + * toExpPos {number} + * minE {number} + * maxE {number} + * errors {boolean|number} + * crypto {boolean|number} + * modulo {number} * * E.g. * Decimal.config({ precision: 20, rounding: 4 }) @@ -2707,7 +3147,7 @@ return Decimal; } - // #precision {number|number[]} Integer, 1 to MAX_DIGITS inclusive. + // precision {number|number[]} Integer, 1 to MAX_DIGITS inclusive. if ( ( v = obj[ p = 'precision' ] ) != u ) { if ( !( outOfRange = v < 1 || v > MAX_DIGITS ) && parse(v) == v ) { @@ -2720,7 +3160,7 @@ } } - // #rounding {number} Integer, 0 to 8 inclusive. + // rounding {number} Integer, 0 to 8 inclusive. if ( ( v = obj[ p = 'rounding' ] ) != u ) { if ( !( outOfRange = v < 0 || v > 8 ) && parse(v) == v ) { @@ -2733,11 +3173,11 @@ } } - // #toExpNeg {number} Integer, -EXP_LIMIT to 0 inclusive. + // toExpNeg {number} Integer, -EXP_LIMIT to 0 inclusive. if ( ( v = obj[ p = 'toExpNeg' ] ) != u ) { if ( !( outOfRange = v < -EXP_LIMIT || v > 0 ) && parse(v) == v ) { - Decimal[p] = Math.floor(v); + Decimal[p] = mathfloor(v); } else { // 'config() toExpNeg not an integer: {v}' @@ -2746,11 +3186,11 @@ } } - // #toExpPos {number} Integer, 0 to EXP_LIMIT inclusive. + // toExpPos {number} Integer, 0 to EXP_LIMIT inclusive. if ( ( v = obj[ p = 'toExpPos' ] ) != u ) { if ( !( outOfRange = v < 0 || v > EXP_LIMIT ) && parse(v) == v ) { - Decimal[p] = Math.floor(v); + Decimal[p] = mathfloor(v); } else { // 'config() toExpPos not an integer: {v}' @@ -2759,11 +3199,11 @@ } } - // #minE {number} Integer, -EXP_LIMIT to 0 inclusive. + // minE {number} Integer, -EXP_LIMIT to 0 inclusive. if ( ( v = obj[ p = 'minE' ] ) != u ) { if ( !( outOfRange = v < -EXP_LIMIT || v > 0 ) && parse(v) == v ) { - Decimal[p] = Math.floor(v); + Decimal[p] = mathfloor(v); } else { // 'config() minE not an integer: {v}' @@ -2772,11 +3212,11 @@ } } - // #maxE {number} Integer, 0 to EXP_LIMIT inclusive. + // maxE {number} Integer, 0 to EXP_LIMIT inclusive. if ( ( v = obj[ p = 'maxE' ] ) != u ) { if ( !( outOfRange = v < 0 || v > EXP_LIMIT ) && parse(v) == v ) { - Decimal[p] = Math.floor(v); + Decimal[p] = mathfloor(v); } else { // 'config() maxE not an integer: {v}' @@ -2785,7 +3225,7 @@ } } - // #errors {boolean|number} true, false, 1 or 0. + // errors {boolean|number} true, false, 1 or 0. if ( ( v = obj[ p = 'errors' ] ) != u ) { if ( v === !!v || v === 1 || v === 0 ) { @@ -2798,7 +3238,7 @@ } } - // #crypto {boolean|number} true, false, 1 or 0. + // crypto {boolean|number} true, false, 1 or 0. if ( ( v = obj[ p = 'crypto' ] ) != u ) { if ( v === !!v || v === 1 || v === 0 ) { @@ -2810,7 +3250,7 @@ } } - // #modulo {number} Integer, 0 to 9 inclusive. + // modulo {number} Integer, 0 to 9 inclusive. if ( ( v = obj[ p = 'modulo' ] ) != u ) { if ( !( outOfRange = v < 0 || v > 9 ) && parse(v) == v ) { @@ -2828,7 +3268,7 @@ /* - * Return a new Decimal whose value is the cosine of #n. + * Return a new Decimal whose value is the cosine of n. * * n {number|string|Decimal} A number given in radians. * @@ -2837,7 +3277,7 @@ /* - * Return a new Decimal whose value is the exponential of #n, + * Return a new Decimal whose value is the exponential of n, * * n {number|string|Decimal} The power to which to raise the base of the natural log. * @@ -2846,7 +3286,7 @@ /* - * Return a new Decimal whose value is #n round to an integer using ROUND_FLOOR. + * Return a new Decimal whose value is n round to an integer using ROUND_FLOOR. * * n {number|string|Decimal} * @@ -2855,7 +3295,7 @@ /* - * Return a new Decimal whose value is the natural logarithm of #n. + * Return a new Decimal whose value is the natural logarithm of n. * * n {number|string|Decimal} * @@ -2864,7 +3304,7 @@ /* - * Return a new Decimal whose value is the log of #x to the base #y, or to base 10 if no + * Return a new Decimal whose value is the log of x to the base y, or to base 10 if no * base is specified. * * log[y](x) @@ -2877,7 +3317,7 @@ /* - * Handle #max and #min. #ltgt is 'lt' or 'gt'. + * Handle max and min. ltgt is 'lt' or 'gt'. */ function maxOrMin( Decimal, args, ltgt ) { var m, n, @@ -2935,7 +3375,8 @@ if ( typeof n != 'string' ) { - // If #n is a number, check if minus zero. + // TODO: modify so regex test below is avoided if type is number. + // If n is a number, check if minus zero. n = ( isNum = typeof n == 'number' || toString.call(n) == '[object Number]' ) && n === 0 && 1 / n < 0 ? '-0' : n + ''; } @@ -2946,12 +3387,12 @@ // Determine sign. x['s'] = n.charAt(0) == '-' ? ( n = n.slice(1), -1 ) : 1; - // Either #n is not a valid Decimal or a base has been specified. + // Either n is not a valid Decimal or a base has been specified. } else { /* Enable exponential notation to be used with base 10 argument. - Ensure return value is rounded to #precision as with other bases. + Ensure return value is rounded to precision as with other bases. */ if ( b == 10 ) { @@ -2971,7 +3412,6 @@ // Remove the `.` from e.g. '1.', and replace e.g. '.1' with '0.1'. n = n.replace( /\.$/, '' ).replace( /^\./, '0.' ); - // Any number in exponential form will fail due to the e+/-. if ( valid = new RegExp( '^' + d + '(?:\\.' + d + ')?$', b < 37 ? 'i' : '' ).test(n) @@ -3033,7 +3473,6 @@ // Decimal point? if ( ( e = n.indexOf('.') ) > -1 ) { - n = n.replace( '.', '' ); } @@ -3054,33 +3493,57 @@ } // Determine leading zeros. - for ( i = 0; n.charAt(i) == '0'; i++ ) { - } + for ( i = 0; n.charAt(i) == '0'; i++ ); - if ( i == ( b = n.length ) ) { + // Determine trailing zeros. + for ( b = n.length; n.charAt(--b) == '0'; ); - // Zero. - x['c'] = [ x['e'] = 0 ]; - } else { + n = n.slice( i, b + 1 ); + + if (n) { + b = n.length; // Disallow numbers with over 15 significant digits if number type. - if ( isNum && b > 15 && n.slice(i).length > 15 ) { + if ( isNum && b > 15 ) { // '{method} number type has more than 15 significant digits: {n}' ifExceptionsThrow( Decimal, 0, orig ); } - // Determine trailing zeros. - for ( ; n.charAt(--b) == '0'; ) { - } - - x['e'] = e - i - 1; + x['e'] = e = e - i - 1; x['c'] = []; - // Convert string to array of digits (without leading and trailing zeros). - for ( e = 0; i <= b; x['c'][e++] = +n.charAt(i++) ) { + // Transform base + + // e is the base 10 exponent. + // i is where to slice n to get the first element of the coefficient array. + i = ( e + 1 ) % LOGBASE; + + if ( e < 0 ) { + i += LOGBASE; } + // b is n.length. + if ( i < b ) { + + if (i) { + x['c'].push( +n.slice( 0, i ) ); + } + + for ( b -= LOGBASE; i < b; ) { + x['c'].push( +n.slice( i, i += LOGBASE ) ); + } + + n = n.slice(i); + i = LOGBASE - n.length; + } else { + i -= b; + } + + for ( ; i--; n += '0' ); + + x['c'].push( +n ); + if (external) { // Overflow? @@ -3096,14 +3559,19 @@ x['c'] = [ x['e'] = 0 ]; } } + } else { + + // Zero. + x['c'] = [ x['e'] = 0 ]; } + id = 0; } })(); /* - * Return a new Decimal whose value is #x raised to the power #y. + * Return a new Decimal whose value is x raised to the power y. * * x {number|string|Decimal} The base. * y {number|string|Decimal} The exponent. @@ -3113,251 +3581,138 @@ /* - * Generate a new Decimal with a random value. + * Returns a new Decimal with a random value equal to or greater than 0 and less than 1, and + * with dp, or Decimal.precision if dp is omitted, decimal places (or less if trailing + * zeros are produced). + * + * [dp] {number} Decimal places. Integer, 0 to MAX_DIGITS inclusive. + * */ - var random = (function () { - - /* - * #crypto false. - * - * Return a string of random decimal digits. - * If #max is falsey return up to 14 digits (almost always 13 or 14 digits), - * else return a number >= 0 and < #max (#max < 256). - */ - function getMathRandom(max) { - var r = Math.random(); - - /* - Add 1 to avoid exponential notation and keep leading zeros. Omit the first and the - last two digits for a maximum of 14 significant digits and to ensure that trailing - digits can be zero. - */ - return max ? ( r * max | 0 ) + '' : ( 1 + r + '' ).slice( 2, -2 ); - } - - - /* - * #crypto true. - * Browsers supporting crypto.getRandomValues. - * - * Return a string of random decimal digits. - * If #max is falsey return 9 digits, else return a number >= 0 and < #max (#max < 256). - */ - function getRandomValues(max) { - var n; - - return max - - // 0 >= n < 256 - ? ( n = crypto['getRandomValues']( new global['Uint8Array'](1) )[0], - n > ( 256 / max | 0 ) * max - 1 - - // Probability of recall if #max is 10 is 6 / 256 = 0.023 (i.e. 1 in 42.7). - ? getRandomValues(max) - : n % max + '' ) - - // 0 >= n < 4294967296 - : ( n = crypto['getRandomValues']( new global['Uint32Array'](1) )[0], - n >= 4e9 - - // Probability of recall is 294967297 / 4294967296 = 0.0687 (i.e. 1 in 14.6). - ? getRandomValues(max) - - // Add 1e9 so 1000000000 >= n <= 4999999999 and omit leading digit. - : ( n + 1e9 + '' ).slice(1) ); - } - - - /* - * #crypto true. - * Node.js supporting crypto.randomBytes. - * - * Return a string of random decimal digits. - * If #max is falsey return 14 digits, else return a number >= 0 and < #max (#max < 256). - */ - function getRandomBytes(max) { - var buf, n, - rb = crypto['randomBytes']; - - return max - ? ( n = rb(1)[0], n > ( 256 / max | 0 ) * max - 1 - ? getRandomBytes(max) - : n % max + '' ) - - // 01000011 0011XXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX - : ( buf = rb(8), buf[0] = 0x43, buf[1] = buf[1] & 0xf | 0x30, - - /* - (mantissa all zeros) 4503599627370496 >= n <= 9007199254740991 (mantissa all ones). - 4503599627370496 - 3599627370496 = 4500000000000000 - 9007199254740991 - 3599627370496 = 9003599627370495 - */ - n = buf.readDoubleBE(0), - n > 9003599627370495 - - /* - Probability of recall is - 3599627370497 / 4503599627370496 = 0.000799 (i.e. 1 in 1251). - */ - ? getRandomBytes(max) - - /* - Subtracting 4503599627370496 gives 0 >= n <= 4499999999999999, - so subtracting 1e15 less than that gives - 1000000000000000 >= n <= 5499999999999999. - Return the last 14 digits as a string. - */ - : ( n - 3503599627370496 + '' ).slice(2) ); - } - - /* - * Returns a new Decimal with a random value equal to or greater than 0 and lower in - * magnitude than #limit. - * - * If #limit is omitted then it will be 1 and the return value will have #precision - * significant digits (or less if trailing zeros are produced). - * - * If #limit is included and #pr is omitted then the return value will be an integer. If - * #pr is included, the return value will have #pr significant digits (or less if - * trailing zeros are produced). - * - * [limit] {number|string|Decimal} - * [pr] {number} Significant digits. Integer, 0 to MAX_DIGITS inclusive. - * - */ - return function ( limit, pr ) { - var c, e, i, ld, n, one, rd, str, - Decimal = this, - r = new Decimal(0), - rand = getMathRandom; - - // null/+-Infinity/NaN? - if ( one = limit == e || !( id = 14, limit = new Decimal(limit) )['c'] && - !ifExceptionsThrow( Decimal, 'limit must be finite', limit, 'random' ) ) { - limit = new Decimal( Decimal['ONE'] ); - - // Zero? - } else if ( !limit['c'][0] ) { - - return r; - } - - if ( Decimal['crypto'] ) { - - // Recent browsers. - if ( crypto['getRandomValues'] ) { - rand = getRandomValues; - - // Node.js. - } else if ( crypto['randomBytes'] ) { - rand = getRandomBytes; - } - } - - e = limit['e']; - n = ( c = limit['c'] ).length; - - // Ensure #r < limit. - do { - i = 0; - str = rand( c[0] + 1 ) + rand(); - - do { - ld = c[i]; // #limit digit - rd = str.charAt(i++); // random digit - } while ( ld == rd ); - } while ( rd > ld || i > n || rd == '' ); - - // Decrement exponent of result for every leading zero. - for ( i = 0; str.charAt(i) == '0'; i++, e-- ) { - } - - if (one) { - pr = Decimal['precision']; - } else if ( pr == null || !checkArg( limit, pr, 'random', 1 ) ) { - pr = e + 1; - } else { - pr |= 0; - } - - pr += i; - - // Add further random digits. - while ( str.length < pr ) { - str += rand(); - } - - // Determine trailing zeros. - for ( ; str.charAt(--pr) == '0'; ) { - } - - if ( ++pr > 0 ) { - - // Convert #str to number array without leading and trailing zeros. - for ( r['c'] = []; i < pr; r['c'].push( +str.charAt(i++) ) ) { - } - } else { - - // Zero. - r['c'] = [ e = 0 ]; - } - - r['e'] = e; - r['s'] = limit['s']; - - return r; - } - })(); - - - /* - * Not currently in public api. - * - * Generate random numbers for testing purposes. - * - * Returns a Decimal with a random sign, a random exponent in the range [-MIN.E, MAX-E] - * and a random number of significant digits in the range [1, #precision]. - * - * Within the limits of the #precision setting, this method can produce any finite Decimal. - * It will not, though, produce a uniform distribution. Intentionally, it is heavily biased - * toward smaller exponents. - * - * Math.random is always used as the source of randomness. - * - function randomE() { - var i, + function random(dp) { + var a, n, v, + i = 0, + r = [], Decimal = this, - // 1 in 4 chance of negative exponent. - isNeg = Math.random() < 0.25, - n = Math.floor( Math.random() * ( ( - isNeg ? -Decimal['minE'] : Decimal['maxE'] ) + 1 ) ) + '', - c = [ Math.random() * 9 + 1 | 0 ], - pr = i = Math.random() * Decimal['precision'] | 0, - r = new Decimal( Decimal['ONE'] ); + rand = new Decimal( Decimal['ONE'] ); - while ( i-- ) { - c.push( Math.random() * 10 | 0 ); - } - c[pr] = Math.random() * 9 + 1 | 0; - - // Further increase likelihood of smaller exponent. Comment-out if not required. - while ( Math.random() < 0.9 ) { - n = n.slice( Math.random() * n.length | 0 ); + if ( dp == null || !checkArg( rand, dp, 'random' ) ) { + dp = Decimal['precision']; + } else { + dp |= 0; } - r['e'] = ( isNeg ? -1 : 1 ) * n.slice( Math.random() * n.length | 0 ); - r['c'] = r['e'] == Decimal['minE'] ? [1] : c; - r['s'] = Math.random() < 0.4 ? -1 : 1; + n = Math.ceil( dp / LOGBASE ); - return r; + if ( Decimal['crypto'] ) { + + // Browsers supporting crypto.getRandomValues. + if ( crypto && crypto['getRandomValues'] ) { + + a = crypto['getRandomValues']( new Uint32Array(n) ); + + for ( ; i < n; ) { + v = a[i]; + + // 0 >= v < 4294967296 + // Probability that v >= 4.29e9, is 4967296 / 4294967296 = 0.00116 (1 in 865). + if ( v >= 4.29e9 ) { + + a[i] = crypto['getRandomValues']( new Uint32Array(1) )[0]; + } else { + + // 0 <= v <= 4289999999 + // 0 <= ( v % 1e7 ) <= 9999999 + r[i++] = v % 1e7; + } + } + + // Node.js supporting crypto.randomBytes. + } else if ( crypto && crypto['randomBytes'] ) { + + // buffer + a = crypto['randomBytes']( n *= 4 ); + + for ( ; i < n; ) { + + // 0 <= v < 2147483648 + v = a[i] + ( a[i + 1] << 8 ) + ( a[i + 2] << 16 ) + + ( ( a[i + 3] & 0x7f ) << 24 ); + + // Probability that v >= 2.14e9, is 7483648 / 2147483648 = 0.0035 (1 in 286). + if ( v >= 2.14e9 ) { + crypto['randomBytes'](4).copy( a, i ); + } else { + + // 0 <= v <= 4289999999 + // 0 <= ( v % 1e7 ) <= 9999999 + r.push( v % 1e7 ); + i += 4; + } + } + i = n / 4; + + } else { + ifExceptionsThrow( Decimal, 'crypto unavailable', crypto, 'random' ); + } + } + + // Use Math.random: either Decimal.crypto is false or crypto is unavailable and errors is false. + if (!i) { + + for ( ; i < n; ) { + r[i++] = Math.random() * 1e7 | 0; + } + } + + n = r[--i]; + dp %= LOGBASE; + + // Convert trailing digits to zeros according to dp. + if ( n && dp ) { + v = mathpow( 10, LOGBASE - dp ); + r[i] = ( n / v | 0 ) * v; + } + + // Remove trailing elements which are zero. + for ( ; r[i] === 0; i-- ) { + r.pop(); + } + + // Zero? + if ( i < 0 ) { + r = [ n = 0 ]; + } else { + n = -1; + + // Remove leading elements which are zero and adjust exponent accordingly. + for ( ; r[0] === 0; ) { + r.shift(); + n -= LOGBASE; + } + + // Count the digits of the first element of r to determine leading zeros. + for ( i = 1, v = r[0]; v >= 10; ) { + v /= 10; + i++; + } + + // Adjust the exponent for leading zeros of the first element of r. + if ( i < LOGBASE ) { + n -= LOGBASE - i; + } + } + + rand['e'] = n; + rand['c'] = r; + + return rand; } - */ /* - * Return a new Decimal whose value is #n round to an integer using rounding mode #rounding. + * Return a new Decimal whose value is n round to an integer using rounding mode rounding. * - * To emulate Math.round, set #rounding to 7 (ROUND_HALF_CEIL). + * To emulate Math.round, set rounding to 7 (ROUND_HALF_CEIL). * * n {number|string|Decimal} * @@ -3370,7 +3725,7 @@ /* - * Return a new Decimal whose value is the sine of #n. + * Return a new Decimal whose value is the sine of n. * * n {number|string|Decimal} A number given in radians. * @@ -3379,7 +3734,7 @@ /* - * Return a new Decimal whose value is the square root of #n. + * Return a new Decimal whose value is the square root of n. * * n {number|string|Decimal} * @@ -3388,7 +3743,7 @@ /* - * Return a new Decimal whose value is the tangent of #n. + * Return a new Decimal whose value is the tangent of n. * * n {number|string|Decimal} A number given in radians. * @@ -3397,7 +3752,7 @@ /* - * Return a new Decimal whose value is #n truncated to an integer. + * Return a new Decimal whose value is n truncated to an integer. * * n {number|string|Decimal} * @@ -3467,7 +3822,7 @@ Decimal['precision'] = 20; // 1 to MAX_DIGITS /* - The rounding mode used when rounding to #precision. + The rounding mode used when rounding to precision. ROUND_UP 0 Away from zero. ROUND_DOWN 1 Towards zero. @@ -3505,11 +3860,11 @@ */ Decimal['modulo'] = 1; // 0 to 9 - // The exponent value at and beneath which #toString returns exponential notation. + // The exponent value at and beneath which toString returns exponential notation. // Number type: -7 Decimal['toExpNeg'] = -7; // 0 to -EXP_LIMIT - // The exponent value at and above which #toString returns exponential notation. + // The exponent value at and above which toString returns exponential notation. // Number type: 21 Decimal['toExpPos'] = 21; // 0 to EXP_LIMIT @@ -3578,7 +3933,6 @@ Decimal['pow'] = pow; Decimal['sqrt'] = sqrt; Decimal['random'] = random; - //Decimal['randomE'] = randomE; if ( obj != null ) { Decimal['config'](obj); diff --git a/decimal.min.js b/decimal.min.js index abf138a..18dbb87 100644 --- a/decimal.min.js +++ b/decimal.min.js @@ -1,2 +1,2 @@ -/*! decimal.js v2.1.0 https://github.com/MikeMcl/decimal.js/LICENCE */ -(function(n){"use strict";function p(n,t,i,r){return(!r&&i>3&&n[t]==4||(r||i<4)&&n[t]==9)&&n[t+1]==9&&n[t+2]==9&&n[t+3]==9&&(r!=null||n[t+4]==9)||r==null&&(n[t]==5||!n[t])&&!n[t+1]&&!n[t+2]&&!n[t+3]&&!n[t+4]}function v(n,t,i){var r=n.constructor;return t==null||((o=t<0||t>8)||t!==0&&(r.errors?parseInt:parseFloat)(t)!=t)&&!f(r,"rounding mode",t,i,0)?r.rounding:t|0}function y(n,t,i,r){var u=n.constructor;return!(o=t<(r||0)||t>=d+1)&&(t===0||(u.errors?parseInt:parseFloat)(t)==t)||f(u,"argument",t,i,0)}function e(n,t,r,u,f,e){var b=n.constructor,k=n.e-t.e,v=n.s==t.s?1:-1,h=n.c,s=t.c;if(!h||!h[0]||!s||!s[0])return new b(!n.s||!t.s||(h?s&&h[0]==s[0]:!s)?NaN:h&&h[0]==0||!s?v*0:v/0);for(var p,w,l,d,y,it=s.slice(),g=y=s.length,rt=h.length,o=h.slice(0,y),c=o.length,nt=new b(v),tt=nt.c=[],a=v=0;s[a]==(h[a]||0);a++);if(s[a]>(h[a]||0)&&(k--,v=1),nt.e=k,r==null?(r=b.precision,u=b.rounding):f&&(r+=k+1),e=e||10,r>=0){for(v+=r;c++c?1:-1;else for(l=-1,p=0;++lo[l]?1:-1;break}if(p<0){for(d=c==y?s:it;c;){if(o[--c]1&&tt.shift();a<=r&&(r=null)}return i(nt,r,u,o[0]!=null,e)}function g(n,t){var h,l,b,c,r,o,s,a=0,k=0,v=0,f=n.constructor,y=f.ONE,d=f.rounding,w=f.precision;if(!n.c||!n.c[0]||n.e>17)return new f(n.c?n.c[0]?n.s<0?0:1/0:y:n.s?n.s<0?0:n:NaN);for(t==null?(u=!1,r=w):r=t,s=new f(.03125);n.e>-2;)n=n.times(s),v+=5;for(l=Math.log(Math.pow(2,v))/Math.LN10*2+5|0,r+=l,h=c=o=new f(y),f.precision=r;;){if(c=i(c.times(n),r,1),h=h.times(++k),s=o.plus(e(c,h,r,1)),s.c.slice(0,r).join("")===o.c.slice(0,r).join("")){for(b=v;b--;)o=i(o.times(o),r,1);if(t==null)if(a<3&&p(o.c,r-l,d,a))f.precision=r+=10,h=c=s=new f(y),k=0,a++;else return i(o,f.precision=w,d,u=!0);else return f.precision=w,o}o=s}}function w(n,t,r,u){var o=n.constructor,e=(n=new o(n)).e,f=n.c;if(!f)return n.toString();for(f.length>++t&&i(n,t,r),e=u?t:t+n.e-e;f.length1?f[0]+"."+f.slice(1).join(""):f[0])+(e<0?"e":"e+")+e:n.toString()}function f(n,t,i,u,f){if(n.errors){var e=new Error((u||["new Decimal","cmp","div","eq","gt","gte","lt","lte","minus","mod","plus","times","toFraction","pow","random","log","sqrt","toNearest","divToInt"][r?r<0?-r:r:1/r<0?1:0])+"() "+(["number type has more than 15 significant digits","LN10 out of digits"][t]||t+([o?" out of range":" not an integer"," not a boolean or binary digit"][f]||""))+": "+i);e.name="Decimal Error";o=r=0;throw e;}}function it(n,t,i){var r=new n(n.ONE);for(u=!1;;){if(i&1&&(r=r.times(t)),i>>=1,!i)break;t=t.times(t)}return u=!0,r}function c(n,t){var b,v,y,ut,o,a,k,nt,tt,it=1,d=10,r=n,l=r.c,s=r.constructor,g=s.ONE,rt=s.rounding,w=s.precision;if(r.s<0||!l||!l[0]||!r.e&&l[0]==1&&l.length==1)return new s(l&&!l[0]?-1/0:r.s!=1?NaN:l?0:r);if(t==null?(u=!1,o=w):o=t,s.precision=o+=d,Math.abs(v=r.e)<15e14){while(l[0]<7&&l[0]!=1||l[0]==1&&l[1]>3)r=r.times(n),l=r.c,it++;v=r.e;l[0]>1?(it==1?r=new s("0."+l.join("")):r.e=-1,v++):r=new s("1."+l.slice(1).join(""))}else return r=new s(r),r.e=0,o+2>h.length&&f(s,1,o+2,"ln"),r=c(r,o-d).plus(new s(h.slice(0,o+2)).times(v+"")),s.precision=w,t==null?i(r,w,rt,u=!0):r;for(nt=r,a=y=r=e(r.minus(g),r.plus(g),o,1),tt=i(r.times(r),o,1),b=3;;){if(y=i(y.times(tt),o,1),k=a.plus(e(y,new s(b),o,1)),k.c.slice(0,o).join("")===a.c.slice(0,o).join(""))if(a=a.times(2),v!==0&&(o+2>h.length&&f(s,1,o+2,"ln"),a=a.plus(new s(h.slice(0,o+2)).times(v+""))),a=e(a,new s(it),o,1),t==null)if(p(a.c,o-d,rt,ut))s.precision=o+=d,k=y=r=e(nt.minus(g),nt.plus(g),o,1),tt=i(r.times(r),o,1),b=ut=1;else return i(a,s.precision=w,rt,u=!0);else return s.precision=w,a;a=k;b+=2}}function i(n,t,i,r,f){var o,h,s,e,c=n.constructor;if(t!=o){if(!(e=n.c))return n;if(s=n.s<0,h=(f=f||10)/2,o=e[t],r=r||t<0||e[t+1]!=null,r=i<4?(o!=null||r)&&(i==0||i==2&&!s||i==3&&s):o>h||o==h&&(i==4||r||i==6&&e[t-1]&1||i==7&&!s||i==8&&s),t<1||!e[0])return e.length=0,r?(t=t-n.e-1,e[0]=1,n.e=-t||0):e[0]=n.e=0,n;if(e.length>t&&(e.length=t),t--,r){for(o=t;e[o]==null;e[o--]=0);for(--f;++e[t]>f;)e[t]=0,t--||(++n.e,e.unshift(1))}for(t=e.length;!e[--t];e.pop());}return u&&(n.e>c.maxE?n.c=n.e=null:n.eo^u?1:-1;for(i=-1,h=(e=f.length)<(o=s.length)?e:o;++is[i]^u?1:-1;return e==o?0:e>o^u?1:-1};t.decimalPlaces=t.dp=function(){var n=this;return n.c?Math.max(n.c.length-n.e-1,0):null};t.dividedBy=t.div=function(n,t){return r=2,e(this,new this.constructor(n,t))};t.dividedToIntegerBy=t.divToInt=function(n,t){var f=this,u=f.constructor;return r=18,i(e(f,new u(n,t),0,1,1),u.precision,u.rounding)};t.equals=t.eq=function(n,t){return r=3,this.cmp(n,t)===0};t.exponential=t.exp=function(){return g(this)};t.floor=function(){return i(new this.constructor(this),this.e+1,3)};t.greaterThan=t.gt=function(n,t){return r=4,this.cmp(n,t)>0};t.greaterThanOrEqualTo=t.gte=function(n,t){return r=5,t=this.cmp(n,t),t==1||t===0};t.isFinite=function(){return!!this.c};t.isInteger=t.isInt=function(){return!!this.c&&this.e>this.c.length-2};t.isNaN=function(){return!this.s};t.isNegative=t.isNeg=function(){return this.s<0};t.isZero=function(){return!!this.c&&this.c[0]==0};t.lessThan=t.lt=function(n,t){return r=6,this.cmp(n,t)<0};t.lessThanOrEqualTo=t.lte=function(n,t){return r=7,t=this.cmp(n,t),t==-1||t===0};t.logarithm=t.log=function(n,t){var b,o,w,d,tt,g,s,a,v,y=this,l=y.constructor,k=l.precision,nt=l.rounding,it=5;if(n==null)n=new l(10),b=!0;else{if(r=15,n=new l(n,t),o=n.c,n.s<0||!o||!o[0]||!n.e&&o[0]==1&&o.length==1)return new l(NaN);b=n.eq(10)}if(o=y.c,y.s<0||!o||!o[0]||!y.e&&o[0]==1&&o.length==1)return new l(o&&!o[0]?-1/0:y.s!=1?NaN:o?0:1/0);if(tt=b&&(o[0]!=1||o.length>1)||(n.c[n.c.length-1]&1)!=(o[o.length-1]&1)||0&&n.eq(2)&&y.toString(2).replace(/[^1]+/g,"")!="1",u=!1,s=k+it,a=s+10,g=c(y,s),b?(a>h.length&&f(l,1,a,"log"),w=new l(h.slice(0,a))):w=c(n,s),v=e(g,w,s,1),p(v.c,d=k,nt))do if(s+=10,g=c(y,s),b?(a=s+10,a>h.length&&f(l,1,a,"log"),w=new l(h.slice(0,a))):w=c(n,s),v=e(g,w,s,1),!tt){for(o=v.c;o[++d]==9;);d==k+it+10&&(v=i(v,k+1,0));break}while(p(v.c,d+=10,nt));return u=!0,i(v,k,nt)};t.minus=function(n,t){var c,o,l,y,h=this,a=h.constructor,s=h.s;if(r=8,n=new a(n,t),t=n.s,!s||!t)return new a(NaN);if(s!=t)return n.s=-t,h.plus(n);var f=h.c,b=h.e,e=n.c,v=n.e,p=a.precision,w=a.rounding;if(!b||!v){if(!f||!e)return f?(n.s=-t,n):new a(e?h:NaN);if(!f[0]||!e[0])return h=e[0]?(n.s=-t,n):new a(f[0]?h:w==3?-0:0),u?i(h,p,w):h}if(f=f.slice(),o=f.length,s=b-v){for((y=s<0)?(s=-s,c=f,o=e.length):(v=b,c=e),p>o&&(o=p),s>(o+=2)&&(s=o,c.length=1),c.reverse(),t=s;t--;c.push(0));c.reverse()}else for((y=o<(l=e.length))&&(l=o),s=t=0;t0)for(;t--;f[l++]=0);for(t=e.length;t>s;){if(f[--t]t&&(t=a),f>++t&&(f=t,h.length=1),h.reverse();f--;h.push(0));h.reverse()}for(e.length-o.length<0&&(h=o,o=e,e=h),f=o.length,t=0;f;e[f]%=10)t=(e[--f]=e[f]+o[f]+t)/10|0;for(t&&(e.unshift(t),++l),f=e.length;e[--f]==0;e.pop());return n.c=e,n.e=l,u?i(n,a,y):n};t.precision=t.sd=function(n){var t=this;return n!=null&&n!==!!n&&n!==1&&n!==0&&f(t.constructor,"argument",n,"precision",1),t.c?n?Math.max(t.e+1,t.c.length):t.c.length:null};t.round=function(){var n=this,t=n.constructor;return i(new t(n),n.e+1,t.rounding)};t.squareRoot=t.sqrt=function(){var l,t,r,a,o,s=this,n=s.c,h=s.s,f=s.e,c=s.constructor,v=new c(.5);if(h!==1||!n||!n[0])return new c(!h||h<0&&(!n||n[0])?NaN:n?s:1/0);for(u=!1,h=Math.sqrt(+s),h==0||h==1/0?(l=n.join(""),(l.length+f)%2==0&&(l+="0"),r=new c(Math.sqrt(l)+""),r.c||(r.c=[1]),r.e=Math.floor((f+1)/2)-(f<0||f%2)):r=new c(h.toString()),t=(f=c.precision)+3;;)if(o=r,r=v.times(o.plus(e(s,o,t+2,1))),o.c.slice(0,t).join("")===r.c.slice(0,t).join(""))if(n=r.c,n[t-3]!=9&&(a||n[t-3]!=4)||n[t-2]!=9||n[t-1]!=9||n[t]!=9){if((!n[t-3]||n[t-3]==5)&&!n[t-2]&&!n[t-1]&&!n[t]&&(n.length>f+1&&(n.length=f+1),!r.times(r).eq(s))){while(n.length-1;h--){for(t=0,f=c+h;f>h;t=t/10|0)t=e[f]+s[h]*o[f-h-1]+t,e[f--]=t%10|0;t&&(e[f]=(e[f]+t)%10)}for(t&&++n.e,e[0]||e.shift(),f=e.length;!e[--f];e.pop());return n.c=e,u?i(n,a.precision,a.rounding):n};t.toDecimalPlaces=t.toDP=function(n,t){var r=this;return r=new r.constructor(r),n==null||!y(r,n,"toDP")?r:i(r,(n|0)+r.e+1,v(r,t,"toDP"))};t.toExponential=function(n,t){var i=this;return w(i,n!=null&&y(i,n,"toExponential")||!i.c?n|0:i.c.length-1,n!=null&&v(i,t,"toExponential"),1)};t.toFixed=function(n,t){var i,r=this,u=r.constructor,f=u.toExpNeg,e=u.toExpPos;return n!=null&&(n=y(r,n,i="toFixed",-d)?r.e+(n|0):null,t=v(r,t,i)),u.toExpNeg=-(u.toExpPos=1/0),n==null?i=r.toString():(i=w(r,n,t),r.s<0&&r.c&&(r.c[0]?i.indexOf("-")<0&&(i="-"+i):i=i.replace("-",""))),u.toExpNeg=f,u.toExpPos=e,i};t.toFormat=function(n,t,i){var r=this.toFixed(t).split(".");return r[0].replace(/\B(?=(\d{3})+$)/g,n==null?",":n+"")+(r[1]?"."+(i?r[1].replace(/\d{5}\B/g,"$&"+i):r[1]):"")};t.toFraction=function(n){var h,i,p,k,s,c,w,a=this,t=a.constructor,l=h=new t(t.ONE),v=c=new t(0),b=a.c,y=new t(t.ONE),d=t.precision;if(!b)return a.toString();for(p=y.e=b.length-a.e-1,(n==null||(!(r=12,s=new t(n)).s||(o=s.cmp(l)<0||!s.c)||t.errors&&s.e0)&&(n=p>0?y:l),u=!1,s=new t(b.join("")),t.precision=b.length;;){if(w=e(s,y,0,1,1),i=h.plus(w.times(v)),i.cmp(n)==1)break;h=v;v=i;l=c.plus(w.times(i=l));c=i;y=s.minus(w.times(i=y));s=i}return i=e(n.minus(h),v,0,1,1),c=c.plus(i.times(l)),h=h.plus(i.times(v)),c.s=l.s=a.s,p*=2,k=e(l,v,p,1,1).minus(a).abs().cmp(e(c,h,p,1,1).minus(a).abs())<1?[l.toString(),v.toString()]:[c.toString(),h.toString()],u=!0,t.precision=d,k};t.toNearest=function(n,t){var f=this,o=f.constructor;return f=new o(f),n==null?(n=new o(o.ONE),t=o.rounding):(r=17,n=new o(n),t=v(f,t,"toNearest")),n.c?f.c&&(u=!1,t<4&&(t=[4,5,7,8][t]),n.c[0]==1&&n.c.length==1?(f.e-=n.e,i(f,f.e+1,t),f.c[0]&&(f.e+=n.e)):n.c[0]?f=e(f,n,0,t,1).times(n):f.c=[f.e=0],u=!0,i(f)):f.s&&(n.s&&(n.s=f.s),f=n),f};t.toNumber=function(){var n=this;return+n||(n.s?0*n.s:NaN)};t.toPower=t.pow=function(n,t){var b,h,y,e,f=this,o=f.constructor,a=f.s,v=+(r=13,n=new o(n,t)),l=v<0?-v:v,s=o.precision,w=o.rounding;if(!f.c||!n.c||(y=!f.c[0])||!n.c[0])return new o(Math.pow(y?a*0:+f,v));if(f=new o(f),b=f.c.length,!f.e&&f.c[0]==f.s&&b==1)return f;if(t=n.c.length-1,n.e||n.c[0]!=n.s||t)if(y=n.e>=t,!y&&a<0)e=new o(NaN);else{if(y&&b*lo.maxE+1||h0?a/0:0);if(u=!1,o.rounding=f.s=1,l=Math.min(12,(h+"").length),e=g(n.times(c(f,s+l)),s),e=i(e,s+5,1),p(e.c,s,w)){for(h=s+10,e=i(g(n.times(c(f,h+l)),h),h+5,1),l=s;e.c[++l]==9;);l==s+15&&(e=i(e,s+1,0))}e.s=a;u=!0;o.rounding=w}e=i(e,s,w)}else e=i(f,s,w);return e};t.toPrecision=function(n,t){return n!=null&&y(this,n,"toPrecision",1)?w(this,--n|0,v(this,t,"toPrecision"),2):this.toString()};t.toSignificantDigits=t.toSD=function(n,t){var r=this,u=r.constructor;return r=new u(r),n==null||!y(r,n,"toSD",1)?i(r,u.precision,u.rounding):i(r,n|0,v(r,t,"toSD"))};t.toString=function(n){var e,t,s,r=this,u=r.constructor,i=r.e;if(i===null)t=r.s?"Infinity":"NaN";else{if(n===e&&(i<=u.toExpNeg||i>=u.toExpPos))return w(r,r.c.length-1,u.rounding,1);if(t=r.c.join(""),i<0){for(;++i;t="0"+t);t="0."+t}else if(s=t.length,i>0)if(++i>s)for(i-=s;i--;t+="0");else i1)t=e+"."+t.slice(1);else if(e=="0")return e;if(n!=null)if((o=!(n>=2&&n<65))||n!=(n|0)&&u.errors)f(u,"base",n,"toString",0);else if(t=b(u,t,n|0,10,r.s),t=="0")return t}return r.s<0?"-"+t:t};t.truncated=t.trunc=function(){return i(new this.constructor(this),this.e+1,1)};t.valueOf=t.toJSON=function(){return this.toString()};b=function(){function n(n,t,i){for(var u,r=[0],f,e=0,o=n.length;ei-1&&(r[u+1]==null&&(r[u+1]=0),r[u+1]+=r[u]/i|0,r[u]%=i)}return r.reverse()}return function(t,i,r,u,f){var o,s,l,h=i.indexOf("."),c=new t(u);for(u<37&&(i=i.toLowerCase()),h<0?(o=new t(c),l=[1]):(o=it(t,c,i.length-h-1),l=n(o.toFixed(),10,r),i=i.replace(".","")),c.c=l,c.e=l.length,s=n(i,u,r),o.c=s,o.e=s.length,o.s=f,o=e(o,c,t.precision,t.rounding,0,r),s=o.c,h=s.length;h--;)s[h]=k.charAt(s[h]);return o.s=1,o.toFixed()}}();l=function(){function c(n){var i,e,t,u=this,h="config",c=u.errors?parseInt:parseFloat;return n==e||typeof n!="object"&&!f(u,"object expected",n,h)?u:((t=n[i="precision"])!=e&&((o=t<1||t>d)||c(t)!=t?f(u,i,t,h,0):u[i]=t|0),(t=n[i="rounding"])!=e&&((o=t<0||t>8)||c(t)!=t?f(u,i,t,h,0):u[i]=t|0),(t=n[i="toExpNeg"])!=e&&((o=t<-a||t>0)||c(t)!=t?f(u,i,t,h,0):u[i]=Math.floor(t)),(t=n[i="toExpPos"])!=e&&((o=t<0||t>a)||c(t)!=t?f(u,i,t,h,0):u[i]=Math.floor(t)),(t=n[i="minE"])!=e&&((o=t<-a||t>0)||c(t)!=t?f(u,i,t,h,0):u[i]=Math.floor(t)),(t=n[i="maxE"])!=e&&((o=t<0||t>a)||c(t)!=t?f(u,i,t,h,0):u[i]=Math.floor(t)),(t=n[i="errors"])!=e&&(t===!!t||t===1||t===0?(o=r=0,u[i]=!!t):f(u,i,t,h,1)),(t=n[i="crypto"])!=e&&(t===!!t||t===1||t===0?u[i]=!!(t&&s&&typeof s=="object"):f(u,i,t,h,1)),(t=n[i="modulo"])!=e&&((o=t<0||t>9)||c(t)!=t?f(u,i,t,h,0):u[i]=t|0),u)}function l(n){return new this(n).exp()}function v(n){return new this(n).ln()}function p(n,t){return new this(n).log(t)}function e(n,t,i){var r,u,f=0;for(tt.call(t[0])=="[object Array]"&&(t=t[0]),r=new n(t[0]);++f=2&&c<65))?(f(e,"base",c,0,0),p=n.test(h)):(w="["+k.slice(0,c=c|0)+"]+",h=h.replace(/\.$/,"").replace(/^\./,"0."),(p=new RegExp("^"+w+"(?:\\."+w+")?$",c<37?"i":"").test(h))?(v&&(h.replace(/^0\.0*|\./,"").length>15&&f(e,0,y),v=!v),h=b(e,h,10,c,s.s)):h!="Infinity"&&h!="NaN"&&(f(e,"not a base "+c+" number",y),h="NaN")):p=n.test(h),!p)return s.c=s.e=null,h!="Infinity"&&(h!="NaN"&&f(e,"not a number",y),s.s=null),r=0,s}for((a=h.indexOf("."))>-1&&(h=h.replace(".","")),(l=h.search(/e/i))>0?(a<0&&(a=l),a+=+h.slice(l+1),h=h.substring(0,l)):a<0&&(a=h.length),l=0;h.charAt(l)=="0";l++);if(l==(c=h.length))s.c=[s.e=0];else{for(v&&c>15&&h.slice(l).length>15&&f(e,0,y);h.charAt(--c)=="0";);for(s.e=a-l-1,s.c=[],a=0;l<=c;s.c[a++]=+h.charAt(l++));u&&(s.e>e.maxE?s.c=s.e=null:s.e(256/i|0)*i-1?t(i):r%i+""):(r=s.getRandomValues(new n.Uint32Array(1))[0],r>=4e9?t(i):(r+1e9+"").slice(1))}function i(n){var r,t,u=s.randomBytes;return n?(t=u(1)[0],t>(256/n|0)*n-1?i(n):t%n+""):(r=u(8),r[0]=67,r[1]=r[1]&15|48,t=r.readDoubleBE(0),t>9003599627370495?i(n):(t-0xc72815b398000+"").slice(2))}return function(n,e){var w,a,o,b,k,d,p,h,c=this,l=new c(0),v=u;if(d=n==a||!(r=14,n=new c(n)).c&&!f(c,"limit must be finite",n,"random"))n=new c(c.ONE);else if(!n.c[0])return l;c.crypto&&(s.getRandomValues?v=t:s.randomBytes&&(v=i));a=n.e;k=(w=n.c).length;do{o=0;h=v(w[0]+1)+v();do b=w[o],p=h.charAt(o++);while(b==p)}while(p>b||o>k||p=="");for(o=0;h.charAt(o)=="0";o++,a--);for(d?e=c.precision:e!=null&&y(n,e,"random",1)?e|=0:e=a+1,e+=o;h.length0)for(l.c=[];o=10;e/=10,o++);return e=t-o,e<0?(e+=i,s=0):(s=Math.ceil((e+1)/i),e%=i),o=h(10,i-e),f=n[s]%o|0,u==null?e<3?(e==0?f=f/100|0:e==1&&(f=f/10|0),c=r<4&&f==99999||r>3&&f==49999||f==5e4||f==0):c=(r<4&&f+1==o||r>3&&f+1==o/2)&&(n[s+1]/o/100|0)==h(10,e-2)-1||(f==o/2||f==0)&&(n[s+1]/o/100|0)==0:e<4?(e==0?f=f/1e3|0:e==1?f=f/100|0:e==2&&(f=f/10|0),c=(u||r<4)&&f==9999||!u&&r>3&&f==4999):c=((u||r<4)&&f+1==o||!u&&r>3&&f+1==o/2)&&(n[s+1]/o/1e3|0)==h(10,e-3)-1,c}function k(n,t,i){var r=n.constructor;return t==null||((c=t<0||t>8)||t!==0&&(r.errors?parseInt:parseFloat)(t)!=t)&&!e(r,"rounding mode",t,i,0)?r.rounding:t|0}function d(n,t,i,r){var u=n.constructor;return!(c=t<(r||0)||t>=et+1)&&(t===0||(u.errors?parseInt:parseFloat)(t)==t)||e(u,"argument",t,i,0)}function rt(n,t){var c,v,k,a,i,e,o,y=0,d=0,p=0,u=n.constructor,w=u.ONE,nt=u.rounding,b=u.precision;if(!n.c||!n.c[0]||n.e>17)return new u(n.c?n.c[0]?n.s<0?0:1/0:w:n.s?n.s<0?0:n:NaN);for(t==null?(f=!1,i=b):i=t,o=new u(.03125);n.e>-2;)n=n.times(o),p+=5;for(v=Math.log(h(2,p))/Math.LN10*2+5|0,i+=v,c=a=e=new u(w),u.precision=i;;){if(a=r(a.times(n),i,1),c=c.times(++d),o=e.plus(s(a,c,i,1)),l(o.c).slice(0,i)===l(e.c).slice(0,i)){for(k=p;k--;)e=r(e.times(e),i,1);if(t==null)if(y<3&&g(e.c,i-v,nt,y))u.precision=i+=10,c=a=o=new u(w),d=0,y++;else return r(e,u.precision=b,nt,f=!0);else return u.precision=b,e}e=o}}function nt(n,t,i,u){var f,o,s=n.constructor,e=(n=new s(n)).e;if(t==null?i=0:(r(n,++t,i),i=u?t:t+n.e-e),e=n.e,f=l(n.c),u==1||u==2&&(t<=e||e<=s.toExpNeg)){for(;f.length1&&(f=f.charAt(0)+"."+f.slice(1));f+=(e<0?"e":"e+")+e}else{if(u=f.length,e<0){for(o=i-u;++e;f="0"+f);f="0."+f}else if(++e>u){for(o=i-e,e-=u;e--;f+="0");o>0&&(f+=".")}else o=i-u,e0&&(f+=".");if(o>0)for(;o--;f+="0");}return n.s<0&&n.c[0]?"-"+f:f}function ot(n){var t=n.length-1,r=t*i+1;if(t=n[t]){for(;t%10==0;t/=10,r--);for(t=n[0];t>=10;t/=10,r++);}return r}function e(n,t,i,r,f){if(n.errors){var e=new Error((r||["new Decimal","cmp","div","eq","gt","gte","lt","lte","minus","mod","plus","times","toFraction","pow","random","log","sqrt","toNearest","divToInt"][u?u<0?-u:u:1/u<0?1:0])+"() "+(["number type has more than 15 significant digits","LN10 out of digits"][t]||t+([c?" out of range":" not an integer"," not a boolean or binary digit"][f]||""))+": "+i);e.name="Decimal Error";c=u=0;throw e;}}function st(n,t,i){var r=new n(n.ONE);for(f=!1;;){if(i&1&&(r=r.times(t)),i>>=1,!i)break;t=t.times(t)}return f=!0,r}function p(n,t){var c,a,d,w,b,et,u,h,nt,rt,ut,ot=1,tt=10,i=n,v=i.c,o=i.constructor,it=o.ONE,ft=o.rounding,k=o.precision;if(i.s<0||!v||!v[0]||!i.e&&v[0]==1&&v.length==1)return new o(v&&!v[0]?-1/0:i.s!=1?NaN:v?0:i);if(t==null?(f=!1,u=k):u=t,o.precision=u+=tt,c=l(v),a=c.charAt(0),Math.abs(w=i.e)<15e14){while(a<7&&a!=1||a==1&&c.charAt(1)>3)i=i.times(n),c=l(i.c),a=c.charAt(0),ot++;w=i.e;a>1?(i=new o("0."+c),w++):i=new o(a+"."+c.slice(1))}else return i=new o(a+"."+c.slice(1)),u+2>y.length&&e(o,1,u+2,"ln"),i=p(i,u-tt).plus(new o(y.slice(0,u+2)).times(w+"")),o.precision=k,t==null?r(i,k,ft,f=!0):i;for(rt=i,h=b=i=s(i.minus(it),i.plus(it),u,1),ut=r(i.times(i),u,1),d=3;;){if(b=r(b.times(ut),u,1),nt=h.plus(s(b,new o(d),u,1)),l(nt.c).slice(0,u)===l(h.c).slice(0,u))if(h=h.times(2),w!==0&&(u+2>y.length&&e(o,1,u+2,"ln"),h=h.plus(new o(y.slice(0,u+2)).times(w+""))),h=s(h,new o(ot),u,1),t==null)if(g(h.c,u-tt,ft,et))o.precision=u+=tt,nt=b=i=s(rt.minus(it),rt.plus(it),u,1),ut=r(i.times(i),u,1),d=et=1;else return r(h,o.precision=k,ft,f=!0);else return o.precision=k,h;h=nt;d+=2}}function r(n,t,r,u){var y,c,s,l,p,w,e,a,b=n.constructor;n:if(t!=c){if(!(e=n.c))return n;for(y=1,l=e[0];l>=10;l/=10,y++);if(c=t-y,c<0)c+=i,s=t,p=e[a=0],w=p/h(10,y-s-1)%10|0;else if(a=Math.ceil((c+1)/i),a>=e.length)if(u){for(;e.length<=a;e.push(0));p=w=0;y=1;c%=i;s=c-i+1}else break n;else{for(p=l=e[a],y=1;l>=10;l/=10,y++);c%=i;s=c-i+y;w=s<0?0:o(p/h(10,y-s-1)%10)}if(u=u||t<0||e[a+1]!=null||(s<0?p:p%h(10,y-s-1)),u=r<4?(w||u)&&(r==0||r==(n.s<0?3:2)):w>5||w==5&&(r==4||u||r==6&&(c>0?s>0?p/h(10,y-s):0:e[a-1])%10&1||r==(n.s<0?8:7)),t<1||!e[0])return e.length=0,u?(t-=n.e+1,e[0]=h(10,t%i),n.e=-t||0):e[0]=n.e=0,n;if(c==0?(e.length=a,l=1,a--):(e.length=a+1,l=h(10,i-c),e[a]=s>0?(p/h(10,y-s)%h(10,s)|0)*l:0),u)for(;;)if(a==0){for(c=1,s=e[0];s>=10;s/=10,c++);for(s=e[0]+=l,l=1;s>=10;s/=10,l++);c!=l&&(n.e++,e[0]==v&&(e[0]=1));break}else{if(e[a]+=l,e[a]!=v)break;e[a--]=0;l=1}for(c=e.length;e[--c]===0;e.pop());}return f&&(n.e>b.maxE?n.c=n.e=null:n.eo^r?1:-1;for(i=-1,h=(e=f.length)<(o=s.length)?e:o;++is[i]^r?1:-1;return e==o?0:e>o^r?1:-1};t.decimalPlaces=t.dp=function(){var r,n,t=null;if(r=this.c){if(t=((n=r.length-1)-o(this.e/i))*i,n=r[n])for(;n%10==0;n/=10,t--);t<0&&(t=0)}return t};t.dividedBy=t.div=function(n,t){return u=2,s(this,new this.constructor(n,t))};t.dividedToIntegerBy=t.divToInt=function(n,t){var f=this,i=f.constructor;return u=18,r(s(f,new i(n,t),0,1,1),i.precision,i.rounding)};t.equals=t.eq=function(n,t){return u=3,this.cmp(n,t)===0};t.exponential=t.exp=function(){return rt(this)};t.floor=function(){return r(new this.constructor(this),this.e+1,3)};t.greaterThan=t.gt=function(n,t){return u=4,this.cmp(n,t)>0};t.greaterThanOrEqualTo=t.gte=function(n,t){return u=5,t=this.cmp(n,t),t==1||t===0};t.isFinite=function(){return!!this.c};t.isInteger=t.isInt=function(){return!!this.c&&o(this.e/i)>this.c.length-2};t.isNaN=function(){return!this.s};t.isNegative=t.isNeg=function(){return this.s<0};t.isZero=function(){return!!this.c&&this.c[0]==0};t.lessThan=t.lt=function(n,t){return u=6,this.cmp(n,t)<0};t.lessThanOrEqualTo=t.lte=function(n,t){return u=7,t=this.cmp(n,t),t==-1||t===0};t.logarithm=t.log=function(n,t){var k,i,b,o,it,d,h,a,v,w=this,c=w.constructor,nt=c.precision,tt=c.rounding;if(n==null)n=new c(10),k=!0;else{if(u=15,n=new c(n,t),i=n.c,n.s<0||!i||!i[0]||!n.e&&i[0]==1&&i.length==1)return new c(NaN);k=n.eq(10)}if(i=w.c,w.s<0||!i||!i[0]||!w.e&&i[0]==1&&i.length==1)return new c(i&&!i[0]?-1/0:w.s!=1?NaN:i?0:1/0);if(it=k&&(o=i[0],i.length>1||o!=1&&o!=10&&o!=100&&o!=1e3&&o!=1e4&&o!=1e5&&o!=1e6),f=!1,h=nt+5,a=h+10,d=p(w,h),k?(a>y.length&&e(c,1,a,"log"),b=new c(y.slice(0,a))):b=p(n,h),v=s(d,b,h,1),g(v.c,o=nt,tt))do if(h+=10,d=p(w,h),k?(a=h+10,a>y.length&&e(c,1,a,"log"),b=new c(y.slice(0,a))):b=p(n,h),v=s(d,b,h,1),!it){+l(v.c).slice(o+1,o+15)+1==1e14&&(v=r(v,nt+1,0));break}while(g(v.c,o+=10,tt));return f=!0,r(v,nt,tt)};t.minus=function(n,t){var a,c,p,k,l=this,w=l.constructor,h=l.s;if(u=8,n=new w(n,t),t=n.s,!h||!t)return new w(NaN);if(h!=t)return n.s=-t,l.plus(n);var e=l.c,s=n.c,b=o(n.e/i),y=o(l.e/i),g=w.precision,d=w.rounding;if(!y||!b){if(!e||!s)return e?(n.s=-t,n):new w(s?l:NaN);if(!e[0]||!s[0])return l=s[0]?(n.s=-t,n):new w(e[0]?l:d==3?-0:0),f?r(l,g,d):l}if(e=e.slice(),c=e.length,h=y-b){for((k=h<0)?(h=-h,a=e,c=s.length):(b=y,a=s),(y=Math.ceil(g/i))>c&&(c=y),h>(c+=2)&&(h=c,a.length=1),a.reverse(),t=h;t--;a.push(0));a.reverse()}else for((k=c<(p=s.length))&&(p=c),h=t=0;t0)for(;t--;e[p++]=0);for(y=v-1,t=s.length;t>h;){if(e[--t]=10;t/=10,h++);return n.e=h+b*i-1,f?r(n,g,d):n};t.modulo=t.mod=function(n,t){var h,e,i=this,o=i.constructor,c=o.modulo;return(u=9,n=new o(n,t),t=n.s,h=!i.c||!t||n.c&&!n.c[0],h||!n.c||i.c&&!i.c[0])?h?new o(NaN):r(new o(i),o.precision,o.rounding):(f=!1,c==9?(n.s=1,e=s(i,n,0,3,1),n.s=t,e.s*=t):e=s(i,n,0,c,1),e=e.times(n),f=!0,i.minus(e))};t.naturalLogarithm=t.ln=function(){return p(this)};t.negated=t.neg=function(){var n=new this.constructor(this);return n.s=-n.s||null,r(n)};t.plus=function(n,t){var l,c=this,y=c.constructor,e=c.s;if(u=10,n=new y(n,t),t=n.s,!e||!t)return new y(NaN);if(e!=t)return n.s=-t,c.minus(n);var s=c.c,h=n.c,p=o(n.e/i),a=o(c.e/i),w=y.precision,b=y.rounding;if(!a||!p){if(!s||!h)return new y(e/0);if(!s[0]||!h[0])return c=h[0]?n:new y(s[0]?c:e*0),f?r(c,w,b):c}if(s=s.slice(),e=a-p){for(e<0?(e=-e,l=s,t=h.length):(p=a,l=h,t=s.length),(a=Math.ceil(w/i))>t&&(t=a),e>++t&&(e=t,l.length=1),l.reverse();e--;l.push(0));l.reverse()}for(s.length-h.length<0&&(l=h,h=s,s=l),e=h.length,t=0,a=v;e;s[e]%=a)t=(s[--e]=s[e]+h[e]+t)/a|0;for(t&&(s.unshift(t),++p),e=s.length;s[--e]==0;s.pop());for(n.c=s,e=1,t=s[0];t>=10;t/=10,e++);return n.e=e+p*i-1,f?r(n,w,b):n};t.precision=t.sd=function(n){var t=null,i=this;return n!=t&&n!==!!n&&n!==1&&n!==0&&e(i.constructor,"argument",n,"precision",1),i.c&&(t=ot(i.c),n&&i.e+1>t&&(t=i.e+1)),t};t.round=function(){var n=this,t=n.constructor;return r(new t(n),n.e+1,t.rounding)};t.squareRoot=t.sqrt=function(){var p,n,c,i,y,h,e=this,a=e.c,u=e.s,t=e.e,v=e.constructor,w=new v(.5);if(u!==1||!a||!a[0])return new v(!u||u<0&&(!a||a[0])?NaN:a?e:1/0);for(f=!1,u=Math.sqrt(+e),u==0||u==1/0?(n=l(a),(n.length+t)%2==0&&(n+="0"),u=Math.sqrt(n),t=o((t+1)/2)-(t<0||t%2),u==1/0?n="1e"+t:(n=u.toExponential(),n=n.slice(0,n.indexOf("e")+1)+t),i=new v(n)):i=new v(u.toString()),c=(t=v.precision)+3;;)if(h=i,i=w.times(h.plus(s(e,h,c+2,1))),l(h.c).slice(0,c)===(n=l(i.c)).slice(0,c))if(n=n.slice(c-3,c+1),n!="9999"&&(y||n!="4999")){+n&&(+n.slice(1)||n.charAt(0)!="5")||(r(i,t+1,1),p=!i.times(i).eq(e));break}else{if(!y&&(r(h,t+1,0),h.times(h).eq(e))){i=h;break}c+=4;y=1}return f=!0,r(i,t,v.rounding,p)};t.times=function(n,t){var e,w,y=this,p=y.constructor,c=y.c,l=(u=11,n=new p(n,t),n.c),a=o(y.e/i),s=o(n.e/i),h=y.s;if(t=n.s,n.s=h==t?1:-1,!a&&(!c||!c[0])||!s&&(!l||!l[0]))return new p(!h||!t||c&&!c[0]&&!l||l&&!l[0]&&!c?NaN:!c||!l?n.s/0:n.s*0);for(w=a+s,h=c.length,t=l.length,h-1;a--){for(t=0,s=h+a;s>a;t=t/v|0)t=e[s]+l[a]*c[s-a-1]+t,e[s--]=t%v|0;t&&(e[s]=(e[s]+t)%v)}for(t&&++w,e[0]||e.shift(),s=e.length;!e[--s];e.pop());for(n.c=e,h=1,t=e[0];t>=10;t/=10,h++);return n.e=h+w*i-1,f?r(n,p.precision,p.rounding):n};t.toDecimalPlaces=t.toDP=function(n,t){var i=this;return i=new i.constructor(i),n==null||!d(i,n,"toDP")?i:r(i,(n|0)+i.e+1,k(i,t,"toDP"))};t.toExponential=function(n,t){var i=this;return i.c?nt(i,n!=null&&d(i,n,"toExponential")?n|0:null,n!=null&&k(i,t,"toExponential"),1):i.toString()};t.toFixed=function(n,t){var i,r=this,u=r.constructor,f=u.toExpNeg,e=u.toExpPos;return n!=null&&(n=d(r,n,i="toFixed")?r.e+(n|0):null,t=k(r,t,i)),u.toExpNeg=-(u.toExpPos=1/0),n!=null&&r.c?(i=nt(r,n,t),r.s<0&&r.c&&(r.c[0]?i.indexOf("-")<0&&(i="-"+i):i=i.replace("-",""))):i=r.toString(),u.toExpNeg=f,u.toExpPos=e,i};t.toFormat=function(n,t,i){var r=this.toFixed(t).split(".");return r[0].replace(/\B(?=(\d{3})+$)/g,n==null?",":n+"")+(r[1]?"."+(i?r[1].replace(/\d{5}\B/g,"$&"+i):r[1]):"")};t.toFraction=function(n){var v,r,d,it,a,y,g,nt,b=this,t=b.constructor,p=v=new t(t.ONE),w=y=new t(0),tt=b.c,k=new t(w);if(!tt)return b.toString();for(d=k.e=ot(tt)-b.e-1,k.c[0]=h(10,(g=d%i)<0?i+g:g),(n==null||(!(u=12,a=new t(n)).s||(c=a.cmp(p)<0||!a.c)||t.errors&&o(a.e/i)0)&&(n=d>0?k:p),f=!1,a=new t(l(tt)),g=t.precision,t.precision=d=tt.length*i*2;;){if(nt=s(a,k,0,1,1),r=v.plus(nt.times(w)),r.cmp(n)==1)break;v=w;w=r;p=y.plus(nt.times(r=p));y=r;k=a.minus(nt.times(r=k));a=r}return r=s(n.minus(v),w,0,1,1),y=y.plus(r.times(p)),v=v.plus(r.times(w)),y.s=p.s=b.s,it=s(p,w,d,1).minus(b).abs().cmp(s(y,v,d,1).minus(b).abs())<1?[p+"",w+""]:[y+"",v+""],f=!0,t.precision=g,it};t.toNearest=function(n,t){var i=this,e=i.constructor;return i=new e(i),n==null?(n=new e(e.ONE),t=e.rounding):(u=17,n=new e(n),t=k(i,t,"toNearest")),n.c?i.c&&(n.c[0]?(f=!1,i=s(i,n,0,t<4?[4,5,7,8][t]:t,1).times(n),f=!0,r(i)):i.c=[i.e=0]):i.s&&(n.s&&(n.s=i.s),i=n),i};t.toNumber=function(){var n=this;return+n||(n.s?0*n.s:NaN)};t.toPower=t.pow=function(n,t){var nt,a,b,s,e=this,c=e.constructor,y=e.s,w=+(u=13,n=new c(n,t)),k=w<0?-w:w,v=c.precision,d=c.rounding;if(!e.c||!n.c||(b=!e.c[0])||!n.c[0])return new c(h(b?y*0:+e,w));if(e=new c(e),nt=e.c.length,!e.e&&e.c[0]==e.s&&nt==1)return e;if(t=n.c.length-1,n.e||n.c[0]!=n.s||t)if(a=o(n.e/i),b=a>=t,!b&&y<0)s=new c(NaN);else{if(b&&nt*i*kc.maxE+1||a0?y/0:0);f=!1;c.rounding=e.s=1;k=Math.min(12,(a+"").length);s=rt(n.times(p(e,v+k)),v);s=r(s,v+5,1);g(s.c,v,d)&&(a=v+10,s=r(rt(n.times(p(e,a+k)),a),a+5,1),+l(s.c).slice(v+1,v+15)+1==1e14&&(s=r(s,v+1,0)));s.s=y;f=!0;c.rounding=d}s=r(s,v,d)}else s=r(e,v,d);return s};t.toPrecision=function(n,t){var i=this;return n!=null&&d(i,n,"toPrecision",1)&&i.c?nt(i,--n|0,k(i,t,"toPrecision"),2):i.toString()};t.toSignificantDigits=t.toSD=function(n,t){var i=this,u=i.constructor;return i=new u(i),n==null||!d(i,n,"toSD",1)?r(i,u.precision,u.rounding):r(i,n|0,k(i,t,"toSD"))};t.toString=function(n){var f,t,o,r=this,u=r.constructor,i=r.e;if(i===null)t=r.s?"Infinity":"NaN";else{if(n===f&&(i<=u.toExpNeg||i>=u.toExpPos))return nt(r,null,u.rounding,1);if(t=l(r.c),i<0){for(;++i;t="0"+t);t="0."+t}else if(o=t.length,i>0)if(++i>o)for(i-=o;i--;t+="0");else i1)t=f+"."+t.slice(1);else if(f=="0")return f;if(n!=null)if((c=!(n>=2&&n<65))||n!=(n|0)&&u.errors)e(u,"base",n,"toString",0);else if(t=tt(u,t,n|0,10,r.s),t=="0")return t}return r.s<0?"-"+t:t};t.truncated=t.trunc=function(){return r(new this.constructor(this),this.e+1,1)};t.valueOf=t.toJSON=function(){return this.toString()};tt=function(){function n(n,t,i){for(var u,r=[0],f,e=0,o=n.length;ei-1&&(r[u+1]==null&&(r[u+1]=0),r[u+1]+=r[u]/i|0,r[u]%=i)}return r.reverse()}return function(t,i,r,u,f){var h,a,p,c,e,y,o=i.indexOf("."),l=t.precision,v=t.rounding;for(u<37&&(i=i.toLowerCase()),o>=0&&(i=i.replace(".",""),y=new t(u),c=st(t,y,i.length-o),y.c=n(c.toFixed(),10,r),y.e=y.c.length),e=n(i,u,r),h=a=e.length;e[--a]==0;e.pop());if(!e[0])return"0";if(o<0?h--:(c.c=e,c.e=h,c.s=f,c=s(c,y,l,v,0,r),e=c.c,p=c.r,h=c.e),o=e[l],a=r/2,p=p||e[l+1]!=null,v<4?(o!=null||p)&&(v==0||v==(c.s<0?3:2)):o>a||o==a&&(v==4||p||v==6&&e[l-1]&1||v==(c.s<0?8:7)))for(e.length=l,--r;++e[--l]>r;)e[l]=0,l||(++h,e.unshift(1));else e.length=l;for(a=e.length;!e[--a];);for(o=0,i="";o<=a;i+=it.charAt(e[o++]));if(h<0){for(;++h;i="0"+i);i="0."+i}else if(o=i.length,++h>o)for(h-=o;h--;i+="0");else hr?1:-1;else for(u=f=0;ut[u]?1:-1;break}return f}function u(n,t,i,r){for(var u=0;i--;)n[i]-=u,u=n[i]1;n.shift());}return function(f,e,s,h,c,l){var nt,et,w,rt,ot,y,tt,ft,it,ut,p,b,ht,vt,ct,st,yt,g,lt,at=f.constructor,d=f.s==e.s?1:-1,k=f.c,a=e.c;if(!k||!k[0]||!a||!a[0])return new at(!f.s||!e.s||(k?a&&k[0]==a[0]:!a)?NaN:k&&k[0]==0||!a?d*0:d/0);for(l?(rt=1,et=f.e-e.e):(l=v,rt=i,et=o(f.e/rt)-o(e.e/rt)),g=a.length,st=k.length,it=new at(d),ut=it.c=[],w=0;a[w]==(k[w]||0);w++);if(a[w]>(k[w]||0)&&et--,s==null?(d=s=at.precision,h=at.rounding):d=c?s+(f.e-e.e)+1:s,d<0)ut.push(1),ot=!0;else{if(d=d/rt+2|0,w=0,g==1){for(y=0,a=a[0],d++;(w1&&(a=n(a,y,l),k=n(k,y,l),g=a.length,st=k.length),ct=g,p=k.slice(0,g),b=p.length;b=l/2&&yt++;do y=0,nt=t(a,p,g,b),nt<0?(ht=p[0],g!=b&&(ht=ht*l+(p[1]||0)),y=ht/yt|0,y>1?(y>=l&&(y=l-1),tt=n(a,y,l),ft=tt.length,b=p.length,nt=t(tt,p,ft,b),nt==1&&(y--,u(tt,g=10;d/=10,w++);it.e=w+et*rt-1;r(it,c?s+it.e+1:s,h,ot)}return it}}();w=function(){function l(n){var i,f,t,r=this,s="config",h=r.errors?parseInt:parseFloat;return n==f||typeof n!="object"&&!e(r,"object expected",n,s)?r:((t=n[i="precision"])!=f&&((c=t<1||t>et)||h(t)!=t?e(r,i,t,s,0):r[i]=t|0),(t=n[i="rounding"])!=f&&((c=t<0||t>8)||h(t)!=t?e(r,i,t,s,0):r[i]=t|0),(t=n[i="toExpNeg"])!=f&&((c=t<-b||t>0)||h(t)!=t?e(r,i,t,s,0):r[i]=o(t)),(t=n[i="toExpPos"])!=f&&((c=t<0||t>b)||h(t)!=t?e(r,i,t,s,0):r[i]=o(t)),(t=n[i="minE"])!=f&&((c=t<-b||t>0)||h(t)!=t?e(r,i,t,s,0):r[i]=o(t)),(t=n[i="maxE"])!=f&&((c=t<0||t>b)||h(t)!=t?e(r,i,t,s,0):r[i]=o(t)),(t=n[i="errors"])!=f&&(t===!!t||t===1||t===0?(c=u=0,r[i]=!!t):e(r,i,t,s,1)),(t=n[i="crypto"])!=f&&(t===!!t||t===1||t===0?r[i]=!!(t&&a&&typeof a=="object"):e(r,i,t,s,1)),(t=n[i="modulo"])!=f&&((c=t<0||t>9)||h(t)!=t?e(r,i,t,s,0):r[i]=t|0),r)}function v(n){return new this(n).exp()}function y(n){return new this(n).ln()}function p(n,t){return new this(n).log(t)}function n(n,t,i){var r,u,f=0;for(ft.call(t[0])=="[object Array]"&&(t=t[0]),r=new n(t[0]);++f=429e7?o[t]=a.getRandomValues(new Uint32Array(1))[0]:f[t++]=u%1e7;else if(a&&a.randomBytes){for(o=a.randomBytes(r*=4);t=214e7?a.randomBytes(4).copy(o,t):(f.push(u%1e7),t+=4);t=r/4}else e(s,"crypto unavailable",a,"random");if(!t)for(;t=10;)u/=10,t++;t=2&&l<65))?(e(o,"base",l,0,0),w=n.test(h)):(b="["+it.slice(0,l=l|0)+"]+",h=h.replace(/\.$/,"").replace(/^\./,"0."),(w=new RegExp("^"+b+"(?:\\."+b+")?$",l<37?"i":"").test(h))?(y&&(h.replace(/^0\.0*|\./,"").length>15&&e(o,0,p),y=!y),h=tt(o,h,10,l,s.s)):h!="Infinity"&&h!="NaN"&&(e(o,"not a base "+l+" number",p),h="NaN")):w=n.test(h),!w)return s.c=s.e=null,h!="Infinity"&&(h!="NaN"&&e(o,"not a number",p),s.s=null),u=0,s}for((v=h.indexOf("."))>-1&&(h=h.replace(".","")),(a=h.search(/e/i))>0?(v<0&&(v=a),v+=+h.slice(a+1),h=h.substring(0,a)):v<0&&(v=h.length),a=0;h.charAt(a)=="0";a++);for(l=h.length;h.charAt(--l)=="0";);if(h=h.slice(a,l+1),h){if(l=h.length,y&&l>15&&e(o,0,p),s.e=v=v-a-1,s.c=[],a=(v+1)%i,v<0&&(a+=i),ao.maxE?s.c=s.e=null:s.e
- random.random([limit [, sd]]) ⇒ Decimal + random.random([dp]) ⇒ Decimal
+

dp: number: integer, 0 to 1e+9 inclusive

- limit: number|string|Decimal
Default value: 1
- sd: number: integer, 1 to 1e+9 inclusive
- See Decimal for further parameter details. + Returns a new Decimal with a pseudo-random value equal to or greater than 0 and + less than 1.

- Returns a new Decimal with a pseudo-random value equal to or greater in magnitude than - 0 and lower in magnitude than limit, and with the same sign as - limit. -

-

- If limit is omitted then it will be 1 and the return value will - have precision significant digits (or less if there are - trailing zeros produced). -

-

- If limit is included and sd is omitted then the return value - will be an integer. If sd is included, the return value will have - sd significant digits (or less if there are trailing zeros produced). -

-

- If limit is a high value be sure to include a precision, otherwise this method - may be slow to return because all integer digits will be generated. + The return value will have dp decimal places (or less if trailing zeros are + produced). If dp is omitted then the number of decimal places will + default to the current precision setting.

Depending on the value of a Decimal constructor's crypto @@ -530,33 +516,11 @@ x.equals(y) // true crypto methods is to be used, the value of a returned Decimal should be cryptographically-secure and statistically indistinguishable from a random value.

-
// A value in the range [0, 1) with precision significant digits
-Decimal.config({ precision: 10 })
-Decimal.random()                        // '0.4117936847'
+    
Decimal.config({ precision: 10 })
+Decimal.random()                    // '0.4117936847'
 
-// A value in the range [0, 1) with 20 significant digits
-Decimal.random(1, 20)                   // '0.48193327636914089007'
+Decimal.random(20)                  // '0.78193327636914089009'
-// An integer in the range [0, 1) -Decimal.random(1) // '0' (always zero) - -// An integer in the range [0, 10) -Decimal.random(10) // '6' - -// An integer in the range (-100, 0] -Decimal.random(-100) // '-82' - -// An integer in the range [0, 9e9999999999) -Decimal.random('9e99999999999') // A browser will hang - -// A value in the range [0, 9e9999999999) with 10 significant digits -Decimal.random('9e99999999999', 25) // '1.508652055e+99999999999' - -// A value in the range (-0.0125, 0] with 16 significant digits -Decimal.random(-0.0125, 16) // '-0.0001963482803540358' - -// A value in the range [0, 0.9) with 1 significant digit -Decimal.random(0.9, 1) // '0.2'
@@ -564,7 +528,7 @@ Decimal.random(0.9, 1) // '0.2'

See squareRoot.

x = Decimal.sqrt('987654321.123456789')
 y = new Decimal('987654321.123456789').sqrt()
-x.equals(y)                    // true
+x.equals(y) // true @@ -723,7 +687,7 @@ new Decimal(100000) // 'Infinity' returns exponential notation.

Decimal.config({ toExpNeg: -7 })
-Decimal.toExpNeg                 // -7
+Decimal.toExpNeg                   // -7
 new Decimal(0.00000123)            // '0.00000123'       e is -6
 new Decimal(0.000000123)           // '1.23e-7'
 
@@ -869,7 +833,12 @@ Decimal.modulo                     // 9

If neither function is supported by the host environment or if crypto is falsey - then the source of randomness will be Math.random. + then the source of randomness will be Math.random. If the crypto + property is set directly (i.e. without using config) to true, then + at the time the random method is called, if + errors is true, an error will be thrown if the + crypto methods are unavailable. +

 Decimal.crypto                     // false
@@ -1746,9 +1715,9 @@ JSON.parse(str, function (key, val) {
     would be serialized, rather then the string returned by valueOf:

JSON.stringify( [x, y, z] )
 /*
-"[{"s":1,"e":459,"c":[1,7,7,7]},
-  {"s":1,"e":2,"c":[2,3,5,4,3,2,5]},
-  {"s":1,"e":-3,"c":[9,8,0,7,4]}]"
+"[{"s":1,"e":459,"c":[17770]},
+  {"s":1,"e":2,"c":[235,4325000]},
+  {"s":1,"e":-3,"c":[98074]}]"
  */
@@ -1823,8 +1792,7 @@ z = new Decimal(-0)

The performance of this method degrades exponentially with increasing digits. For - non-integer exponents in particular, even when only quite a small number of significant - digits is required, the performance of this method may not be adequate. + non-integer exponents in particular, the performance of this method may not be adequate.

 Math.pow(0.7, 2)               // 0.48999999999999994
@@ -2038,7 +2006,7 @@ x.valueOf()                     // '1.777e+457'
c coefficient* number[] - Array of single digits + Array of integers, each 0 - 1e7 e @@ -2058,19 +2026,23 @@ x.valueOf() // '1.777e+457'
The value of any of the three properties may also be null.

- The value of a Decimal is stored in a normalised decimal floating point - format which corresponds to the value's toExponential form, - with the decimal point to be positioned after the most significant - (left-most) digit of the coefficient. + The properties are best considered to be read-only.

- Note that, as with JavaScript numbers, the original exponent and - fractional trailing zeros are not preserved. + From version 3 of this library, the value of a Decimal is stored in a normalised base + 10000 floating point format. While previously it was acceptable to change the + exponent of a Decimal by writing to its exponent property directly, this is no longer + recommended (as the number of digits in the first element of the coefficient array is + dependent on the exponent, so the coefficient would also need to be altered). +

+

+ As with JavaScript numbers, the original exponent and fractional trailing zeros of a number + are not preserved.

 x = new Decimal(0.123)                // '0.123'
 x.toExponential()                     // '1.23e-1'
-x.c                                   // '1,2,3'
+x.c                                   // [ 1230000 ]
 x.e                                   // -1
 x.s                                   // 1
 
@@ -2078,31 +2050,11 @@ y = new Number(-123.4567000e+2)       // '-12345.67'
 y.toExponential()                     // '-1.234567e+4'
 z = new Decimal('-123.4567000e+2')    // '-12345.67'
 z.toExponential()                     // '-1.234567e+4'
-z.c                                   // '1,2,3,4,5,6,7'
+z.c                                   // [ 12345, 6700000 ]
 z.e                                   // 4
 z.s                                   // -1
-

- A Decimal is mutable in the sense that the value of its properties can - be changed.
- For example, to rapidly shift a value by a power of 10: -

-
-x = new Decimal('1234.000')           // '1234'
-x.toExponential()                     // '1.234e+3'
-x.c                                   // '1,2,3,4'
-x.e                                   // 3
-
-x.e = -5
-x                                     // '0.00001234'
-

- If changing the coefficient array directly, which is not recommended, be - careful to avoid leading or trailing zeros (unless zero itself is being - represented). -

- -

Zero, NaN and Infinity

@@ -2276,6 +2228,11 @@ y.s // -1 argument not a boolean or binary digit Ignore + + random + crypto unavailable + Use Math.random + diff --git a/package.json b/package.json index 27e58af..0c7193a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "decimal.js", "description": "An arbitrary-precision Decimal type for JavaScript.", - "version": "2.1.0", + "version": "3.0.0", "keywords": [ "arbitrary", "precision", @@ -31,6 +31,6 @@ "license": "MIT", "scripts": { "test": "node ./test/every-test.js", - "build": "uglifyjs decimal.js -c -m -o decimal.min.js --preamble '/* decimal.js v2.1.0 https://github.com/MikeMcl/decimal.js/LICENCE */'" + "build": "uglifyjs decimal.js -c -m -o decimal.min.js --preamble '/* decimal.js v3.0.0 https://github.com/MikeMcl/decimal.js/LICENCE */'" } } \ No newline at end of file diff --git a/test/browser/single-test.html b/test/browser/single-test.html index f7f4cc9..6513a13 100644 --- a/test/browser/single-test.html +++ b/test/browser/single-test.html @@ -45,7 +45,6 @@ - diff --git a/test/random.js b/test/random.js index 090f95a..6d56530 100644 --- a/test/random.js +++ b/test/random.js @@ -1,6 +1,6 @@ var count = (function random(Decimal) { var start = +new Date(), - error, i, j, limit, log, pr, u, + dp, error, i, j, k, log, m, r, passed = 0, total = 0; @@ -14,20 +14,7 @@ var count = (function random(Decimal) { } if (!Decimal && typeof require === 'function') { - Decimal = require('../decimal'); - } - - function assert(result, r, message) { - total++; - if (result === true) { - passed++; - //log('\n r: ' + r); - } else { - error('\n Test number: ' + total + ' failed'); - error(' r: ' + r); - error(' ' + message); - //process.exit(); - } + Decimal = require('../decimal.js'); } function assertException(func, message) { @@ -49,74 +36,65 @@ var count = (function random(Decimal) { } } - function T(limit, pr){ - var i, r, d; - - if ( !limit ) { - limit = new Decimal(1); - pr = Decimal.precision; - } - - for ( i = 0; i < 17; i++ ) { - r = Decimal.random(limit, pr); - //log(r.toString()); - d = r.c.length; - - if ( pr == null ) { - d = Math.max(d, r.e + 1) - r.e - 1; - assert(d === 0, r, 'dp is not 0: ' + d); - } else { - assert(d <= pr, r, 'sd: ' + d + ' > pr: ' + pr); - } - - assert(r.gte(0), r, 'r < 0'); - assert(r.lt(limit), r, 'r >= limit: ' + limit); - } - } - log('\n Testing random...'); - // First iteration crypto: false, second iteration crypto: true. - Decimal.config({ crypto: false, errors: true }); + Decimal.config({ errors: true, crypto: false }); - for ( i = 0; i < 2; i++ ) { - //log( '\n crypto: ' + Decimal.crypto ); + for ( i = 0; i < 9996; i++ ) { - Decimal.precision = Math.random() * 100 + 1 | 0; - //log( Decimal.precision ); + //Decimal.crypto = false; + //Decimal.crypto = true; + // 50% chance that Decimal.crypto is true. + //Decimal.crypto = Math.random() > 0.5; - for ( j = 0; j < 10; j++ ) { - - T(); - T(u); - T(null); - T(1); - T(1, u); - T(1, null); - T(10); - T(1000); - - // limit will have 1 - 17 integer digits and 1 - 17 fraction digits. - limit = +(Math.random() + '').slice(2, Math.random() * 17 + 3 | 0) + - (Math.random() + '').slice(1, Math.random() * 17 + 3 | 0); - - if ( +limit == 0 ) { - limit = 1; - } - - //log(' limit: ' + limit); - - T(limit); - - // Precision. Integer 1 - 80. - pr = Math.random() * 80 + 1 | 0; - - //log(' pr: ' + pr); - - T(limit, pr); + if ( Math.random() > 0.5 ) { + dp = Decimal.precision = Math.random() * 10 + 1 | 0; + r = Decimal.random(); + } else { + dp = Math.random() * 10 | 0; + r = Decimal.random(dp); } - Decimal.config({ crypto: true }); + //log(r.toString()); + + if ( r.c[0] ) { + j = r.c.length; + k = r.c[j - 1]; + j *= 7; + + // Decrement for trailing zeros in last element of r.c. + for ( ; k % 10 === 0; k /= 10, j-- ); + } else { + j = 0; + } + + // Check number of decimal places (j is actual dp). + if ( j > dp ) { + m = ' r.c.length - r.e - 1 > dp'; + + // Check 0 <= r < 1 + } else if ( r.lt(0) || r.gte(1) ) { + m = ' r.lt(0) || r.gte(1)'; + + // Check that the attributes of r are formed correctly. + } else if ( !r.eq( new Decimal(r) ) || !r.eq( new Decimal( r.toString() ) ) ) { + m = ' !r.eq( new Decimal(r) ) || !r.eq( new Decimal( r.toString() ) )'; + } + + total++; + + if (m) { + error('\n Test number: ' + total + ' failed'); + error(m); + error(' r: ' + r); + error(' r.c: ' + r.c); + error(' r.e: ' + r.e); + error(' r.s: ' + r.s); + error(' dp: ' + dp); + m = null; + } else { + passed++; + } } assertException(function () { Decimal.random(Infinity) }, 'Infinity'); diff --git a/test/toFixed.js b/test/toFixed.js index 5b36c0c..9012f90 100644 --- a/test/toFixed.js +++ b/test/toFixed.js @@ -15,7 +15,7 @@ var count = (function toFixed(Decimal) { str.replace('\n', '
') + '' }; } - if (!Decimal && typeof require === 'function') Decimal = require('../decimal'); + if (!Decimal && typeof require === 'function') Decimal = require('../decimal.js'); function assert(expected, actual) { total++; @@ -1051,11 +1051,8 @@ var count = (function toFixed(Decimal) { T('123.45000000000', '12.345e1', '1.1e1'); T('123.5', '12.345e1', 1); - T('120', '12.345e1', '-1'); - T('0', '12.345e1', -23); + T('123.45', '12.345e1', '-1'); T('123.45', '12.345e1', 1e9 + 1); - T('123', '12.345e1', '-0.01'); - T('123', '12.345e1', '-1e-1'); T('123.45', '12.345e1', Infinity); T('123.45', '12.345e1', '-Infinity'); @@ -1070,7 +1067,7 @@ var count = (function toFixed(Decimal) { T('1', 0.55, 0); T('1', 0.56, 0); T('-1', -0.54, 0); - T('-0', -0.5, 0); // test no. 1307 + T('-0', -0.5, 0); T('-1', -0.56, 0); T('-0.5', -0.5, 1); T('1.3', 1.25, 1); @@ -1119,27 +1116,6 @@ var count = (function toFixed(Decimal) { T('-1.00000000000000000', '-1.000000000000000000005', '17') T('-1.00000000000000000001', '-1.000000000000000000005', '20') - Decimal.rounding = 4; - - T('1000', 999.5, -1); - T('1000', 999.5, -2); - T('1000', 999.5, -3); - T('0', 999.5, -4); - T('0', 999.5, -5); - - T('0', 0.000123456, -1); - T('9870', 9870.000123456, -1); - T('9900', 9870.000123456, -2); - T('10000', 9870.000123456, -3); - - Decimal.rounding = 1; - - T('990', 999.5, -1); - T('900', 999.5, -2); - T('0', 999.5, -3); - T('0', 999.5, -4); - T('0', 999.5, -5); - log('\n ' + passed + ' of ' + total + ' tests passed in ' + (+new Date() - start) + ' ms \n'); return [passed, total]; })(this.Decimal);