[英]org.javamoney.moneta.RoundedMoney - some operations result in a rounded value some are not
If i use org.javamoney.moneta
and run the following program, i got some contrary results for some operations on org.javamoney.moneta.RoundedMoney
. 如果我使用
org.javamoney.moneta
并运行以下程序,则对org.javamoney.moneta.RoundedMoney
进行的某些操作会得到相反的结果。 Sometimes the resulted value is rounded some times it is not. 有时,结果值会四舍五入而不是四舍五入。
Am I using the class wrong or is that a bug? 我使用的课程是否错误或是一个错误?
import java.math.BigDecimal;
import javax.money.CurrencyUnit;
import javax.money.Monetary;
import org.javamoney.moneta.RoundedMoney;
public final class RoundedMoneyRounding
{
private RoundedMoneyRounding()
{
}
public static void main(final String... args)
{
final CurrencyUnit usd = Monetary.getCurrency("USD");
final RoundedMoney halfcent = RoundedMoney.of(new BigDecimal("0.005"), usd);
final RoundedMoney zero = RoundedMoney.of(BigDecimal.ZERO, usd);
System.out.append("A1. 0.005 + 0 = ").println(//
halfcent.add(zero) //
.getNumber().numberValue(BigDecimal.class).toPlainString());
System.out.append("A2. 0 + 0.005 = ").println(//
zero.add(halfcent) //
.getNumber().numberValue(BigDecimal.class).toPlainString());
System.out.println("----");
System.out.append("B1: -0.005 = ").println(//
halfcent.negate() //
.getNumber().numberValue(BigDecimal.class).toPlainString());
System.out.append("B2: 0.005 * -1 = ").println(//
halfcent.multiply(new BigDecimal("-1")) //
.getNumber().numberValue(BigDecimal.class).toPlainString());
System.out.println("----");
System.out.append("C1: 0.005 * 1 = ").println(//
halfcent.multiply(BigDecimal.ONE) //
.getNumber().numberValue(BigDecimal.class).toPlainString());
System.out.append("C2: 0.005 * 1.1 = ").println(//
halfcent.multiply(new BigDecimal("1.1")) //
.getNumber().numberValue(BigDecimal.class).toPlainString());
System.out.println("----");
System.out.append("D1: 0.005 * 2 = ").println(//
halfcent.multiply(new BigDecimal("2")) //
.getNumber().numberValue(BigDecimal.class).toPlainString());
System.out.append("D2: (0.005 * 2) / 2 = ").println(//
halfcent.multiply(new BigDecimal("2")).divide(new BigDecimal("2")) //
.getNumber().numberValue(BigDecimal.class).toPlainString());
}
}
Output: 输出:
A1. 0.005 + 0 = 0.005
A2. 0 + 0.005 = 0
----
B1: -0.005 = -0.005
B2: 0.005 * -1 = 0
----
C1: 0.005 * 1 = 0.005
C2: 0.005 * 1.1 = 0.01
----
D1: 0.005 * 2 = 0.01
D2: (0.005 * 2) / 2 = 0
The used maven
dependency is: 使用的
maven
依赖项是:
<dependency>
<groupId>org.javamoney</groupId>
<artifactId>moneta</artifactId>
<version>1.3</version>
<type>pom</type>
</dependency>
(Just found the corresponding issue on GitHub 😛) (刚刚在GitHub found 上找到了相应的问题 )
This is probably due to the implementation-specific assumption that RoundedMoney
instances will always contain rounded values, but, apparently, this is not enforced in the factory methods and constructors of that class. 这可能是由于特定于实现的假设所决定的,即
RoundedMoney
实例将始终包含舍入的值,但是,显然,这不是在该类的工厂方法和构造函数中强制执行的。 You can happily construct it with unrounded values. 您可以使用未取整的值来愉快地构造它。
When doing math with that class, some arithmetic optimizations apply: Examples A1 and C1 use the identity elements of addition and multiplication on the right hand side, hence they are effectively no-ops, and this
will be returned, representing the initial unrounded value. 当与类做数学,一些算术优化应用:实施例A1和C1使用加法和乘法在右手侧的身份元素,因此,它们是有效的空操作,并且
this
将被返回,表示初始未舍入值。 Examples A2 and C2 could theoretically return the right hand side operator directly, but that optimization is missing, so RoundedMoney
actually starts to calculate (and round) the result. 示例A2和C2在理论上可以直接返回右侧运算符,但是缺少优化,因此
RoundedMoney
实际上开始计算(并四舍五入)结果。
Example B1 just flips the sign of the number value. 示例B1只是翻转数字值的符号。 Here, the same assumptions apply: If
x
is a correctly rounded value, then -x
is also correctly rounded [1] . 在这里,适用相同的假设:如果
x
是正确舍入的值,则-x
也正确舍入[1] 。 So, RoundedMoney
won't bother to apply the rounding to the new numeric value. 因此,
RoundedMoney
不会费心将舍入应用于新的数值。 In contrast, example B2 isn't optimized, but calculated and rounded. 相反,示例B2并未进行优化,而是经过了计算和四舍五入。
So, I think the actual culprits are the factory methods , which won't apply the rounding to user-supplied values: 因此,我认为真正的罪魁祸首是工厂方法 ,该方法不会将舍入应用于用户提供的值:
public static RoundedMoney of(BigDecimal number, CurrencyUnit currency) {
return new RoundedMoney(number, currency, Monetary.getDefaultRounding());
}
public static RoundedMoney of(BigDecimal number, CurrencyUnit currency, MonetaryOperator rounding) {
return new RoundedMoney(number, currency, rounding);
}
should most probably be 应该是
public static RoundedMoney of(BigDecimal number, CurrencyUnit currency) {
return of(number, currency, Monetary.getDefaultRounding());
}
public static RoundedMoney of(BigDecimal number, CurrencyUnit currency, MonetaryOperator rounding) {
return new RoundedMoney(number, currency, rounding).with(rounding);
}
I'd argue this is a bug, but since there's not much (no?) documentation about how that class is supposed to be used – or not used, for that matter – it might even be intended behavior? 我认为这是一个错误,但是由于没有太多(否?)有关该类应如何使用(或不使用)的文档,它甚至可能是预期的行为?
[1]: This is interesting. [1]:这很有趣。 Is there any rounding which won't satisfy that assumption?
是否有任何舍入不能满足该假设? In fact, since
RoundedMoney
leverages a MoentaryOperator
to apply the rounding, one could easily pass in some arbitrary "non-symmetric" operator. 实际上,由于
RoundedMoney
利用MoentaryOperator
进行了四舍五入,因此可以轻松传入一些任意的“非对称”运算符。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.