微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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 - 代码日志

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐