ArithmeticException 在 BigDecimal.divide 期间抛出

我认为java.math.BigDecimal应该是对使用十进制数执行无限精度算术的需求的答案™。

请考虑以下代码段:

import java.math.BigDecimal;
//...

final BigDecimal one = BigDecimal.ONE;
final BigDecimal three = BigDecimal.valueOf(3);
final BigDecimal third = one.divide(three);

assert third.multiply(three).equals(one); // this should pass, right?

我希望通过,但实际上执行甚至没有到达那里:导致被抛出!assertone.divide(three)ArithmeticException

Exception in thread "main" java.lang.ArithmeticException:
Non-terminating decimal expansion; no exact representable decimal result.
    at java.math.BigDecimal.divide

事实证明,此行为在 API 中明确记录:

在 的情况下,精确商可以有一个无限长的十进制展开;例如,1 除以 3。如果商具有非终止十进制展开,并且指定运算以返回确切的结果,则抛出 。否则,将返回除法的确切结果,就像其他操作一样。divideArithmeticException

进一步浏览API,发现实际上存在各种重载,执行不精确的划分,即:divide

final BigDecimal third = one.divide(three, 33, RoundingMode.DOWN);
System.out.println(three.multiply(third));
// prints "0.999999999999999999999999999999999"

当然,现在显而易见的问题是“有什么意义???”。当我们需要精确的算术时,我认为这是解决方案,例如用于财务计算。如果我们甚至不能完全做到,那么这有多大用处?它是否真的用于一般目的,或者它仅在非常小众的应用程序中有用,幸运的是,您根本不需要这样做?BigDecimaldividedivide

如果这不是正确的答案,那么我们可以在财务计算中使用什么来精确划分?(我的意思是,我没有金融专业,但他们仍然使用部门,对吧???)。


答案 1

如果这不是正确的答案,那么我们可以在财务计算中使用什么来精确划分?(我的意思是,我没有金融专业,但他们仍然使用部门,对吧???)。

然后我在小学1,他们告诉我,当你除以1乘以3时,你得到0.33333...即重复出现的小数。以十进制形式表示的数字的除法是不精确的。事实上,对于任何固定基数,都会有分数(将一个整数除以另一个整数的结果),这些分数不能完全表示为该基数中的有限精度浮点数。(该号码将具有重复部分...)

当您进行涉及除法的财务计算时,您必须考虑如何处理重复分数。您可以将其向上或向下舍入,或舍入到最接近的整数,或者其他什么,但基本上您不能忘记这个问题。

BigDecimal javadoc 是这样说的:

BigDecimal 类使用户能够完全控制舍入行为。如果未指定舍入模式,并且无法表示确切的结果,则引发异常;否则,可以通过向操作提供适当的 MathContext 对象,以所选的精度和舍入模式执行计算。

换句话说,您有责任告诉BigDecimal如何处理舍入。

编辑 - 回应OP的这些后续行动。

BigDecimal如何检测无限重复的小数?

它不会显式检测重复出现的小数。它只是检测某些操作的结果不能使用指定的精度精确表示;例如,小数点后需要太多的数字才能获得精确的表示。

它必须跟踪并检测股息中的周期。它本可以选择以另一种方式处理这个问题,通过标记重复部分的位置,等等。

我想这可以被指定为精确地表示重复出现的小数;即作为一个类。但是,这将使实现更加复杂,并且使用2 的成本更高。而且由于大多数人都希望数字以十进制显示,并且重复出现的十进制问题在这一点上再次出现。BigDecimalBigRational

底线是,这种额外的复杂性和运行时成本不适合的典型用例。这包括财务计算,其中会计约定不允许您使用重复的小数。BigDecimal


1 - 这是一所优秀的小学。你可能在高中时就被教过这个。

2 - 要么尝试删除除数和红利的常见因素(计算成本高昂),要么允许它们无限制地增长(空间使用昂贵,后续操作计算成本高)。


答案 2

该类不是 。从你的一些评论来看,听起来你只是想抱怨有人没有在这类课程中构建所有可能的数字处理算法。金融应用程序不需要无限的小数精度;只需将值精确到所需的精度(通常为 0、2、4 或 5 位小数位)。BigDecimalBigFractional

实际上,我已经处理了许多使用.我不喜欢它,但这就是它们的编写方式(也不是用Java编写的)。当有汇率和单位转换时,就会有四舍五入和瘀伤问题的可能性。 消除了后者,但仍有前者用于划分。doubleBigDecimal


推荐