From fd668fea70a41cf8e2493aee7125861c84738463 Mon Sep 17 00:00:00 2001
From: Michael Mclaughlin
Date: Sat, 9 Dec 2017 22:05:28 +0000
Subject: [PATCH] Add Decimal.isDecimal and config reset
---
decimal.d.ts | 3 ++
decimal.js | 33 ++++++++++++++++-----
decimal.mjs | 45 +++++++++++++++++++---------
doc/API.html | 59 +++++++++++++++++++++++++++++--------
test/modules/clone.js | 35 ++++++++++++++++++++++
test/modules/config.js | 31 +++++++++++++++++++
test/modules/isFiniteEtc.js | 20 ++++++++++++-
7 files changed, 191 insertions(+), 35 deletions(-)
diff --git a/decimal.d.ts b/decimal.d.ts
index d072ec7..8bee33a 100644
--- a/decimal.d.ts
+++ b/decimal.d.ts
@@ -76,6 +76,7 @@ interface DecimalConfig {
// Requires `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
diff --git a/decimal.js b/decimal.js
index d1f27d8..addde56 100644
--- a/decimal.js
+++ b/decimal.js
@@ -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;
diff --git a/decimal.mjs b/decimal.mjs
index 39e0cd1..595b3cb 100644
--- a/decimal.mjs
+++ b/decimal.mjs
@@ -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;
diff --git a/doc/API.html b/doc/API.html
index c9f12ef..ab44236 100644
--- a/doc/API.html
+++ b/doc/API.html
@@ -83,6 +83,7 @@ li span{float:right;margin-right:10px;color:#c0c0c0}
exp
floor
hypot
+ isDecimal
ln
log
log2
@@ -195,9 +196,9 @@ li span{float:right;margin-right:10px;color:#c0c0c0}
Properties
- - ddigits
- - eexponent
- - ssign
+ - ddigits
+ - eexponent
+ - ssign
Zero, NaN & Infinity
@@ -446,24 +447,32 @@ a.equals(b) // true
settings as this
Decimal constructor if object
is omitted.
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 })
+// Decimal9 = Decimal.clone({ precision: 9 }) is equivalent to:
+Decimal9 = Decimal.clone()
+Decimal9.set({ precision: 9 })
+
+ If object
has a 'defaults'
property with value true
+ then the new constructor will use the default configuration.
+
+
+D1 = Decimal.clone({ defaults: true })
+
+// Use the defaults except for precision
+D2 = Decimal.clone({ defaults: true, precision: 50 })
It is not inefficient in terms of memory usage to use multiple Decimal constructors as
functions are shared between them.
-
cos.cos(x) ⇒ Decimal
x
: number|string|Decimal
See cosine
.
@@ -537,6 +546,22 @@ a.equals(b) // true
+
+ isDecimal.isDecimal(object) ⇒ boolean
+
+ object
: any
+
+ Returns true
if object
is a Decimal instance (where Decimal is any
+ Decimal constructor), or false
if it is not.
+
+ a = new Decimal(1)
+b = {}
+a instanceof Decimal // true
+Decimal.isDecimal(a) // true
+Decimal.isDecimal(b) // false
+
+
+
log.log(x [, base]) ⇒ Decimal
x
: number|string|Decimal
@@ -720,6 +745,10 @@ a.equals(b) // true
The values of the configuration object properties are checked for validity and then stored as
equivalently-named properties of this
Decimal constructor.
+
+ If object
has a 'defaults'
property with value true
+ then any unspecified properties will be reset to their default values.
+
Throws on an invalid object
or configuration property value.
// Defaults
@@ -732,7 +761,13 @@ Decimal.set({
minE: -9e15,
modulo: 1,
crypto: false
-})
+})
+
+// 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 })
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'
-1 , 1 , or NaN |
- The properties are best considered to be read-only.
+ All the properties are best considered to be read-only.
- 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.
diff --git a/test/modules/clone.js b/test/modules/clone.js
index 5e7a457..fd76874 100644
--- a/test/modules/clone.js
+++ b/test/modules/clone.js
@@ -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);
});
diff --git a/test/modules/config.js b/test/modules/config.js
index 9a3596d..08e1ea5 100644
--- a/test/modules/config.js
+++ b/test/modules/config.js
@@ -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);
});
diff --git a/test/modules/isFiniteEtc.js b/test/modules/isFiniteEtc.js
index 04b0b73..6e3c442 100644
--- a/test/modules/isFiniteEtc.js
+++ b/test/modules/isFiniteEtc.js
@@ -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)));
});