From d102ead7af1bf72dbb28896f7a609ed8069180c6 Mon Sep 17 00:00:00 2001 From: Michael Mclaughlin Date: Tue, 22 Jun 2021 12:15:13 +0100 Subject: [PATCH] #101 Add clamp method --- decimal.js | 48 +++++++++++++++++++++++++++++++----------- decimal.mjs | 48 +++++++++++++++++++++++++++++++----------- doc/API.html | 34 ++++++++++++++++++++++++++++++ test/modules/clamp.js | 49 +++++++++++++++++++++++++++++++++++++++++++ test/test.html | 1 + test/test.js | 1 + 6 files changed, 157 insertions(+), 24 deletions(-) create mode 100644 test/modules/clamp.js diff --git a/decimal.js b/decimal.js index 8f445dd..2d1eb8a 100644 --- a/decimal.js +++ b/decimal.js @@ -131,6 +131,7 @@ /* * absoluteValue abs * ceil + * clampedTo clamp * comparedTo cmp * cosine cos * cubeRoot cbrt @@ -212,6 +213,26 @@ }; + /* + * Return a new Decimal whose value is the value of this Decimal clamped to the range + * delineated by `min` and `max`. + * + * min {number|string|Decimal} + * max {number|string|Decimal} + * + */ + P.clampedTo = P.clamp = function (min, max) { + var k, + x = this, + Ctor = x.constructor; + min = new Ctor(min); + max = new Ctor(max); + if (!min.s || !max.s || min.gt(max)) return new Ctor(NaN); + k = x.cmp(min); + return k < 0 ? min : x.cmp(max) > 0 ? max : new Ctor(x); + }; + + /* * Return * 1 if the value of this Decimal is greater than the value of `y`, @@ -2445,18 +2466,6 @@ }; - /* - // Add aliases to match BigDecimal method names. - // P.add = P.plus; - P.subtract = P.minus; - P.multiply = P.times; - P.divide = P.div; - P.remainder = P.mod; - P.compareTo = P.cmp; - P.negate = P.neg; - */ - - // Helper functions for Decimal.prototype (P) and/or Decimal methods, and their callers. @@ -3934,6 +3943,7 @@ * atan2 * cbrt * ceil + * clamp * clone * config * cos @@ -4153,6 +4163,19 @@ } + /* + * Return a new Decimal whose value is `x` clamped to the range delineated by `min` and `max`. + * + * x {number|string|Decimal} + * min {number|string|Decimal} + * max {number|string|Decimal} + * + */ + function clamp(x, min, max) { + return new this(x).clamp(min, max); + } + + /* * Configure global settings for a Decimal constructor. * @@ -4386,6 +4409,7 @@ Decimal.atan2 = atan2; Decimal.cbrt = cbrt; // ES6 Decimal.ceil = ceil; + Decimal.clamp = clamp; Decimal.cos = cos; Decimal.cosh = cosh; // ES6 Decimal.div = div; diff --git a/decimal.mjs b/decimal.mjs index 6ef5d42..6d03387 100644 --- a/decimal.mjs +++ b/decimal.mjs @@ -127,6 +127,7 @@ var EXP_LIMIT = 9e15, // 0 to 9e15 /* * absoluteValue abs * ceil + * clampedTo clamp * comparedTo cmp * cosine cos * cubeRoot cbrt @@ -208,6 +209,26 @@ P.ceil = function () { }; +/* + * Return a new Decimal whose value is the value of this Decimal clamped to the range + * delineated by `min` and `max`. + * + * min {number|string|Decimal} + * max {number|string|Decimal} + * + */ +P.clampedTo = P.clamp = function (min, max) { + var k, + x = this, + Ctor = x.constructor; + min = new Ctor(min); + max = new Ctor(max); + if (!min.s || !max.s || min.gt(max)) return new Ctor(NaN); + k = x.cmp(min); + return k < 0 ? min : x.cmp(max) > 0 ? max : new Ctor(x); +}; + + /* * Return * 1 if the value of this Decimal is greater than the value of `y`, @@ -2441,18 +2462,6 @@ P.valueOf = P.toJSON = function () { }; -/* -// Add aliases to match BigDecimal method names. -// P.add = P.plus; -P.subtract = P.minus; -P.multiply = P.times; -P.divide = P.div; -P.remainder = P.mod; -P.compareTo = P.cmp; -P.negate = P.neg; - */ - - // Helper functions for Decimal.prototype (P) and/or Decimal methods, and their callers. @@ -3930,6 +3939,7 @@ function truncate(arr, len) { * atan2 * cbrt * ceil + * clamp * clone * config * cos @@ -4149,6 +4159,19 @@ function ceil(x) { } +/* + * Return a new Decimal whose value is `x` clamped to the range delineated by `min` and `max`. + * + * x {number|string|Decimal} + * min {number|string|Decimal} + * max {number|string|Decimal} + * + */ +function clamp(x, min, max) { + return new this(x).clamp(min, max); +} + + /* * Configure global settings for a Decimal constructor. * @@ -4382,6 +4405,7 @@ function clone(obj) { Decimal.atan2 = atan2; Decimal.cbrt = cbrt; // ES6 Decimal.ceil = ceil; + Decimal.clamp = clamp; Decimal.cos = cos; Decimal.cosh = cosh; // ES6 Decimal.div = div; diff --git a/doc/API.html b/doc/API.html index 7af7e90..36b716e 100644 --- a/doc/API.html +++ b/doc/API.html @@ -76,6 +76,7 @@ li span{float:right;margin-right:10px;color:#c0c0c0}
  • atan2
  • cbrt
  • ceil
  • +
  • clamp
  • clone
  • cos
  • cosh
  • @@ -138,6 +139,7 @@ li span{float:right;margin-right:10px;color:#c0c0c0}
  • absoluteValue abs
  • ceil
  • comparedTo cmp
  • +
  • clampedTo clamp
  • cosine cos
  • cubeRoot cbrt
  • decimalPlaces dp
  • @@ -436,6 +438,16 @@ b = new Decimal(x).ceil() a.equals(b) // true + +
    clamp.clamp(min, max) ⇒ Decimal
    +

    + min: number|string|Decimal
    + max: number|string|Decimal +

    +

    See clampedTo.

    +
    Decimal.clamp(10.1, 0, 10)     // '10'
    + +
    clone @@ -1264,6 +1276,28 @@ y.ceil() // '-1' +
    clampedTo.clamp(min, max) ⇒ Decimal
    +

    + min: number|string|Decimal
    + max: number|string|Decimal +

    +

    + Returns a new Decimal whose value is the value of this Decimal clamped to the range + delineated by min and max. +

    +

    + The return value is not affected by the value of the + precision setting. +

    +
    +x = new Decimal(5)
    +min = new Decimal(100)
    +max = new Decimal(Infinity)
    +x.clampedTo(min, max)         // '100'
    +x.clamp(-10, -0.1)            // '-0.1'
    + + +
    comparedTo.cmp(x) ⇒ number

    x: number|string|Decimal

    diff --git a/test/modules/clamp.js b/test/modules/clamp.js new file mode 100644 index 0000000..29b4170 --- /dev/null +++ b/test/modules/clamp.js @@ -0,0 +1,49 @@ +if (typeof T === 'undefined') require('../setup'); + +T('clamp', function () { + + function t(x, min, max, expected) { + //T.assertEqual(expected, new Decimal(x).clampedTo(min, max).valueOf()); + T.assertEqual(expected, new Decimal(x).clamp(min, max).valueOf()); + //T.assertEqual(expected, Decimal.clamp(x, min, max).valueOf()); + } + + t('-0', '0', '0', '-0'); + t('-0', '-0', '0', '-0'); + t('-0', '0', '-0', '-0'); + t('-0', '-0', '-0', '-0'); + + t('0', '0', '0', '0'); + t('0', '-0', '0', '0'); + t('0', '0', '-0', '0'); + t('0', '-0', '-0', '0'); + + t(0, 0, 1, '0'); + t(-1, 0, 1, '0'); + t(-2, 0, 1, '0'); + t(1, 0, 1, '1'); + t(2, 0, 1, '1'); + + t(0, 0, -1, 'NaN'); + t(1, 1, 1, '1'); + t(-1, 1, 1, '1'); + t(-1, -1, 1, '-1'); + t(1, 1, -1, 'NaN'); + t(2, 1, 2, '2'); + t(3, 1, 2, '2'); + t(1, 0, 1, '1'); + t(2, 0, 1, '1'); + + t(Infinity, 0, 1, '1'); + t(0, -Infinity, 0, '0'); + t(-Infinity, 0, 1, '0'); + t(-Infinity, -Infinity, Infinity, '-Infinity'); + t(Infinity, -Infinity, Infinity, 'Infinity'); + t(Infinity, Infinity, -Infinity, 'NaN'); + t(0, Infinity, 0, 'NaN'); + t(0, 1, Infinity, '1'); + + t(0, NaN, 1, 'NaN'); + t(0, 0, NaN, 'NaN'); + t(NaN, 0, 1, 'NaN'); +}); \ No newline at end of file diff --git a/test/test.html b/test/test.html index 7412f16..be0033c 100644 --- a/test/test.html +++ b/test/test.html @@ -28,6 +28,7 @@ 'atanh', 'cbrt', 'ceil', + 'clamp', 'clone', 'cmp', 'config', diff --git a/test/test.js b/test/test.js index bcc42f4..9758ea1 100644 --- a/test/test.js +++ b/test/test.js @@ -15,6 +15,7 @@ console.log('\n Testing decimal.js\n'); 'atanh', 'cbrt', 'ceil', + 'clamp', 'clone', 'cmp', 'config',