Precise Financial Calculation in JavaScript. What Are the Gotchas?
You should probably scale your decimal values by 100, and represent all the monetary values in whole cents. This is to avoid problems with floating-point logic and arithmetic. There is no decimal data type in JavaScript - the only numeric data type is floating-point. Therefore it is generally recommended to handle money as 2550
cents instead of 25.50
dollars.
Consider that in JavaScript:
var result = 1.0 + 2.0; // (result === 3.0) returns true
But:
var result = 0.1 + 0.2; // (result === 0.3) returns false
The expression 0.1 + 0.2 === 0.3
returns false
, but fortunately integer arithmetic in floating-point is exact, so decimal representation errors can be avoided by scaling1.
Note that while the set of real numbers is infinite, only a finite number of them (18,437,736,874,454,810,627 to be exact) can be represented exactly by the JavaScript floating-point format. Therefore the representation of the other numbers will be an approximation of the actual number2.
1 Douglas Crockford: JavaScript: The Good Parts: Appendix A - Awful Parts (page 105).
2 David Flanagan: JavaScript: The Definitive Guide, Fourth Edition: 3.1.3 Floating-Point Literals (page 31).
How to deal with floating point number precision in JavaScript?
From the Floating-Point Guide:
What can I do to avoid this problem?
That depends on what kind of
calculations you’re doing.
- If you really need your results to add up exactly, especially when you
work with money: use a special decimal
datatype.- If you just don’t want to see all those extra decimal places: simply
format your result rounded to a fixed
number of decimal places when
displaying it.- If you have no decimal datatype available, an alternative is to work
with integers, e.g. do money
calculations entirely in cents. But
this is more work and has some
drawbacks.
Note that the first point only applies if you really need specific precise decimal behaviour. Most people don't need that, they're just irritated that their programs don't work correctly with numbers like 1/10 without realizing that they wouldn't even blink at the same error if it occurred with 1/3.
If the first point really applies to you, use BigDecimal for JavaScript, which is not elegant at all, but actually solves the problem rather than providing an imperfect workaround.
Correcting floating math broken by multiplying, is it ok?
You should round after multiplying:
var d = (Math.round(1000*a)-Math.round(1000*b))/1000;
Just multiplying may not solve the problem. When you assign
var a = 16924.83;
it might internally represent this as something like 16924.8300001
, so when you multiply by 1000
you get 16924830.001
. You need to round to get rid of that fraction.
Related Topics
Check If an Array Is Empty or Exists
How to Add an Object to an Array
How to Load Local Script Files as Fallback in Cases Where Cdn Are Blocked/Unavailable
Where to Write to Localstorage in a Redux App
Understanding Meteor Publish/Subscribe
Parse JSON String into a Particular Object Prototype in JavaScript
Ajax, Back Button and Dom Updates
Can Es6 Template Literals Be Substituted at Runtime (Or Reused)
Nodejs Callbacks Simple Example
What Is the Correct Term for Variable Shadowing in JavaScript
Activexobject in Firefox or Chrome (Not Ie!)
Inspect Extension's Chrome.Storage in Devtools
How to Get the Day of Week and the Month of the Year
How to Break a String Across More Than One Line of Code in JavaScript
Communication Between Sibling Components in Vue.Js 2.0