Formatting a number to given precision (eg. currency)

There is no build-in functionality to print a number with eg. 2 places precision, like you need to print a currency ammount. In this script you learn how to add this functionality to the Math object and make it available all over your movie like a build in function. Define the function in the first frame of your movie. // extend the Math object with our new function Math.format = function( num, precision, splitCharacter){ if((precision = Math.abs(precision)) == 0) return Math.round(num); if(splitCharacter == null) splitCharacter = "."; return Math.round(num) + splitCharacter + Math.round(num * Math.pow( 10, precision)).toString().substr(-precision); } // How to use it trace(Math.format(12.345, 2)); trace(Math.format(12.34, 2)); trace(Math.format(12.3, 2)); trace(Math.format(12., 2)); trace(Math.format(12, 2)); trace(Math.format(0.345, 2)); trace(Math.format(.345, 2)); trace(Math.format(0.045, 2)); trace(Math.format(0.04, 5));
Sam Nseir Date: 23/07/2001

Hi Ralf, Does this Math.prototype thing really work for you? I\'ve tried everything and it just won\'t call it. However if is simply replace Math.prototype with Object.prototype then it works. So is it just me or is it the Math Object? Cheers mate, Sam
bokel Date: 23/07/2001

Hi Sam, thank you for pointing that out. You are right, we cannot prototype Math, instead of this we have to extend Math directly. I changed it above Thanks again, bokel
Tim Date: 22/05/2002
Ralf, your new format doesn't work, with .5 numbers: trace(Math.format(0.5, 2)); // 1.50 You could change the Math.round(num) by ((num<0) ? "-" + Math.floor(Math.abs(num)) : Math.floor(num)) but it is not very elegant. You can probably find something better. Tim.
John Date: 24/03/2003
This function will not work correctly with ANYTHING ABOVE .5 Just as someone else mentioned 0.50 gets set to 1.50 but 2.7 also doesn't work because it gets formatted to 3.70 That is because the base number is getting rounded, so change the final line of code (the return statement) to: return (Math.floor(num)+splitCharacter+Math.round(num*Math.pow(10, precision)).toString().substr(-precision)); ...and you've got yourself a nice function. (All I did was change the Math.round(num) to Math.floor(num) ) John
qjava Date: 10/11/2003
Math.format = function( num, precision, splitCharacter){ if((precision = Math.abs(precision)) == 0) return Math.round(num); if(splitCharacter == null) splitCharacter = "."; var result=Math.round(num * Math.pow( 10, precision)).toString().substr(-precision); var num=result.substring(0,result.length-2); var prec=result.substr(result.length-2,2); return num+splitCharacter+prec; }
Brightone Date: 28/02/2007
Hi to all, This function is not working with numbers under 0.1. Here is another possibility - instead of the line "return .... " you can write this: result = (Math.floor(num)).toString() + splitCharacter ; for(i=0;i<precision;i++){ num=(num-Math.floor(num))*10; result += (Math.floor(num)).toString(); } return result; I think this works good. Atanas
Critic Date: 19/02/2008
Dude, drop it. You can only fuck it up so many times before you need to start looking elsewhere.
KingIsulgard Date: 06/10/2008
Hi there, There is a little glitch in your function. When a number has .5+ it will be rounded up. You need to floor instead of round your number. Also, your function didn't work as a math object, just make a normal function of it. Just change it to this: // Extend the Math object with our new function function number_format( num, precision, splitCharacter){ if((precision = Math.abs(precision)) == 0) return Math.round(num); if(splitCharacter == null) splitCharacter = "."; return Math.floor(num) + splitCharacter + Math.round(num * Math.pow( 10, precision)).toString().substr(-precision); } This is the perfect function :)
RaffyPogi Date: 12/11/2008
NumberFormat = function(Num:Number,Precision:Number,splitChar:String,splitNum:String){ if(splitChar == null) splitChar = "."; if(splitNum == null) splitNum = ","; if(Math.floor(Num).toString().length>3){ newNumber = newSplit = finalNumber = ""; splitCtr = 0; for(x=0;x<=(Math.floor(Num).toString().length-1);x++){ splitCtr++; myNum = Math.floor(Num).toString().substr(((Math.floor(Num).toString().length-1)-x),1); if((splitCtr == 3) and x<(Math.floor(Num).toString().length-1)) { splitCtr = 0; newSplit = splitNum; } else newSplit = ""; newNumber+= myNum+newSplit; } for(x=0;x<=newNumber.length-1;x++){ myNum = newNumber.substr(((newNumber.length-1)-x),1); finalNumber+= myNum; } if((Precision = Math.abs(Precision)) == 0) return finalNumber + splitChar + Math.floor(Num); else return finalNumber + splitChar + Math.floor(Num * Math.pow( 10, Precision)).toString().substr(-Precision); } else if((Precision = Math.abs(Precision)) == 0) return Math.floor(Num); return Math.floor(Num) + splitChar + Math.floor(Num * Math.pow( 10, Precision)).toString().substr(-Precision); }; trace(NumberFormat(412313.21, 2,".",",")); // output -> 412,313.21 // added comma(s) to separate thousands/millions
davea0511 Date: 05/01/2009
All the above formulas are way too complex and many give wrong results. Here's my function, and it's been thoroughly tested and ALWAYS gives correct results: function numFormat(num,precision) { dec=Math.pow( 10, precision); return Math.round(num*dec)/dec; }; Piece of cake. If you also want comma separators at the 10^3, 10^6, 10^9, etc RaffiPogy's method is probably best (I thoroughly tested it and it works exceptionally well), but of course his result can not be further manipulated because of the commas. He also adds trailing zeros for significant digits ... which may be misleading.
Barry Brunning Date: 22/10/2009
This discussion convinced me the problem has its traps. I came here because of the formatting currency requirement. To get the number correctly formatted with thousands separators (and after discovering some difficulties with RaffiPogy's method), I came up with (using davea0511's numFormat above): public function numberFormat(num:Number,precision:Number, thou_sep:String=',', dec_sep:String='.'):String { // Number to the required precision var num_prec:Number = numFormat(num, precision); var str_prec:String = num_prec.toString(); var len_prec:Number = str_prec.length; // Whole part of number var num_whole:Number = Math.floor(num_prec); var str_whole:String = num_whole.toString(); var len_whole:Number = str_whole.length; // Insert the thousands separators var sna:String=""; for (var i:Number=3; i < len_whole; i+=3){ sna = thou_sep + str_whole.substr(-i, 3) + sna; } sna = str_whole.substr(-i,3 - i + len_whole) + sna; // Include decimal part of the number (includes fractional case of num) sna += str_prec.substr(len_whole); // Is there a decimal part required (for currency, say)? if (precision > 0) { if (len_whole == len_prec) sna += dec_sep; // Add the trailing zeroes required var len_dec:Number = len_prec - len_whole; if (len_dec == 0) len_dec++; // account for the decimal point for (var i:Number=len_dec; i <= precision; i++) sna += '0'; } return sna; } I wanted a leading currency symbol (multi-currency application) and negative values bracketed. The code is (where the call to getSymbol() returns the currency symbol for a given international currency code, getPlaces() returns the conventional number of places shown for that currency and pp allows for additional precision for currency rate conversions): public function currencyFormat(u:Number, code:String, pp:Number=0):String{ var symbol:String = getSymbol(code); if (symbol == '?') return ''; var prec:Number = getPlaces(code) + pp; var lft:String = (u >= 0?"":"("); var rgt:String = (u >= 0?"":")"); u = Math.abs(u); return lft + symbol + ' ' + numberFormat(u, prec) + ' ' + code + rgt; } Keen observers will have noted this is AS3.
dajackg Date: 13/05/2010
Folks: function formatNumber(num:Number, precision:uint):String { if (isNaN(n)) { return "NaN"; } return n.toFixed(precision); }
gabe Date: 08/07/2010
hi folks! great codes, but check RaffyPogi's method. If you give 0 for precision, the function return with a correct result, but paste the whole number (what i gave to the function) after the number i get. what could be the problem?
Matthew Waygood Date: 09/09/2010
dajackg suggested n.toFixed(precision), but I found it gave very bad results using 12 for n and precision 2 gave me 12.00000000001 So adjusting the code at the top to stop various error, such as -0.00, getting 0.1 instead of 0.01 and 0.5 I wrote the following:- Math.format = function( num, precision, splitCharacter){ // formats a number rounding the fraction OFF to the nearest precision e.g. 0.0001 with 2 precision gives 0.00, 0.005 gives 0.01, -0.001 gives 0.00 since you can't have -0.00 if((precision = Math.abs(precision)) == 0) return Math.round(num); if(splitCharacter == null) splitCharacter = "."; whole=Math.floor(Math.abs(num)); fraction=Math.round(Math.abs(num)*Math.pow( 10, precision)); // change to floor/ceil if required to round up/down fraction_str=fraction.toString(); while(fraction_str.length<precision) fraction_str='0'+fraction_str; // stops 0.01 x100 = 1 not 01 decimal=fraction_str.substr(-precision); sign=''; number=whole+(fraction/Math.pow( 10, precision)); if( (num<0) && (number>0) ) sign='-'; // stops -0.00 return sign + whole + splitCharacter + decimal; }
bob Date: 25/08/2011
function roundFloat(theNumber:* = 0, decimalPlaces:int = 0){ var mynum:Number = Number(theNumber); var ret:*; var dec:Number if(decimalPlaces < 1){ ret = Math.round(mynum); } else { dec = Math.pow(10, decimalPlaces); ret = int((mynum)*dec) / dec; ret = ret.toFixed(decimalPlaces); } return (ret); } var num:*; var test:*; var Atest:Array = [ 34, 56.8, .5, 0.2, "42", ".6", "10.1", 000.5, "000.5" ]; for(var i:uint=0; i<Atest.length; i++){ trace( "-----------------------------------"); num = Atest[i]; trace( "source:tt" + num + "tt : t" + typeof num ); test = roundFloat(num); trace( "no dec:tt" + test + "tt : t" + typeof test ); test = roundFloat(num, 2); trace( "rnd 2:tt" + test + "t : t" + typeof test ); }
Add comment
Home