views:

427

answers:

3

I write line of business applications. I'd like to build a front-end end using Javascript and am trying to figure out how to deal with, for a business user, are floating point errors (I understand from a computer science perspective they might not be considered errors). I've read plenty on this and seen all kinds of rounding hacks that work on examples given but seem prone to break down unexpectedly. Is there a definitive way to do decimal math in javascript?

A: 

the only definite solution seems to be writing your own arbitrary precision number type working on strings internally -- which will be complicated and horribly slow.

fforw
+1 for complicated, but slow is relative: for a front end on modern hardware it's probably in the acceptable range, though granted not as fast as a native float.
Joel Coehoorn
I agree with Joel. I wrote a decimal big integer class that, while much slower than native numbers, (especially multiplying/dividing huge numbers), would definitely be fast enough for reasonably-sized numbers.
Matthew Crumley
+3  A: 

According to Douglas Crockford, the only way around this problem is scale your values to integer. Make sure it really is an integer by using Math.round on the scaled value. (DC does not talk about the rounding part, but I discovered it was necessary. e.g. Math.round(1.1 *100)) Do calculation(s). When you are done with the math scale back to original precision. See JavaScript: The Good Parts "Floating Point" section.

Julien Chastang
If I scale values to integers (i.e., say, store everything in cents) won't I still run into errors if I divide those integers?
Convert all values to cents. (See above about Math.round.) Do as many calculations as you want. When you are ready to give the user answer convert back to $ by dividing by 100. That should work.
Julien Chastang
I don't think that completely addresses the issue, you can still end up with intermediate problems with more than one divide. I don't think it's much better than just doing everything normally and just doing a round at the end.
Nosredna
@Barry Glenn: At least those "errors" will only be worth 1 cent, and the precision will only make a difference in whether the cents are rounded up or down. And the rounding method should be half-even (banker's rounding).
Mk12
+1  A: 

One answer is to do the math in decimal instead of binary. Then you never have to worry about the decimal <=> binary conversion errors. You'd represent the numbers as binary digits in an array or a string and write the math routines yourself.

Here are some bignumber libraries you can look into if you don't want to go to that trouble:

http://jsfromhell.com/classes/bignumber

http://stz-ida.de/html/oss/js_bigdecimal.html.en

Nosredna