【问题标题】:What's the proper way to show money in an UI in Java?在 Java 的 UI 中显示钱的正确方法是什么?
【发布时间】:2011-03-25 11:43:18
【问题描述】:

在后端,我将货币值存储在 Money 类中,该类包装 BigDecimal 并将舍入设置为始终为 8 级的 Half Even。所有基本操作都可以正常工作并按预期运行。但我需要以 2 的比例向用户显示这些值,这会导致舍入错误。

例如,我在后端有这些值:

a = 109.11432
b = 9015.57069
c = 9124.68501

它们中的每一个都被格式化为 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;

然后我有

a = 109,11
b = 9.015,57
c = 9.124,69

一开始没关系。但是 c 应该是 a + b。使用实际值,这是可以保证的,但四舍五入会给我 0.01 的误差。

处理这种情况的正确方法是什么?

【问题讨论】:

  • 我认为你不应该存储 109.11432,取整它,我的意思是当你去商店时,收银员会要求你支付 5,90132 美元吗? ;]
  • 在我得到这些结果之前已经完成了很多操作,很多乘法、加法、除法,这导致了我展示的这些值。如果我对每个操作进行四舍五入,最终我的错误会比 1 美分大得多。我以前做过。

标签: java formatting currency


【解决方案1】:

它似乎在做你想做的事。你存储它的方式,你存储的远远超过 0.01。如果这不是你的意图,那就停止这样做:)

如果您希望 a + b 等于 c 并保留 2 个小数位,那么您需要在进行加法之前进行四舍五入。您的问题的解决方案取决于您的应用程序的要求。一种常见的存钱方式实际上是使用整数。这样一来,您就无法存储分数,也永远不会遇到您当前描述的问题。

但这真的取决于您的要求。您是否需要根据 0.01 或完全准确度进行货币算术,然后对最终结果进行四舍五入?这是一个商业问题,而不是技术问题。

【讨论】:

  • 确定你会遇到同样的问题 - 你仍然需要在某个时候四舍五入。
  • 不,您不可能遇到完全相同的问题,因为他正在添加两个存储的货币值。使用整数时添加两个存储的货币值永远不会有 1+7 = 9,这正是他遇到的问题。使用整数会强制您在存储值之前做出适当的舍入和算术决定。
  • 我需要在完全准确的基础上进行货币算术,然后对最终结果进行四舍五入。这就是问题所在。
  • 最终结果是什么?这里的问题是现在你说 a+b=c 两位小数——为什么?如果这仅用于显示目的,那么在存储 .125 时显示 .12 是错误的——这是一个谎言。如果您要存储小数便士,请将其显示出来,否则您会得到这些奇怪的东西。如果 c 是最终答案,请检测 0.4 + .4 = .8 表示 0 + 0 = 1 的情况,而不是向上和向下取整。无论如何......再一次,你问的是商业问题,而不是技术问题。这些计算的规则/约束是什么。一旦你定义了这些,你就可以实现它。
  • 我猜你是对的,taotree。我需要两位小数只是为了显示目的,所以它确实是一个谎言。我们一直在围绕这个问题讨论我们的要求,并希望能够根据系统的业务需求制定解决方案。
【解决方案2】:

注意NumberFormat可以有rounding mode

但归根结底,没有专门针对这种情况设计的舍入方法可以满足诸如“这些值必须相加到这个值”之类的业务需求。舍入半偶数旨在避免大规模偏差,而不是单个最后一个小数错误。那么你最初是从哪里获得数据的呢?这就是您必须确保四舍五入保留总数的地方。

由于您只显示 2 个小数位,是否真的需要存储 8 个小数位的数据?我还质疑“使用真实值,这是有保证的”的假设,因为在任何计算产生值之后四舍五入到 8 位时,同样的事情也可能发生在那里。

【讨论】:

    【解决方案3】:

    如果我正在编写一个货币类,我会让它由两个整数部分组成 - 美元和美分(或雷亚尔和分,或其他)。这样你就永远不会得到分数。您只需要在加法和减法运算中处理超过 100 美分的滚动即可。

    编辑:

    对我最初回复的评论有一个很好的观点。另一种选择是只存储美分数,然后在需要显示时除以 100。

    【讨论】:

    • 我认为这不是处理这个问题的好方法,实现所有操作会出现太多问题,因此它们可以正常工作。我认为这太容易出错了。
    猜你喜欢
    • 1970-01-01
    • 2011-08-21
    • 1970-01-01
    • 1970-01-01
    • 2020-08-18
    • 2016-12-25
    • 2015-02-22
    • 2010-11-21
    • 2015-05-06
    相关资源
    最近更新 更多