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
不幸的是,到目前为止,所有的答案都忽略了一个事实,即并非所有货币都有100个子单位(例如,美分是美元(USD)的子单位)。像伊拉克第纳尔(IQD)这样的货币有1000个子单位:伊拉克第纳尔等于1000费尔。日元(JPY)没有子单位。所以“乘以100做整数运算”并不总是正确的答案。 此外,对于货币计算,您还需要跟踪货币。您不能将美元(USD)添加到印度卢比(INR)(没有先将一个转换为另一个)。 JavaScript的整数数据类型所能表示的最大数量也有限制。 在货币计算中,您还必须记住,货币具有有限的精度(通常为0-3个小数点),四舍五入需要以特定的方式进行(例如,“正常”四舍五入vs.银行家四舍五入)。要执行的四舍五入类型也可能因管辖区/货币而异。 How to handle money in javascript对相关点有很好的讨论。 在我的搜索中,我找到了dinero.js库。还没有在生产系统中使用它,所以不能给予一个明智的意见。
9条答案
按热度按时间kmb7vmvb1#
您可能应该将十进制值缩放100,并以整美分表示所有货币值。这是为了避免problems with floating-point logic and arithmetic。JavaScript中没有decimal数据类型-唯一的数字数据类型是浮点型。因此,通常建议将货币处理为
2550
美分,而不是25.50
美元。在JavaScript中考虑:
但是:
表达式
0.1 + 0.2 === 0.3
返回false
,但幸运的是,浮点数中的整数运算是精确的,因此可以通过scaling 1避免十进制表示错误。请注意,虽然真实的集是无限的,但只有有限个(确切地说是18,437,736,874,454,810,627)可以用JavaScript浮点格式精确表示。因此,其他数的表示将是实际数2的近似值。
1道格拉斯·克罗克福德:JavaScript:好的部分:附录A -可怕的部分(第105页)。
2大卫·弗拉纳根:JavaScript: The Definitive Guide, Fourth Edition: 3.1.3 Floating-Point Literals (page 31)。
zkure5ic2#
将每个值缩放100是解决方案。手工做可能是无用的,因为你可以找到为你做这件事的库。我推荐moneysafe,它提供了一个非常适合ES6应用程序的函数式API:
https://github.com/ericelliott/moneysafe
在Node.js和浏览器中都可以使用。
qvtsj1bj3#
没有所谓的“精确”的财务计算,因为只有两个小数位,但这是一个更普遍的问题。
在JavaScript中,可以将每个值缩放100,并在每次出现小数时使用
Math.round()
。您可以使用一个对象来存储数字,并在其原型
valueOf()
方法中包含舍入。像这样:这样,每次使用Money-object时,它都将被表示为四舍五入到两位小数。未舍入的值仍然可以通过
m.amount
访问。如果愿意,可以在
Money.prototype.valueOf()
中构建自己的舍入算法。neskvpey4#
不幸的是,到目前为止,所有的答案都忽略了一个事实,即并非所有货币都有100个子单位(例如,美分是美元(USD)的子单位)。像伊拉克第纳尔(IQD)这样的货币有1000个子单位:伊拉克第纳尔等于1000费尔。日元(JPY)没有子单位。所以“乘以100做整数运算”并不总是正确的答案。
此外,对于货币计算,您还需要跟踪货币。您不能将美元(USD)添加到印度卢比(INR)(没有先将一个转换为另一个)。
JavaScript的整数数据类型所能表示的最大数量也有限制。
在货币计算中,您还必须记住,货币具有有限的精度(通常为0-3个小数点),四舍五入需要以特定的方式进行(例如,“正常”四舍五入vs.银行家四舍五入)。要执行的四舍五入类型也可能因管辖区/货币而异。
How to handle money in javascript对相关点有很好的讨论。
在我的搜索中,我找到了dinero.js库。还没有在生产系统中使用它,所以不能给予一个明智的意见。
swvgeqrz5#
use decimaljs...它是一个非常好的库,解决了问题的一个苛刻的部分...
在你所有行动中使用它。
https://github.com/MikeMcl/decimal.js/
jv4diomz6#
您的问题源于浮点计算的不准确性。如果你只是使用舍入来解决这个问题,你会有更大的错误,当你乘和除。
解决方案如下,解释如下:
你需要思考这背后的数学来理解它。像1/3这样的真实的在数学中不能用十进制值来表示,因为它们是无穷的(例如- .3333333333333...)。十进制中的某些数字不能正确地用二进制表示。例如,0.1不能用有限的位数正确地以二进制表示。
更多详细描述请看这里:http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
看看解决方案实现:http://floating-point-gui.de/languages/javascript/
fumotvh37#
由于其编码的二进制性质,一些十进制数不能以完美的准确度表示。举个例子
如果你需要使用纯javascript,那么你需要考虑每个计算的解决方案。对于上面的代码,我们可以将小数转换为整数。
Avoiding Problems with Decimal Math in JavaScript
有一个专门的图书馆为财务计算与伟大的文件。Finance.js
dm7nw8vv8#
使用此代码进行货币计算和两位数的整数。
23c0lvtd9#
在这里,我们使用JavaScript和Node.js在金融市场中进行真实的货币交易。我们提出了一个自定义的Decimal类,它表示不可变的十进制数并提供计算逻辑。
如果你很好奇,你可以在这里看到https://github.com/Reiryoku-Technologies/Mida/blob/master/src/core/decimals/MidaDecimal.ts的定义。
该软件包适用于NPM上的任何人。