From 0ae1879884de2fb6dbfaeb6eb8efc6b629dff9e8 Mon Sep 17 00:00:00 2001 From: josdejong Date: Thu, 28 Nov 2013 13:38:08 +0100 Subject: [PATCH] Fixed function format for precision > 20 (see #100) --- lib/util/number.js | 38 ++++++++++++++++++++------ test/util/number.test.js | 59 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 9 deletions(-) diff --git a/lib/util/number.js b/lib/util/number.js index 7570ec015..5d11b2dc4 100644 --- a/lib/util/number.js +++ b/lib/util/number.js @@ -141,12 +141,10 @@ exports.format = function format(value, options) { // handle the various notations switch (notation) { case 'fixed': - return value.toFixed(precision || 0); - // Note: the (precision || 0) is needed for BigNumber, which has an - // undefined default precision instead of 0. + return exports.toFixed(value, precision); case 'scientific': - return exports.toScientific(value, precision); + return exports.toExponential(value, precision); case 'auto': // determine lower and upper bound for scientific notation. @@ -187,12 +185,12 @@ exports.format = function format(value, options) { str = new BigNumber(value.toPrecision(precision)).toString(); } else { // Number - str = parseFloat(value.toPrecision(precision)) + ''; + str = parseFloat(value.toPrecision(precision ? Math.min(precision, 21) : precision)) + ''; } } else { // scientific notation - str = exports.toScientific(value, precision); + str = exports.toExponential(value, precision); } // restore BigNumber configuration @@ -248,21 +246,43 @@ function _isBetween(value, lower, upper) { /** * Format a number in scientific notation. Like '1.23e+5', '2.3e+0', '3.500e-3' - * @param {Number} value + * @param {Number | BigNumber} value * @param {Number} [precision] Number of digits in formatted output. * If not provided, the maximum available digits * is used. * @returns {string} str */ -exports.toScientific = function toScientific (value, precision) { +exports.toExponential = function toExponential (value, precision) { if (precision !== undefined) { - return value.toExponential(precision - 1); + if (value instanceof BigNumber) { + return value.toExponential(precision - 1); + } + else { // Number + return value.toExponential(Math.min(precision - 1, 20)); + } } else { return value.toExponential(); } }; +/** + * Format a number with fixed notation. + * @param {Number | BigNumber} value + * @param {Number} [precision=0] Optional number of decimals after the + * decimal point. Zero by default. + */ +exports.toFixed = function toFixed (value, precision) { + if (value instanceof BigNumber) { + return value.toFixed(precision || 0); + // Note: the (precision || 0) is needed as the toFixed of BigNumber has an + // undefined default precision instead of 0. + } + else { // Number + return value.toFixed(Math.min(precision, 20)); + } +}; + /** * Count the number of significant digits of a number. * diff --git a/test/util/number.test.js b/test/util/number.test.js index b8e986591..595cd47b6 100644 --- a/test/util/number.test.js +++ b/test/util/number.test.js @@ -63,6 +63,62 @@ describe('number', function() { assert.equal(number.digits(120.5e50), 4); }); + it('should format a number using toFixed', function() { + assert.equal(number.toFixed(2.34), '2'); + assert.equal(number.toFixed(2.34, 1), '2.3'); + assert.equal(number.toFixed(2.34e10, 1), '23400000000.0'); + assert.equal(number.toFixed(2.34e-10, 1), '0.0'); + assert.equal(number.toFixed(2, 20), '2.00000000000000000000'); + assert.equal(number.toFixed(2, 21), '2.00000000000000000000'); + assert.equal(number.toFixed(2, 22), '2.00000000000000000000'); + assert.equal(number.toFixed(2, 30), '2.00000000000000000000'); + }); + + it('should format a bignumber using toFixed', function() { + var DECIMAL_PLACES = BigNumber.config().DECIMAL_PLACES; + BigNumber.config(100); + + assert.equal(number.toFixed(new BigNumber(2.34)), '2'); + assert.equal(number.toFixed(new BigNumber(2.34), 1), '2.3'); + assert.equal(number.toFixed(new BigNumber(2), 20), '2.00000000000000000000'); + assert.equal(number.toFixed(new BigNumber(2), 21), '2.000000000000000000000'); + assert.equal(number.toFixed(new BigNumber(2), 22), '2.0000000000000000000000'); + assert.equal(number.toFixed(new BigNumber(2), 30), '2.000000000000000000000000000000'); + + // restore global bignumber configuration + BigNumber.config(DECIMAL_PLACES); + }); + + it('should format a number using toExponential', function() { + assert.equal(number.toExponential(2.34), '2.34e+0'); + assert.equal(number.toExponential(2.34e+3), '2.34e+3'); + assert.equal(number.toExponential(2.34e-3), '2.34e-3'); + assert.equal(number.toExponential(2.34e+3, 2), '2.3e+3'); + assert.equal(number.toExponential(2e+3, 20), '2.0000000000000000000e+3'); + assert.equal(number.toExponential(2e+3, 21), '2.00000000000000000000e+3'); + assert.equal(number.toExponential(2e+3, 22), '2.00000000000000000000e+3'); + assert.equal(number.toExponential(2e+3, 30), '2.00000000000000000000e+3'); + }); + + it('should format a bignumber using toExponential', function() { + var DECIMAL_PLACES = BigNumber.config().DECIMAL_PLACES; + BigNumber.config(100); + + assert.equal(number.toExponential(new BigNumber(2.34)), '2.34e+0'); + assert.equal(number.toExponential(new BigNumber(2.34e+3)), '2.34e+3'); + assert.equal(number.toExponential(new BigNumber(2.34e-3)), '2.34e-3'); + assert.equal(number.toExponential(new BigNumber(2.34e+3), 2), '2.3e+3'); + assert.equal(number.toExponential(new BigNumber(2e+3), 20), '2.0000000000000000000e+3'); + assert.equal(number.toExponential(new BigNumber(2e+3), 21), '2.00000000000000000000e+3'); + assert.equal(number.toExponential(new BigNumber(2e+3), 22), '2.000000000000000000000e+3'); + assert.equal(number.toExponential(new BigNumber(2e+3), 30), '2.00000000000000000000000000000e+3'); + assert.equal(number.toExponential(new BigNumber('2e+300'), 30), '2.00000000000000000000000000000e+300'); + assert.equal(number.toExponential(new BigNumber('2e-300'), 30), '2.00000000000000000000000000000e-300'); + + // restore global bignumber configuration + BigNumber.config(DECIMAL_PLACES); + }); + it('should convert a number into a bignumber (when possible)', function() { assert.deepEqual(number.toBigNumber(2.34), new BigNumber(2.34)); assert.deepEqual(number.toBigNumber(0), new BigNumber(0)); @@ -189,6 +245,9 @@ describe('number', function() { assert.equal(number.format(123e-6, {precision: 8}), '1.23e-4'); // should remove trailing zeros assert.equal(number.format(3e+6, {precision: 8}), '3e+6'); // should remove trailing zeros assert.equal(number.format(1234, {precision: 2}), '1200'); + + // overflow the maximum allowed precision of 20 + assert.equal(number.format(2.3, {precision: 30}), '2.3'); }); it('auto notation with custom lower and upper bound', function () {