From 94dc8ee8e8c4f92652e4bf0e659cb647849417ad Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Tue, 1 Dec 2015 11:05:34 +0000 Subject: [PATCH] refact(formatNumber): optimisations --- src/ng/filter/filters.js | 87 ++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/src/ng/filter/filters.js b/src/ng/filter/filters.js index 57537ad7428b..8a3bb7076b3d 100644 --- a/src/ng/filter/filters.js +++ b/src/ng/filter/filters.js @@ -1,5 +1,9 @@ 'use strict'; +var MAX_DIGITS = 22; +var DECIMAL_SEP = '.'; +var ZERO_CHAR = '0'; + /** * @ngdoc filter * @name currency @@ -137,10 +141,16 @@ function numberFilter($locale) { }; } -var MAX_DIGITS = 22; -var DECIMAL_SEP = '.'; -var ZERO_CHAR = '0'; - +/** + * parse a number (as a string) into three components that can be used + * for formatting the number + * @param {string} numStr The number to parse + * @return {object} An object describing this number, containing the following keys: + * - d : an array of digits containing leading zeros as necessary + * - i : the number of the digits in `d` that are to the left of the decimal point + * - e : the exponent for numbers that would need more than `MAX_DIGITS` digits in `d` + * + */ function parse(numStr) { var exponent = 0, digits, integerLen; var e, i, j, zeros; @@ -184,39 +194,40 @@ function parse(numStr) { integerLen = 1; } - return { digits: digits, exponent: exponent, integerLen: integerLen }; + return { d: digits, e: exponent, i: integerLen }; } +/** + * Round the parsed number to the specified number of decimal places + * This function changed the parsedNumber in-place + */ function roundNumber(parsedNumber, fractionSize, minFrac, maxFrac) { - var digit = 0; - var digits = parsedNumber.digits; - var fractionLen = digits.length - parsedNumber.integerLen; + var digits = parsedNumber.d; + var fractionLen = digits.length - parsedNumber.i; - // determine fractionSize if it is not specified - if (isUndefined(fractionSize)) { - fractionSize = Math.min(Math.max(minFrac, fractionLen), maxFrac); - } + // determine fractionSize if it is not specified; `+fractionSize` converts it to a number + fractionSize = (isUndefined(fractionSize)) ? Math.min(Math.max(minFrac, fractionLen), maxFrac) : +fractionSize; - // Cut off unwanted digits with rounding - for (; fractionLen > fractionSize && digits.length; fractionLen--) { - digit = digits.pop(); - // Round up if necessary - if (digit >= 5) digits[digits.length - 1]++; - } + // The indec of the digit to where rounding is to occur + var roundAt = fractionSize + parsedNumber.i; + var digit = digits[roundAt]; - if (!digits.length) { + if (roundAt > 0 ) { + digits.splice(roundAt); + } else { // We rounded to zero so reset the parsedNumber - parsedNumber.integerLen = 1; - // If the last removed digit was >= 5 then we need to round up - if (digit >= 5) digits.push(1); - // Pad out with the necessary zeros - while (digits.length <= fractionSize) digits.unshift(0); + parsedNumber.i = 1; + digits.length = roundAt = fractionSize+1; + for(var i=0; i= 5) digits[roundAt-1]++; + // Pad out with zeros to get the required fraction length - for (; fractionLen < fractionSize; fractionLen++) digits.push(0); + for (; fractionLen < fractionSize; fractionLen++) digits.push(0); + - // Do a final clear of any carrying, e.g. the last digit was rounded up to 10 + // Do any carrying, e.g. a digit was rounded up to 10 var carry = digits.reduceRight(function(carry, d, i, digits) { d = d + carry; digits[i] = d % 10; @@ -224,7 +235,7 @@ function roundNumber(parsedNumber, fractionSize, minFrac, maxFrac) { }, 0); if (carry) { digits.unshift(carry); - parsedNumber.integerLen++; + parsedNumber.i++; } } @@ -248,16 +259,11 @@ function roundNumber(parsedNumber, fractionSize, minFrac, maxFrac) { */ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) { - if (isObject(number)) return ''; - - var isNegative = number < 0; - number = Math.abs(number); - - var isInfinity = number === Infinity; - if (!isInfinity && !isFinite(number)) return ''; + if (!(isString(number) || isNumber(number)) || isNaN(number)) return ''; + var isInfinity = !isFinite(number); var isZero = false; - var numStr = number + '', + var numStr = Math.abs(number) + '', formattedText = '', parsedNumber; @@ -268,8 +274,9 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) { roundNumber(parsedNumber, fractionSize, pattern.minFrac, pattern.maxFrac); - var digits = parsedNumber.digits; - var integerLen = parsedNumber.integerLen; + var digits = parsedNumber.d; + var integerLen = parsedNumber.i; + var exponent = parsedNumber.e; var decimals = []; isZero = digits.reduce(function(isZero, d) { return isZero && !d; }, true); @@ -305,11 +312,11 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) { formattedText += decimalSep + decimals.join(''); } - if (parsedNumber.exponent) { - formattedText += 'e+' + parsedNumber.exponent; + if (exponent) { + formattedText += 'e+' + exponent; } } - if (isNegative && !isZero) { + if (number < 0 && !isZero) { return pattern.negPre + formattedText + pattern.negSuf; } else { return pattern.posPre + formattedText + pattern.posSuf;