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*l
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 @@
-
|