diff --git a/accounting.js b/accounting.js index fd181fd..8b3afd0 100644 --- a/accounting.js +++ b/accounting.js @@ -31,13 +31,15 @@ decimal : ".", // decimal point separator thousand : ",", // thousands separator precision : 2, // decimal places - grouping : 3 // digit grouping (not implemented yet) + grouping : 3, // digit grouping (not implemented yet) + round : 0 }, number: { precision : 0, // default precision on numbers is 0 grouping : 3, // digit grouping (not implemented yet) thousand : ",", - decimal : "." + decimal : ".", + round : 0 } }; @@ -169,7 +171,7 @@ * Alias: `accounting.parse(string)` * * Decimal must be included in the regular expression to match floats (defaults to - * accounting.settings.number.decimal), so if the number uses a non-standard decimal + * accounting.settings.number.decimal), so if the number uses a non-standard decimal * separator, provide it as the second argument. * * Also matches bracketed negatives (eg. "$ (1.99)" => -1.99) @@ -208,16 +210,28 @@ /** - * Implementation of toFixed() that treats floats more like decimals + * Implementation of xed() that treats floats more like decimals * - * Fixes binary rounding issues (eg. (0.615).toFixed(2) === "0.61") that present + * Fixes binary rounding issues (eg. (0.615).xed(2) === "0.61") that present * problems for accounting- and finance-related software. */ - var toFixed = lib.toFixed = function(value, precision) { + var toFixed = lib.toFixed = function(value, precision, round) { precision = checkPrecision(precision, lib.settings.number.precision); var exponentialForm = Number(lib.unformat(value) + 'e' + precision); - var rounded = Math.round(exponentialForm); + var roundMethod + + if (round > 0) { + roundMethod = Math.ceil + } + else if (round < 0) { + roundMethod = Math.floor + } + else { + roundMethod = Math.round + } + + var rounded = roundMethod(exponentialForm); var finalResult = Number(rounded + 'e-' + precision).toFixed(precision); return finalResult; }; @@ -230,11 +244,11 @@ * Localise by overriding the precision and thousand / decimal separators * 2nd parameter `precision` can be an object matching `settings.number` */ - var formatNumber = lib.formatNumber = lib.format = function(number, precision, thousand, decimal) { + var formatNumber = lib.formatNumber = lib.format = function(number, precision, thousand, decimal, round) { // Resursively format arrays: if (isArray(number)) { return map(number, function(val) { - return formatNumber(val, precision, thousand, decimal); + return formatNumber(val, precision, thousand, decimal,round); }); } @@ -246,7 +260,8 @@ (isObject(precision) ? precision : { precision : precision, thousand : thousand, - decimal : decimal + decimal : decimal, + round : round }), lib.settings.number ), @@ -256,11 +271,11 @@ // Do some calc: negative = number < 0 ? "-" : "", - base = parseInt(toFixed(Math.abs(number || 0), usePrecision), 10) + "", + base = parseInt(toFixed(Math.abs(number || 0), usePrecision, opts.round), 10) + "", mod = base.length > 3 ? base.length % 3 : 0; // Format the number: - return negative + (mod ? base.substr(0, mod) + opts.thousand : "") + base.substr(mod).replace(/(\d{3})(?=\d)/g, "$1" + opts.thousand) + (usePrecision ? opts.decimal + toFixed(Math.abs(number), usePrecision).split('.')[1] : ""); + return negative + (mod ? base.substr(0, mod) + opts.thousand : "") + base.substr(mod).replace(/(\d{3})(?=\d)/g, "$1" + opts.thousand) + (usePrecision ? opts.decimal + toFixed(Math.abs(number), usePrecision, opts.round).split('.')[1] : ""); }; @@ -275,11 +290,11 @@ * * To do: tidy up the parameters */ - var formatMoney = lib.formatMoney = function(number, symbol, precision, thousand, decimal, format) { + var formatMoney = lib.formatMoney = function(number, symbol, precision, thousand, decimal, format, round) { // Resursively format arrays: if (isArray(number)) { return map(number, function(val){ - return formatMoney(val, symbol, precision, thousand, decimal, format); + return formatMoney(val, symbol, precision, thousand, decimal, format, round); }); } @@ -293,7 +308,8 @@ precision : precision, thousand : thousand, decimal : decimal, - format : format + format : format, + round : round }), lib.settings.currency ), @@ -305,7 +321,7 @@ useFormat = number > 0 ? formats.pos : number < 0 ? formats.neg : formats.zero; // Return with currency symbol added: - return useFormat.replace('%s', opts.symbol).replace('%v', formatNumber(Math.abs(number), checkPrecision(opts.precision), opts.thousand, opts.decimal)); + return useFormat.replace('%s', opts.symbol).replace('%v', formatNumber(Math.abs(number), checkPrecision(opts.precision), opts.thousand, opts.decimal, opts.round)); }; @@ -321,7 +337,7 @@ * NB: `white-space:pre` CSS rule is required on the list container to prevent * browsers from collapsing the whitespace in the output strings. */ - lib.formatColumn = function(list, symbol, precision, thousand, decimal, format) { + lib.formatColumn = function(list, symbol, precision, thousand, decimal, format, round) { if (!list || !isArray(list)) return []; // Build options object from second param (if object) or all params, extending defaults: @@ -331,7 +347,8 @@ precision : precision, thousand : thousand, decimal : decimal, - format : format + format : format, + round: round }), lib.settings.currency ), @@ -358,7 +375,7 @@ var useFormat = val > 0 ? formats.pos : val < 0 ? formats.neg : formats.zero, // Format this value, push into formatted list and save the length: - fVal = useFormat.replace('%s', opts.symbol).replace('%v', formatNumber(Math.abs(val), checkPrecision(opts.precision), opts.thousand, opts.decimal)); + fVal = useFormat.replace('%s', opts.symbol).replace('%v', formatNumber(Math.abs(val), checkPrecision(opts.precision), opts.thousand, opts.decimal, opts.round)); if (fVal.length > maxLength) maxLength = fVal.length; return fVal; diff --git a/accounting.min.js b/accounting.min.js index 8e09b86..053c20b 100644 --- a/accounting.min.js +++ b/accounting.min.js @@ -1,4 +1,4 @@ /*! * accounting.js v0.4.2, copyright 2014 Open Exchange Rates, MIT license, http://openexchangerates.github.io/accounting.js */ -(function(p,z){function q(a){return!!(""===a||a&&a.charCodeAt&&a.substr)}function m(a){return u?u(a):"[object Array]"===v.call(a)}function r(a){return"[object Object]"===v.call(a)}function s(a,b){var d,a=a||{},b=b||{};for(d in b)b.hasOwnProperty(d)&&null==a[d]&&(a[d]=b[d]);return a}function j(a,b,d){var c=[],e,h;if(!a)return c;if(w&&a.map===w)return a.map(b,d);for(e=0,h=a.length;ea?"-":"",g=parseInt(y(Math.abs(a||0),h),10)+"",l=3a?g.neg:g.zero).replace("%s",f.symbol).replace("%v",t(Math.abs(a),n(f.precision),f.thousand,f.decimal))};c.formatColumn=function(a,b,d,i,e,h){if(!a)return[];var f=s(r(b)?b:{symbol:b,precision:d,thousand:i,decimal:e,format:h},c.settings.currency),g=x(f.format),l=g.pos.indexOf("%s")a?g.neg:g.zero).replace("%s",f.symbol).replace("%v",t(Math.abs(a),n(f.precision),f.thousand,f.decimal));if(a.length>k)k=a.length;return a});return j(a,function(a){return q(a)&&a.lengtht;t++)u[t]=r.call(e,n[t],t,n);return u}function i(n,r){return n=Math.round(Math.abs(n)),isNaN(n)?r:n}function c(n){var r=s.settings.currency.format;return"function"==typeof n&&(n=n()),e(n)&&n.match("%v")?{pos:n,neg:n.replace("-","").replace("%v","-%v"),zero:n}:n&&n.pos&&n.pos.match("%v")?n:e(r)?s.settings.currency.format={pos:r,neg:r.replace("%v","-%v"),zero:r}:r}var s={};s.version="0.4.2",s.settings={currency:{symbol:"$",format:"%s%v",decimal:".",thousand:",",precision:2,grouping:3,round:0},number:{precision:0,grouping:3,thousand:",",decimal:".",round:0}};var f=Array.prototype.map,l=Array.isArray,p=Object.prototype.toString,m=s.unformat=s.parse=function(n,r){if(t(n))return a(n,function(n){return m(n,r)});if(n=n||0,"number"==typeof n)return n;r=r||s.settings.number.decimal;var e=new RegExp("[^0-9-"+r+"]",["g"]),o=parseFloat((""+n).replace(/\((?=\d+)(.*)\)/,"-$1").replace(e,"").replace(r,"."));return isNaN(o)?0:o},d=s.toFixed=function(n,r,e){r=i(r,s.settings.number.precision);var t,o=Number(s.unformat(n)+"e"+r);t=e>0?Math.ceil:0>e?Math.floor:Math.round;var u=t(o),a=Number(u+"e-"+r).toFixed(r);return a},g=s.formatNumber=s.format=function(n,r,e,c,f){if(t(n))return a(n,function(n){return g(n,r,e,c,f)});n=m(n);var l=u(o(r)?r:{precision:r,thousand:e,decimal:c,round:f},s.settings.number),p=i(l.precision),h=0>n?"-":"",b=parseInt(d(Math.abs(n||0),p,l.round),10)+"",y=b.length>3?b.length%3:0;return h+(y?b.substr(0,y)+l.thousand:"")+b.substr(y).replace(/(\d{3})(?=\d)/g,"$1"+l.thousand)+(p?l.decimal+d(Math.abs(n),p,l.round).split(".")[1]:"")},h=s.formatMoney=function(n,r,e,f,l,p,d){if(t(n))return a(n,function(n){return h(n,r,e,f,l,p,d)});n=m(n);var b=u(o(r)?r:{symbol:r,precision:e,thousand:f,decimal:l,format:p,round:d},s.settings.currency),y=c(b.format),v=n>0?y.pos:0>n?y.neg:y.zero;return v.replace("%s",b.symbol).replace("%v",g(Math.abs(n),i(b.precision),b.thousand,b.decimal,b.round))};s.formatColumn=function(n,r,f,l,p,d,h){if(!n||!t(n))return[];var b=u(o(r)?r:{symbol:r,precision:f,thousand:l,decimal:p,format:d,round:h},s.settings.currency),y=c(b.format),v=y.pos.indexOf("%s")0?y.pos:0>n?y.neg:y.zero,o=e.replace("%s",b.symbol).replace("%v",g(Math.abs(n),i(b.precision),b.thousand,b.decimal,b.round));return o.length>x&&(x=o.length),o});return a(M,function(n,r){return e(n)&&n.length