java-Scala中的BigDecimal

我在scala中偶然发现了一些有趣的东西(可能仅对我来说).简而言之,如果我们有一个BigDecimal(假设val a = BigDecimal(someValue),其中someValue是十进制字符串),则运算结果

N * a / N == a

不会总是产生真实的.我想这与BigDecimals上的任何意见有关.我知道在Scala中创建的BigDecimals的认MathContext设置为DECIMAL128(HALF_EVEN舍入且精度等于34).我发现小数点后超过30位的这种行为

我的问题是为什么我得到这样的结果.我可以控制它们吗?

-0.007633587786259541984732824427480916

解决方法:

正如前面的评论已经指出的那样,用无理数是无法避免的.这是因为无法使用标准数值类型(如果有的话)来表示非理性数字.由于我没有无理数的示例(即使PI仅限于固定的数字位数,因此可以表示为2个整数的商,这使其很合理),因此,我将使用重复小数点来说明问题.我将N * a / N更改为a / N * N,因为它可以更好地说明整数问题,但它们是等效的:

a = BigDecimal(1)
N = BigDecimal(3)
a/N = 0.333...
a/N*N = 0.999...

如上例所示,可以使用任意多个小数位和任何舍入模式,但是结果永远不会等于1.(尽管每次操作使用不同的舍入模式都可以得到1,即BigDecimal(3,roundHalfEven)*(BigDecimal(1,roundUp)/ 3))

您可以控制数字比较的一件事是在执行算术运算时使用较高的精度,而在比较时舍入为所需的(较低)精度:

val HighPrecision = new java.math.MathContext(36, java.math.RoundingMode.HALF_EVEN);
val TargetPrecision = java.math.MathContext.DECIMAL128;

val a = BigDecimal(1, HighPrecision)
val N = BigDecimal(3, HighPrecision)
(a/N*N).round(TargetPrecision) == a.round(TargetPrecision)

在上面的示例中,最后一个表达式的计算结果为true.

更新

为了回答您的评论,尽管BigDecimal是任意精度,但仍受精度限制.可以是34,也可以是1000000(如果有足够的内存). BigDecimal不知道1/3是0.33

相关文章

点击查看更多相关文章

转载注明原文:java-Scala中的BigDecimal - 代码日志

相关文章

共收录Twitter的14款开源软件,第1页Twitter的Emoji表情 Tw...
Java和Scala中关于==的区别Java:==比较两个变量本身的值,即...
本篇内容主要讲解“Scala怎么使用”,感兴趣的朋友不妨来看看...
这篇文章主要介绍“Scala是一种什么语言”,在日常操作中,相...
这篇文章主要介绍“Scala Trait怎么使用”,在日常操作中,相...
这篇文章主要介绍“Scala类型检查与模式匹配怎么使用”,在日...