代表Java和Postgres中货币汇率的十进制数

问题描述 投票:0回答:1

我们考虑两种储蓄和计算货币以及货币汇率的选择。汇率选项: 1 - 使用整数。将每个数字乘以 10^7,这样 1.0 将变为 10,000,000。 在 Java 中它将是

long
,在 Postgres 中是
BIGINT
2 - 按原样保存数据。在java中我们使用BigDecimal,在postgres中我们使用BigDecimal
numeric(18,7)
这些选项可能会出现任何问题吗?舍入、溢出等

java postgresql precision
1个回答
0
投票

BigDecimal
各种复杂。例如,
.equals
不会执行您认为的操作:即使
a.equals(b)
false
代表
精确
相同的金额,
a
也可以返回 b

BigDecimal zero1 = BigDecimal.ZERO.setScale(2);
BigDecimal zero2 = BigDecimal.ZERO.setScale(3);
System.out.println(zero1.equals(zero2)); // false
System.out.println(zero1.compareTo(zero2)); // 0

除法也有点复杂;如果没有数学背景,就无法进行除法,除非小数部分除以一个仅由 2 和 5 组成的数字(如果分解为质因数)。 (所以,你不能除以 3、15 或 700) - 这是因为十进制不能表示(1 除以 3 等于 0.333333),而 BD 反映了该代表模型。

通常以货币为单位,任何类型、任何精度的舍入都不是您想要的。例如,如果工作是取消共同持有的账户,并且作为该工作的一部分,账户中的金额需要在其所有者之间平均分配,那么如果联合账户中有 1.04 欧元并且持有由 3 个人组成,正确的做法是使用随机数生成器选出不幸的失败者。该帐户获得 34 美分,其他两个帐户获得 35 美分。或者放入银行保留剩余部分的合约中,这样,每个人得到 34 美分,银行保留 2 美分(当然,如果余额为负 1.04 欧元,每个人损失 35 美分,银行获利 1 美分)。您无法在数字系统中表达这些内容,您需要在完成这项工作的代码中表达它(“取消联名账户”代码需要明确执行此操作)。

此外,一般来说,大多数金融交易无法处理亚原子。我无法将半美分转入银行,因此,如果您的存储系统可以代表半美分,那么您实际上只是将罐头踢到路边。

因此,请采用

long
方法作为一般原则。

但请注意,特别是对于外汇来说,BD 是不可避免的。您想要从数据库中读取 long,然后将其转换为 BigDecimal 并固定比例(因此,51,000,234 再次转换为 5.1000234),进行乘法,然后获取该结果并返回到

long
,当场决定如何处理任何一分钱的零头(四舍五入到最接近的通常是一个坏主意,通常您希望四舍五入以有利于系统 - 如果客户得到这个金额,则向下舍入,如果客户必须付款,则向上舍入因为如果你不这样做,有人就可以进行几百万次 api 调用,每隔几次调用就“赚取”1 美分,并欺骗系统,这很糟糕)。

所以:

  • 对于外汇数学,BigDecimal 是正确的。
  • 对于金融金额的存储,
    long
    是正确的(存储美分。1.04欧元存储为“104”。每种货币都有一个原子。美元和欧元有美分,英镑有便士,日元就是日元,比特币有聪,等等)。
  • 对于外汇汇率的存储,任何一种都是合理的选择。但我建议你使用
    long
© www.soinside.com 2019 - 2024. All rights reserved.