mirror of
https://github.com/josdejong/mathjs.git
synced 2026-01-18 14:59:29 +00:00
Some more fixes and improvements in NumberFormatter
This commit is contained in:
parent
2cdeb0d49b
commit
5dfa79196e
@ -3,7 +3,7 @@
|
||||
## not-yet-released, version 1.5.1
|
||||
|
||||
- Fixed #316: a bug in rounding values when formatting.
|
||||
- Fixed #317: a bug in formatting negative values.
|
||||
- Fixed #317, #319: a bug in formatting negative values.
|
||||
|
||||
|
||||
## 2015-03-28, version 1.5.0
|
||||
|
||||
@ -47,18 +47,28 @@ function NumberFormatter (value) {
|
||||
* decimal point. Zero by default.
|
||||
*/
|
||||
NumberFormatter.prototype.toFixed = function (precision) {
|
||||
if (precision) {
|
||||
var dot = this.exponent > 0 ? this.exponent : 0;
|
||||
var all = init(-this.exponent, 0).concat(this.coefficients);
|
||||
var coefficients = round(all, dot + precision + 1);
|
||||
coefficients.splice(dot + 1, 0, '.');
|
||||
var rounded = this.roundDigits(this.exponent + 1 + (precision || 0));
|
||||
var c = rounded.coefficients;
|
||||
var p = rounded.exponent + 1; // exponent may have changed
|
||||
|
||||
return this.sign + coefficients.join('');
|
||||
// append zeros if needed
|
||||
var pp = p + (precision || 0);
|
||||
if (c.length < pp) {
|
||||
c = c.concat(zeros(pp - c.length));
|
||||
}
|
||||
else {
|
||||
// TODO: make the || '0' redundant
|
||||
return this.sign + round(this.coefficients, this.exponent + 1).join('') || '0';
|
||||
|
||||
// prepend zeros if needed
|
||||
if (p < 0) {
|
||||
c = zeros(-p + 1).concat(c);
|
||||
p = 1;
|
||||
}
|
||||
|
||||
// insert a dot if needed
|
||||
if (precision) {
|
||||
c.splice(p, 0, (p === 0) ? '0.' : '.');
|
||||
}
|
||||
|
||||
return this.sign + c.join('');
|
||||
};
|
||||
|
||||
/**
|
||||
@ -68,15 +78,20 @@ NumberFormatter.prototype.toFixed = function (precision) {
|
||||
* is used.
|
||||
*/
|
||||
NumberFormatter.prototype.toExponential = function (precision) {
|
||||
var coefficients = precision
|
||||
? round(this.coefficients, precision)
|
||||
: this.coefficients.slice(0);
|
||||
// round if needed, else create a clone
|
||||
var rounded = precision ? this.roundDigits(precision) : this.clone();
|
||||
var c = rounded.coefficients;
|
||||
var e = rounded.exponent;
|
||||
|
||||
var first = coefficients.shift();
|
||||
return this.sign +
|
||||
first +
|
||||
(coefficients.length > 0 ? ('.' + coefficients.join('')) : '') +
|
||||
'e' + (this.exponent >= 0 ? '+' : '') + this.exponent;
|
||||
// append zeros if needed
|
||||
if (c.length < precision) {
|
||||
c = c.concat(zeros(precision - c.length));
|
||||
}
|
||||
|
||||
// format as `C.CCCe+EEE` or `C.CCCe-EEE`
|
||||
var first = c.shift();
|
||||
return this.sign + first + (c.length > 0 ? ('.' + c.join('')) : '') +
|
||||
'e' + (e >= 0 ? '+' : '') + e;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -99,74 +114,92 @@ NumberFormatter.prototype.toPrecision = function(precision, options) {
|
||||
return this.toExponential(precision);
|
||||
}
|
||||
else {
|
||||
var all = init(-this.exponent, 0).concat(this.coefficients);
|
||||
|
||||
var coefficients = precision
|
||||
? round(all, precision + (this.exponent < 0 ? -this.exponent : 0))
|
||||
: all;
|
||||
var rounded = precision ? this.roundDigits(precision) : this.clone();
|
||||
var c = rounded.coefficients;
|
||||
var e = rounded.exponent;
|
||||
|
||||
// append trailing zeros
|
||||
var trailing = init(this.exponent - coefficients.length + 1, 0);
|
||||
coefficients = coefficients.concat(trailing);
|
||||
|
||||
var dot = this.exponent > 0 ? this.exponent : 0;
|
||||
if (dot < coefficients.length - 1) {
|
||||
coefficients.splice(dot + 1, 0, '.');
|
||||
if (c.length < precision) {
|
||||
c = c.concat(zeros(precision - c.length));
|
||||
}
|
||||
|
||||
return this.sign + coefficients.join('');
|
||||
// append trailing zeros
|
||||
// TODO: simplify the next statement
|
||||
c = c.concat(zeros(e - c.length + 1 +
|
||||
(c.length < precision ? precision - c.length : 0)));
|
||||
|
||||
// prepend zeros
|
||||
c = zeros(-e).concat(c);
|
||||
|
||||
var dot = e > 0 ? e : 0;
|
||||
if (dot < c.length - 1) {
|
||||
c.splice(dot + 1, 0, '.');
|
||||
}
|
||||
|
||||
return this.sign + c.join('');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Round an array with coefficients. For example:
|
||||
*
|
||||
* round([2,3,4,5,6], 2) returns '23'
|
||||
* round([2,3,4,5,6], 4) returns '2346'
|
||||
* round([2,3], 4) returns '2300'
|
||||
*
|
||||
* @param {number[]} coefficients
|
||||
* @param {number} count
|
||||
* @return {number[]} Returns array with rounded coefficients
|
||||
* Crete a clone of the NumberFormatter
|
||||
* @return {NumberFormatter} Returns a clone of the NumberFormatter
|
||||
*/
|
||||
function round(coefficients, count) {
|
||||
// TODO: simplify this method, write in a more compact way
|
||||
var rounded = coefficients.slice(0, count);
|
||||
if (coefficients[count] >= 5) {
|
||||
if (count === 0) {
|
||||
rounded.unshift(0);
|
||||
count++;
|
||||
}
|
||||
rounded[count - 1]++;
|
||||
NumberFormatter.prototype.clone = function () {
|
||||
var clone = new NumberFormatter('0');
|
||||
clone.sign = this.sign;
|
||||
clone.coefficients = this.coefficients.slice(0);
|
||||
clone.exponent = this.exponent;
|
||||
return clone;
|
||||
};
|
||||
|
||||
var i = count - 1;
|
||||
while (i > 0) {
|
||||
if (rounded[i] === 10) {
|
||||
rounded[i] = 0;
|
||||
/**
|
||||
* Round the number of digits of a number *
|
||||
* @param {number} precision A positive integer
|
||||
* @return {NumberFormatter} Returns a new NumberFormatter with the rounded
|
||||
* digits
|
||||
*/
|
||||
NumberFormatter.prototype.roundDigits = function (precision) {
|
||||
var rounded = this.clone();
|
||||
var c = rounded.coefficients;
|
||||
|
||||
// prepend zeros if needed
|
||||
while (precision <= 0) {
|
||||
c.unshift(0);
|
||||
rounded.exponent++;
|
||||
precision++;
|
||||
}
|
||||
|
||||
if (c.length > precision) {
|
||||
var removed = c.splice(precision);
|
||||
|
||||
if (removed[0] >= 5) {
|
||||
var i = precision - 1;
|
||||
c[i]++;
|
||||
while (c[i] === 10) {
|
||||
c.pop();
|
||||
if (i === 0) {
|
||||
rounded.unshift(0);
|
||||
c.unshift(0);
|
||||
rounded.exponent++;
|
||||
i++;
|
||||
}
|
||||
rounded[i - 1]++;
|
||||
i--;
|
||||
c[i]++;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
return rounded.concat(init(count - rounded.length, 0));
|
||||
}
|
||||
return rounded;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize an array with a certain length and initialize with values.
|
||||
* Create an array filled with zeros.
|
||||
* @param {number} length
|
||||
* @param {number} value
|
||||
* @return {Array}
|
||||
*/
|
||||
function init(length, value) {
|
||||
function zeros(length) {
|
||||
var arr = [];
|
||||
for (var i = 0; i < length; i++) {
|
||||
arr.push(value);
|
||||
arr.push(0);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
@ -28,6 +28,21 @@ describe('NumberFormatter', function() {
|
||||
assert.deepEqual(new NumberFormatter('2.3e-3'), {sign: '', coefficients: [2, 3], exponent: -3});
|
||||
assert.deepEqual(new NumberFormatter('23e-3'), {sign: '', coefficients: [2, 3], exponent: -2});
|
||||
assert.deepEqual(new NumberFormatter('-23e-3'), {sign: '-', coefficients: [2, 3], exponent: -2});
|
||||
assert.deepEqual(new NumberFormatter('99.99'), {sign: '', coefficients: [9,9,9,9], exponent: 1});
|
||||
});
|
||||
|
||||
it('should clone a NumberFormatter', function () {
|
||||
var a = new NumberFormatter(2.3);
|
||||
var clone = a.clone();
|
||||
assert.deepEqual(clone, a);
|
||||
assert.notStrictEqual(clone, a);
|
||||
});
|
||||
|
||||
it('should round a NumberFormatter', function () {
|
||||
assert.deepEqual(new NumberFormatter(123456).roundDigits(3), new NumberFormatter(123000));
|
||||
assert.deepEqual(new NumberFormatter(123456).roundDigits(4), new NumberFormatter(123500));
|
||||
assert.deepEqual(new NumberFormatter(0.00555).roundDigits(2), new NumberFormatter(0.0056));
|
||||
assert.deepEqual(new NumberFormatter(99.99).roundDigits(2), new NumberFormatter(100));
|
||||
});
|
||||
|
||||
it('should format a number with toFixed', function () {
|
||||
@ -58,6 +73,8 @@ describe('NumberFormatter', function() {
|
||||
|
||||
it('should format a number with toExponential', function () {
|
||||
assert.strictEqual(new NumberFormatter(0).toExponential(), '0e+0');
|
||||
assert.strictEqual(new NumberFormatter(1).toExponential(), '1e+0');
|
||||
assert.strictEqual(new NumberFormatter(1000).toExponential(), '1e+3');
|
||||
assert.strictEqual(new NumberFormatter(2300).toExponential(), '2.3e+3');
|
||||
assert.strictEqual(new NumberFormatter(3.568).toExponential(), '3.568e+0');
|
||||
assert.strictEqual(new NumberFormatter(0.00123).toExponential(), '1.23e-3');
|
||||
@ -67,6 +84,7 @@ describe('NumberFormatter', function() {
|
||||
assert.strictEqual(new NumberFormatter(0).toExponential(2), '0.0e+0');
|
||||
assert.strictEqual(new NumberFormatter(1234).toExponential(2), '1.2e+3');
|
||||
assert.strictEqual(new NumberFormatter(1234).toExponential(6), '1.23400e+3');
|
||||
assert.strictEqual(new NumberFormatter(9999).toExponential(2), '1.0e+4');
|
||||
});
|
||||
|
||||
it('should format a number with toPrecision', function () {
|
||||
@ -79,9 +97,14 @@ describe('NumberFormatter', function() {
|
||||
|
||||
assert.strictEqual(new NumberFormatter(2300).toPrecision(6), '2300.00');
|
||||
assert.strictEqual(new NumberFormatter(1234.5678).toPrecision(6), '1234.57');
|
||||
assert.strictEqual(new NumberFormatter(1234.5678).toPrecision(2), '1200');
|
||||
assert.strictEqual(new NumberFormatter(1234).toPrecision(2), '1200');
|
||||
assert.strictEqual(new NumberFormatter(0.004).toPrecision(3), '0.00400');
|
||||
assert.strictEqual(new NumberFormatter(0.00123456).toPrecision(5), '0.0012346');
|
||||
assert.strictEqual(new NumberFormatter(999).toPrecision(2), '1000');
|
||||
assert.strictEqual(new NumberFormatter(9990).toPrecision(2), '10000');
|
||||
assert.strictEqual(new NumberFormatter(99999).toPrecision(2), '100000');
|
||||
assert.strictEqual(new NumberFormatter(999e7).toPrecision(2), '1.0e+10');
|
||||
});
|
||||
|
||||
it('should should throw an error on invalid input', function () {
|
||||
|
||||
@ -128,6 +128,7 @@ describe('number', function() {
|
||||
assert.equal(number.format(123.456, options), '123');
|
||||
assert.equal(number.format(123.7, options), '124');
|
||||
assert.equal(number.format(-123.7, options), '-124');
|
||||
assert.equal(number.format(-66, options), '-66');
|
||||
assert.equal(number.format(0.123456, options), '0');
|
||||
|
||||
assert.equal(number.format(123456789, options), '123456789');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user