Precise Financial Calculation in JavaScript. What Are the Gotchas?

浪子不回头ぞ 提交于 2019-11-26 01:49:17

问题


In the interest of creating cross-platform code, I\'d like to develop a simple financial application in JavaScript. The calculations required involve compound interest and relatively long decimal numbers. I\'d like to know what mistakes to avoid when using JavaScript to do this type of math—if it is possible at all!


回答1:


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).




回答2:


Scaling every value by 100 is the solution. Doing it by hand is probably useless, since you can find libraries that do that for you. I recommend moneysafe, which offers a functional API well suited for ES6 applications:

const { in$, $ } = require('moneysafe');
console.log(in$($(10.5) + $(.3)); // 10.8

https://github.com/ericelliott/moneysafe

Works both in Node.js and the browser.




回答3:


There's no such thing as "precise" financial calculation because of just two decimal fraction digits but that's a more general problem.

In JavaScript, you can scale every value by 100 and use Math.round() everytime a fraction can occur.

You could use an object to store the numbers and include the rounding in its prototypes valueOf() method. Like this:

sys = require('sys');

var Money = function(amount) {
        this.amount = amount;
    }
Money.prototype.valueOf = function() {
    return Math.round(this.amount*100)/100;
}

var m = new Money(50.42355446);
var n = new Money(30.342141);

sys.puts(m.amount + n.amount); //80.76569546
sys.puts(m+n); //80.76

That way, everytime you use a Money-object, it will be represented as rounded to two decimals. The unrounded value is still accessible via m.amount.

You can build in your own rounding algorithm into Money.prototype.valueOf(), if you like.




回答4:


Your problem stems from inaccuracy in floating point calculations. If you're just using rounding to solve this you'll have greater error when you're multiplying and dividing.

The solution is below, an explanation follows:

You'll need to think about mathematics behind this to understand it. Real numbers like 1/3 cannot be represented in math with decimal values since they're endless (e.g. - .333333333333333 ...). Some numbers in decimal cannot be represented in binary correctly. For example, 0.1 cannot be represented in binary correctly with a limited number of digits.

For more detailed description look here: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

Take a look at the solution implementation: http://floating-point-gui.de/languages/javascript/




回答5:


use decimaljs ... It a very good library that solves a harsh part of the problem ...

just use it in all your operation.

https://github.com/MikeMcl/decimal.js/




回答6:


If you want to build a really precise application you should not trust JavaScript libraries. instead you can use Web-Assembly.



来源:https://stackoverflow.com/questions/2876536/precise-financial-calculation-in-javascript-what-are-the-gotchas

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!