Add Decimal.isDecimal and config reset

pull/83/head
Michael Mclaughlin 7 years ago
parent 17a358f2f4
commit fd668fea70

3
decimal.d.ts vendored

@ -76,6 +76,7 @@ interface DecimalConfig {
// Requires `toFormat` <https://github.com/MikeMcl/toFormat>.
format?: DecimalFormat;
defaults?: boolean;
}
// Requires `toFormat`.
@ -92,6 +93,7 @@ export declare class Decimal {
readonly d: number[];
readonly e: number;
readonly s: number;
private readonly name: string;
constructor(n: DecimalValue);
@ -285,6 +287,7 @@ export declare class Decimal {
static exp(n: DecimalValue): Decimal
static floor(n: DecimalValue): Decimal
static hypot(...n: DecimalValue[]): Decimal
static isDecimal(object: any): boolean
static ln(n: DecimalValue): Decimal
static log(n: DecimalValue, base?: DecimalValue): Decimal
static log2(n: DecimalValue): Decimal

@ -34,7 +34,7 @@
// The initial configuration properties of the Decimal constructor.
Decimal = {
DEFAULTS = {
// These values must be integers within the stated ranges (inclusive).
// Most of these values can be changed at run-time using the `Decimal.config` method.
@ -99,7 +99,7 @@
// ----------------------------------- END OF EDITABLE DEFAULTS ------------------------------- //
inexact, noConflict, quadrant,
Decimal, inexact, noConflict, quadrant,
external = true,
decimalError = '[DecimalError] ',
@ -123,7 +123,7 @@
PI_PRECISION = PI.length - 1,
// Decimal.prototype object
P = {};
P = { name: '[object Decimal]' };
// Decimal prototype methods
@ -4160,6 +4160,7 @@
* minE {number}
* modulo {number}
* crypto {boolean|number}
* defaults {true}
*
* E.g. Decimal.config({ precision: 20, rounding: 4 })
*
@ -4167,6 +4168,7 @@
function config(obj) {
if (!obj || typeof obj !== 'object') throw Error(decimalError + 'Object expected');
var i, p, v,
useDefaults = obj.defaults === true,
ps = [
'precision', 1, MAX_DIGITS,
'rounding', 0, 8,
@ -4178,13 +4180,15 @@
];
for (i = 0; i < ps.length; i += 3) {
if ((v = obj[p = ps[i]]) !== void 0) {
if (p = ps[i], useDefaults) this[p] = DEFAULTS[p];
if ((v = obj[p]) !== void 0) {
if (mathfloor(v) === v && v >= ps[i + 1] && v <= ps[i + 2]) this[p] = v;
else throw Error(invalidArgument + p + ': ' + v);
}
}
if ((v = obj[p = 'crypto']) !== void 0) {
if (p = 'crypto', useDefaults) this[p] = DEFAULTS[p];
if ((v = obj[p]) !== void 0) {
if (v === true || v === false || v === 0 || v === 1) {
if (v) {
if (typeof crypto != 'undefined' && crypto &&
@ -4327,6 +4331,7 @@
Decimal.config = Decimal.set = config;
Decimal.clone = clone;
Decimal.isDecimal = isDecimalInstance;
Decimal.abs = abs;
Decimal.acos = acos;
@ -4367,8 +4372,10 @@
if (obj === void 0) obj = {};
if (obj) {
ps = ['precision', 'rounding', 'toExpNeg', 'toExpPos', 'maxE', 'minE', 'modulo', 'crypto'];
for (i = 0; i < ps.length;) if (!obj.hasOwnProperty(p = ps[i++])) obj[p] = this[p];
if (obj.defaults !== true) {
ps = ['precision', 'rounding', 'toExpNeg', 'toExpPos', 'maxE', 'minE', 'modulo', 'crypto'];
for (i = 0; i < ps.length;) if (!obj.hasOwnProperty(p = ps[i++])) obj[p] = this[p];
}
}
Decimal.config(obj);
@ -4445,6 +4452,16 @@
}
/*
* Return true if object is a Decimal instance (where Decimal is any Decimal constructor),
* otherwise return false.
*
*/
function isDecimalInstance(obj) {
return obj instanceof Decimal || obj && obj.name === '[object Decimal]' || false;
}
/*
* Return a new Decimal whose value is the natural logarithm of `x`, rounded to `precision`
* significant digits using rounding mode `rounding`.
@ -4775,7 +4792,7 @@
// Create and configure initial Decimal constructor.
Decimal = clone(Decimal);
Decimal = clone(DEFAULTS);
Decimal['default'] = Decimal.Decimal = Decimal;

@ -25,14 +25,14 @@ var EXP_LIMIT = 9e15, // 0 to 9e15
NUMERALS = '0123456789abcdef',
// The natural logarithm of 10 (1025 digits).
ln10 = '2.3025850929940456840179914546843642076011014886287729760333279009675726096773524802359972050895982983419677840422862486334095254650828067566662873690987816894829072083255546808437998948262331985283935053089653777326288461633662222876982198867465436674744042432743651550489343149393914796194044002221051017141748003688084012647080685567743216228355220114804663715659121373450747856947683463616792101806445070648000277502684916746550586856935673420670581136429224554405758925724208241314695689016758940256776311356919292033376587141660230105703089634572075440370847469940168269282808481184289314848524948644871927809676271275775397027668605952496716674183485704422507197965004714951050492214776567636938662976979522110718264549734772662425709429322582798502585509785265383207606726317164309505995087807523710333101197857547331541421808427543863591778117054309827482385045648019095610299291824318237525357709750539565187697510374970888692180205189339507238539205144634197265287286965110862571492198849978748873771345686209167058',
LN10 = '2.3025850929940456840179914546843642076011014886287729760333279009675726096773524802359972050895982983419677840422862486334095254650828067566662873690987816894829072083255546808437998948262331985283935053089653777326288461633662222876982198867465436674744042432743651550489343149393914796194044002221051017141748003688084012647080685567743216228355220114804663715659121373450747856947683463616792101806445070648000277502684916746550586856935673420670581136429224554405758925724208241314695689016758940256776311356919292033376587141660230105703089634572075440370847469940168269282808481184289314848524948644871927809676271275775397027668605952496716674183485704422507197965004714951050492214776567636938662976979522110718264549734772662425709429322582798502585509785265383207606726317164309505995087807523710333101197857547331541421808427543863591778117054309827482385045648019095610299291824318237525357709750539565187697510374970888692180205189339507238539205144634197265287286965110862571492198849978748873771345686209167058',
// Pi (1025 digits).
pi = '3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632789',
PI = '3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632789',
// The initial configuration properties of the Decimal constructor.
defaults = {
DEFAULTS = {
// These values must be integers within the stated ranges (inclusive).
// Most of these values can be changed at run-time using the `Decimal.config` method.
@ -97,7 +97,7 @@ var EXP_LIMIT = 9e15, // 0 to 9e15
// ----------------------------------- END OF EDITABLE DEFAULTS ------------------------------- //
Decimal, LN10, PI, inexact, quadrant,
Decimal, inexact, quadrant,
external = true,
decimalError = '[DecimalError] ',
@ -117,11 +117,11 @@ var EXP_LIMIT = 9e15, // 0 to 9e15
LOG_BASE = 7,
MAX_SAFE_INTEGER = 9007199254740991,
LN10_PRECISION = ln10.length - 1,
PI_PRECISION = pi.length - 1,
LN10_PRECISION = LN10.length - 1,
PI_PRECISION = PI.length - 1,
// Decimal.prototype object
P = {};
P = { name: '[object Decimal]' };
// Decimal prototype methods
@ -4158,6 +4158,7 @@ function ceil(x) {
* minE {number}
* modulo {number}
* crypto {boolean|number}
* defaults {true}
*
* E.g. Decimal.config({ precision: 20, rounding: 4 })
*
@ -4165,6 +4166,7 @@ function ceil(x) {
function config(obj) {
if (!obj || typeof obj !== 'object') throw Error(decimalError + 'Object expected');
var i, p, v,
useDefaults = obj.defaults === true,
ps = [
'precision', 1, MAX_DIGITS,
'rounding', 0, 8,
@ -4176,13 +4178,15 @@ function config(obj) {
];
for (i = 0; i < ps.length; i += 3) {
if ((v = obj[p = ps[i]]) !== void 0) {
if (p = ps[i], useDefaults) this[p] = DEFAULTS[p];
if ((v = obj[p]) !== void 0) {
if (mathfloor(v) === v && v >= ps[i + 1] && v <= ps[i + 2]) this[p] = v;
else throw Error(invalidArgument + p + ': ' + v);
}
}
if ((v = obj[p = 'crypto']) !== void 0) {
if (p = 'crypto', useDefaults) this[p] = DEFAULTS[p];
if ((v = obj[p]) !== void 0) {
if (v === true || v === false || v === 0 || v === 1) {
if (v) {
if (typeof crypto != 'undefined' && crypto &&
@ -4325,6 +4329,7 @@ function clone(obj) {
Decimal.config = Decimal.set = config;
Decimal.clone = clone;
Decimal.isDecimal = isDecimalInstance;
Decimal.abs = abs;
Decimal.acos = acos;
@ -4365,8 +4370,10 @@ function clone(obj) {
if (obj === void 0) obj = {};
if (obj) {
ps = ['precision', 'rounding', 'toExpNeg', 'toExpPos', 'maxE', 'minE', 'modulo', 'crypto'];
for (i = 0; i < ps.length;) if (!obj.hasOwnProperty(p = ps[i++])) obj[p] = this[p];
if (obj.defaults !== true) {
ps = ['precision', 'rounding', 'toExpNeg', 'toExpPos', 'maxE', 'minE', 'modulo', 'crypto'];
for (i = 0; i < ps.length;) if (!obj.hasOwnProperty(p = ps[i++])) obj[p] = this[p];
}
}
Decimal.config(obj);
@ -4443,6 +4450,16 @@ function hypot() {
}
/*
* Return true if object is a Decimal instance (where Decimal is any Decimal constructor),
* otherwise return false.
*
*/
function isDecimalInstance(obj) {
return obj instanceof Decimal || obj && obj.name === '[object Decimal]' || false;
}
/*
* Return a new Decimal whose value is the natural logarithm of `x`, rounded to `precision`
* significant digits using rounding mode `rounding`.
@ -4773,12 +4790,12 @@ function trunc(x) {
// Create and configure initial Decimal constructor.
Decimal = clone(defaults);
Decimal = clone(DEFAULTS);
Decimal['default'] = Decimal.Decimal = Decimal;
// Create the internal constants from their string values.
LN10 = new Decimal(ln10);
PI = new Decimal(pi);
LN10 = new Decimal(LN10);
PI = new Decimal(PI);
export default Decimal;

@ -83,6 +83,7 @@ li span{float:right;margin-right:10px;color:#c0c0c0}
<li><a href="#Dexp" >exp</a></li>
<li><a href="#Dfloor" >floor</a></li>
<li><a href="#Dhypot" >hypot</a></li>
<li><a href="#DisDecimal" >isDecimal</a></li>
<li><a href="#Dln" >ln</a></li>
<li><a href="#Dlog" >log</a></li>
<li><a href="#Dlog2" >log2</a></li>
@ -195,9 +196,9 @@ li span{float:right;margin-right:10px;color:#c0c0c0}
<a href="#instance-properties">Properties</a>
<ul>
<li><a href="#digits" >d</a><span>digits</span></li>
<li><a href="#exponent">e</a><span>exponent</span></li>
<li><a href="#sign" >s</a><span>sign</span></li>
<li><a href="#digits" >d</a><span>digits</span></li>
<li><a href="#exponent" >e</a><span>exponent</span></li>
<li><a href="#sign" >s</a><span>sign</span></li>
</ul>
<a href="#zero-nan-infinity">Zero, NaN &amp; Infinity</a>
@ -446,24 +447,32 @@ a.equals(b) // true</pre>
settings as <code>this</code> Decimal constructor if <code>object</code> is omitted.
</p>
<pre>Decimal.set({ precision: 5 })
D9 = Decimal.clone({ precision: 9 })
Decimal9 = Decimal.clone({ precision: 9 })
a = new Decimal(1)
b = new D9(1)
b = new Decimal9(1)
a.div(3) // 0.33333
b.div(3) // 0.333333333
// D9 = Decimal.clone({ precision: 9 }) is equivalent to:
D9 = Decimal.clone()
D9.set({ precision: 9 })</pre>
// Decimal9 = Decimal.clone({ precision: 9 }) is equivalent to:
Decimal9 = Decimal.clone()
Decimal9.set({ precision: 9 })</pre>
<p>
If <code>object</code> has a <code>'defaults'</code> property with value <code>true</code>
then the new constructor will use the default configuration.
</p>
<pre>
D1 = Decimal.clone({ defaults: true })
// Use the defaults except for precision
D2 = Decimal.clone({ defaults: true, precision: 50 })</pre>
<p>
It is not inefficient in terms of memory usage to use multiple Decimal constructors as
functions are shared between them.
</p>
<h5 id="Dcos">cos<code class='inset'>.cos(x) <i>&rArr; Decimal</i></code></h5>
<p><code>x</code>: <i>number|string|Decimal</i></p>
<p>See <code><a href='#cos'>cosine</a></code>.</p>
@ -537,6 +546,22 @@ a.equals(b) // true</pre>
<h5 id="DisDecimal">
isDecimal<code class='inset'>.isDecimal(object) <i>&rArr; boolean</i></code>
</h5>
<p><code>object</code>: <i>any</i></p>
<p>
Returns <code>true</code> if <code>object</code> is a Decimal instance (where Decimal is any
Decimal constructor), or <code>false</code> if it is not.
</p>
<pre>a = new Decimal(1)
b = {}
a instanceof Decimal // true
Decimal.isDecimal(a) // true
Decimal.isDecimal(b) // false</pre>
<h5 id="Dlog">log<code class='inset'>.log(x [, base]) <i>&rArr; Decimal</i></code></h5>
<p>
<code>x</code>: <i>number|string|Decimal</i><br />
@ -720,6 +745,10 @@ a.equals(b) // true</pre>
The values of the configuration object properties are checked for validity and then stored as
equivalently-named properties of <code>this</code> Decimal constructor.
</p>
<p>
If <code>object</code> has a <code>'defaults'</code> property with value <code>true</code>
then any unspecified properties will be reset to their default values.
</p>
<p>Throws on an invalid <code>object</code> or configuration property value.</p>
<pre>
// Defaults
@ -732,7 +761,13 @@ Decimal.set({
minE: -9e15,
modulo: 1,
crypto: false
})</pre>
})
// Reset all properties to their default values
Decimal.set({ defaults: true })
// Set precision to 50 and all other properties to their default values
Decimal.set({ precision: 50, defaults: true })</pre>
<p>
The properties of a Decimal constructor can also be set by direct assignment, but that will
by-pass the validity checking that this method performs - this is not a problem if the user
@ -2478,9 +2513,9 @@ x.valueOf() // '-0'</pre>
<td><code>-1</code>, <code>1</code>, or <code>NaN</code></td>
</tr>
</table>
<p>The properties are best considered to be read-only.</p>
<p>All the properties are best considered to be read-only.</p>
<p>
As with JavaScript numbers, the original exponent and fractional trailing zeros of a number
As with JavaScript numbers, the original exponent and fractional trailing zeros of a value
are not preserved.
</p>
<pre>

@ -105,5 +105,40 @@ T('clone', function () {
t(new D8(1).constructor !== new D9(1).constructor);
T.assertException(function () { Decimal.clone(null) }, "Decimal.clone(null)");
// defaults: true
Decimal.config({
precision: 100,
rounding: 2,
toExpNeg: -100,
toExpPos: 200,
defaults: true
});
t(Decimal.precision === 100);
t(Decimal.rounding === 2);
t(Decimal.toExpNeg === -100);
t(Decimal.toExpPos === 200);
t(Decimal.defaults === undefined);
D1 = Decimal.clone({ defaults: true });
t(D1.precision === 20);
t(D1.rounding === 4);
t(D1.toExpNeg === -7);
t(D1.toExpPos === 21);
t(D1.defaults === undefined);
D2 = Decimal.clone({ defaults: true, rounding: 5 });
t(D2.precision === 20);
t(D2.rounding === 5);
t(D2.toExpNeg === -7);
t(D2.toExpPos === 21);
D3 = Decimal.clone({ defaults: false });
t(D3.rounding === 2);
});

@ -338,5 +338,36 @@ T('config', function () {
t(9, {modulo: void 0});
// defaults
t = function (actual) {
T.assert(actual);
}
Decimal.config({
precision: 100,
rounding: 2,
toExpNeg: -100,
toExpPos: 200,
});
t(Decimal.precision === 100);
Decimal.config({ defaults: true });
t(Decimal.precision === 20);
t(Decimal.rounding === 4);
t(Decimal.toExpNeg === -7);
t(Decimal.toExpPos === 21);
t(Decimal.defaults === undefined);
Decimal.rounding = 3;
Decimal.config({ precision: 50, defaults: true });
t(Decimal.precision === 50);
t(Decimal.rounding === 4);
// Decimal.set is an alias for Decimal.config
T.assertEqual(Decimal.set, Decimal.config);
});

@ -1,6 +1,6 @@
if (typeof T === 'undefined') require('../setup');
T('isFinite, isInteger, isNaN, isNegative, isZero', function () {
T('isFinite, isInteger, isNaN, isNegative, isZero, isDecimal', function () {
function t(actual) {
T.assert(actual);
@ -257,4 +257,22 @@ T('isFinite, isInteger, isNaN, isNegative, isZero', function () {
t(!new Decimal('0.999999999999999999999').isInteger());
t(new Decimal('4e4').isInteger());
t(new Decimal('-4e4').isInteger());
// Decimal.isDecimal
t(Decimal.isDecimal(new Decimal(1)));
t(Decimal.isDecimal(new Decimal('-2.3')));
t(Decimal.isDecimal(new Decimal(NaN)));
t(Decimal.isDecimal(new Decimal('Infinity')));
t(!Decimal.isDecimal());
t(!Decimal.isDecimal(0));
t(!Decimal.isDecimal(1));
t(!Decimal.isDecimal('-2.3'));
t(!Decimal.isDecimal(NaN));
t(!Decimal.isDecimal(Infinity));
t(!Decimal.isDecimal(undefined));
t(!Decimal.isDecimal({}));
t(!Decimal.isDecimal({isDecimal: true}));
t(!Decimal.isDecimal(new Number(4)));
});

Loading…
Cancel
Save