Reputation: 141
In php, we have number_format()
. Passing it a value such as:
number_format(3.00 * 0.175, 2);
returns 0.53, which is what I would expect.
However, in JavaScript using toFixed()
var num = 3.00 * 0.175;
num.toFixed(2);
returns 0.52.
Ok, so perhaps toFixed
is not what I want... Maybe something like this...
var num = 3.17 * 0.175;
var dec = 2;
Math.round( Math.round( num * Math.pow( 10, dec + 1 ) ) / Math.pow( 10, 1 ) ) / Math.pow(10,dec);
No, that doesn't work either. It will return 0.56.
How can I get a number_format
function in JavaScript that doesn't give an incorrect answer?
Actually I did find an implementation of number_format for js, http://phpjs.org/functions/number_format, but it suffers from the same problem.
What is going on here with JavaScript rounding up? What am I missing?
Upvotes: 11
Views: 11496
Reputation: 3927
JavaScript does badly with floating point numbers (as do many other languages).
When I run
3.000 * 0.175
In my browser, I get
0.5249999999999999
Which will not round up to 0.525 with Math.round
. To circumvent this, you kind of have to multiply both sides until you get them to be integers (relatively easy, knowing some tricks help though).
So to do this we can say something like this:
function money_multiply (a, b) {
var log_10 = function (c) { return Math.log(c) / Math.log(10); },
ten_e = function (d) { return Math.pow(10, d); },
pow_10 = -Math.floor(Math.min(log_10(a), log_10(b))) + 1;
return ((a * ten_e(pow_10)) * (b * ten_e(pow_10))) / ten_e(pow_10 * 2);
}
This may look kind of funky, but here's some pseudo-code:
get the lowest power of 10 of the arguments (with log(base 10))
add 1 to make positive powers of ten (covert to integers)
multiply
divide by conversion factor (to get original quantities)
Hope this is what you are looking for. Here's a sample run:
3.000 * 0.175
0.5249999999999999
money_multiply(3.000, 0.175);
0.525
Upvotes: 13
Reputation: 31
Why all the powers?? Why not just add slightly less than 1/2 a cent
and round
:
(3.00 * 0.175 + 0.0049).toFixed(2)
Never had any accountants complain about the output.
Upvotes: 3
Reputation: 211
I know this is old but this is how I usually solve a rounding problem. This can be put in a function easily but for now I just put in simple vars for right now. If this doesn't work you could use money_format() or number_format() as a start from php.js (more info below).
var n = (3.00 * 0.175);
n = Math.round(n * Math.pow(10, 3)) / Math.pow(10, 3);
Math.round(n*100)/100;
comes out to 0.53 (0.5249999999999999)
var n = (3.00 * 0.175);
n = Math.round(n * Math.pow(10, 3)) / Math.pow(10, 3);
Math.round(n*100)/100;
comes out to 0.56 (0.55475)
It also looks like the php.js repo is being kept up on GitHub https://github.com/kvz/phpjs so if there isn't a function that is not performing correctly an issue can be submitted.
Anyway figured this information may help someone looking later on.
Upvotes: 0
Reputation: 86688
Why didn't you just use Math.round( num * Math.pow( 10, dec ) ) / Math.pow( 10, dec) )
?
EDIT: I see, the problem is that 3 * 0.175 gives you 0.52499999999999991, leading you to want an additional rounding step. Maybe just adding a small amount would work:
Math.round( num * Math.pow( 10, dec ) + 0.000000001 ) / Math.pow( 10, dec) )
Upvotes: 0
Reputation: 9072
I think the problem you are encountering is with floating point math as opposed to the rounding itself.
Using the firebug console for testing, logging the result of 3.00 * 0.175
given 0.524999...
. So rounding this number down is actually correct.
I don't know if there is a good solution to your problem, but in my experience when working with currency: it is easier to work in the smallest unit (cents) and then convert for display.
Upvotes: 1
Reputation: 78242
The toFixed
function is working correctly. It truncates past the specified amount of fraction digits.
Upvotes: 3