views:

724

answers:

4

in JavaScript, the typical way to round a number to N decimal places is something like:

function round_number(num, dec) {
    return Math.round(num * Math.pow(10, dec)) / Math.pow(10, dec);
}

However this approach will round to a maximum of N decimal places while I want to always round to N decimal places. For example "2.0" would be rounded to "2".

Any ideas?

+5  A: 

That's not a rounding ploblem, that is a display problem. A number doesn't contain information about significant digits; the value 2 is the same as 2.0000000000000. It's when you turn the rounded value into a string that you have make it display a certain number of digits.

You could just add zeroes after the number, something like:

var s = number.toString();
if (s.indexOf('.') == -1) s += '.';
while (s.length < s.indexOf('.') + 4) s += '0';

(Note that this assumes that the regional settings of the client uses period as decimal separator, the code needs some more work to function for other settings.)

Guffa
What's wrong with `.toFixed(dec)`?
Mark
+1  A: 

Here's a link to a Javascript sprintf,

http://www.webtoolkit.info/javascript-sprintf.html

A call to sprintf() is one rounding methodology in perl, but javascript doesn't have that function natively.

http://perldoc.perl.org/functions/sprintf.html

Does that help?

Paul
+2  A: 

Hopefully working code (didn't do much testing):

function toFixed(value, precision) {
    var precision = precision || 0,
        neg = value < 0,
        power = Math.pow(10, precision),
        value = Math.round(value * power),
        integral = String((neg ? Math.ceil : Math.floor)(value / power)),
        fraction = String((neg ? -value : value) % power),
        padding = new Array(Math.max(precision - fraction.length, 0) + 1).join('0');

    return precision ? integral + '.' +  padding + fraction : integral;
}
Christoph
Your code has a bug. I tried toFixed(2.01, 4) and got a result of "2.100". If I ever find a way to fix it, I will post it as an answer to this question.
mikez302
@mikez302: the padding computation was off by one; should work now, but feel free to bug me again if it's still broken...
Christoph
+1  A: 

I found a way. This is Christoph's code with a fix:

function toFixed(value, precision) {
var precision = precision || 0,
    neg = value < 0,
    power = Math.pow(10, precision),
    value = Math.round(value * power),
    integral = String((neg ? Math.ceil : Math.floor)(value / power)),
    fraction = String((neg ? -value : value) % power),
    padding = new Array(Math.max(precision - fraction.length, 0) + 1).join('0');

return precision ? integral + '.' +  padding + fraction : integral;

}

Read the details of repeating a character using an array constructor here if you are curious as to why I added the "+ 1".

mikez302