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.
Add comment
Home