[英]What's the proper way to show money in an UI in Java?
On the backend I'm storing money values in a Money class which wraps a BigDecimal and sets rounding to be always Half Even with scale 8. All basic operations work fine and behave as expected. 在后端,我将Money值存储在Money类中,该类包装一个BigDecimal并将舍入值始终设置为小数位数为8的Half Even。所有基本操作都能正常工作,并且按预期运行。 But I need to show those values to the user with scale of 2, and that's bringing me rounding errors. 但是我需要以2的比例向用户显示这些值,这给我带来了舍入误差。
For example, I have these values in the backend: 例如,我在后端有这些值:
a = 109.11432 一个= 109.11432
b = 9015.57069 b = 9015.57069
c = 9124.68501 c = 9124.68501
Each one of them is formatted to the pt-BR locale: 其中每个都格式化为pt-BR语言环境:
NumberFormat nf = NumberFormat.getInstance();
nf.setCurrency(Currency.getInstance(new Locale("pt","BR")));
nf.setMinimumFractionDigits(2);
nf.setMaximumFractionDigits(2);
String n = nf.format(valor);
return n;
And then I have 然后我有
a = 109,11 a = 109,11
b = 9.015,57 b = 9.015,57
c = 9.124,69 c = 9.124,69
And that's ok, at first. 没关系,首先。 But c should be a + b. 但是c应该是a + b。 With the real values, this is guaranteed, but the rounding gives me a 0.01 error. 使用实际值可以保证,但是四舍五入给了我0.01的误差。
What's the proper way to handle this situation? 处理这种情况的正确方法是什么?
It seems to be doing exactly what you want it to. 它似乎完全按照您想要的去做。 The way you are storing it, you are storing far beyond 0.01. 存储方式远远超出了0.01。 If that is not your intention, then stop doing it :) 如果这不是您的意图,请停止这样做:)
If you want a + b to equal c with 2 decimal places, then you need to round before doing the addition. 如果希望a + b等于c并保留小数点后2位,则在进行加法之前需要四舍五入。 The solution to your issue depends on the requirements of your application. 解决问题的方法取决于应用程序的要求。 One common way of storing money is actually with an integer. 一种常见的存钱方式实际上是使用整数。 That way, you cannot store fractions and you could never have the issue you are currently describing. 这样,您将无法存储分数,也永远不会遇到当前正在描述的问题。
But it really depends on your requirements. 但这确实取决于您的要求。 Are you required to do money arithmetic based on 0.01, or on full accuracy and then round the end result? 您是否需要根据0.01或完全准确度进行货币算术,然后舍入最终结果? That's a business question, not a technical question. 这是一个业务问题,而不是技术问题。
Note that a NumberFormat
also can have a rounding mode . 请注意, NumberFormat
也可以具有舍入模式 。
But ultimately, no rounding method can fulfill a business requirement like "these values have to add up to this one" without being designed specifically for that case. 但是最终,如果没有专门针对这种情况进行设计,则没有一种舍入方法可以满足“这些值必须累加起来”这样的业务要求。 Round-half-even is designed to avoid a large-scale bias, not single last-decimal errors. 半双半周期旨在避免大规模偏差,而不是单个最后十进制误差。 So where do you originally get the data from? 那么,您最初是从哪里获得数据的呢? That's where you have to make sure that the rounding preserves the total. 那是您必须确保四舍五入保留总数的地方。
Is storing the data with 8 fractional digits really a requirement, since you display only 2? 由于只显示2位,是否真的需要存储8位小数的数据? I'd also question the assumption that "With the real values, this is guaranteed", since the same thing could happen there, when rounding to 8 digits after whatever calculation produced the values. 我还要质疑“具有真实值,这是可以保证的”的假设,因为在进行任何计算得出值后四舍五入到8位数字时,可能会发生同样的事情。
If I were writing a money class, I would make it consist of two integer portions - dollars and cents (or reais and centavos, or whatever). 如果我正在写一个货币类,我将使它由两个整数部分组成-美元和美分(或雷亚尔和美分,或其他)。 That way you never end up with fractional cents. 这样,您永远都不会得到小数美分。 You just have to handle rolling over 100 cents in the addition and subtraction operations. 您只需要在加减运算中处理超过100美分的滚动。
EDIT: 编辑:
The comment to my original response has a good point. 对我的原始答复的评论很有意义。 Another option would be to just store the number of cents, then divide by 100 when you need to display. 另一种选择是只存储美分,然后在需要显示时除以100。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.