【问题标题】:BigDecimal losing precision on divideBigDecimal 在除法上失去精度
【发布时间】:2021-09-27 17:18:46
【问题描述】:

考虑以下 BigDecimals

BigDecimal("6.0000").precision() // = 5
BigDecimal("0.20000").precision() // = 5

当你划分那些 BigDecimals 时:

BigDecimal("6.0000").divide(BigDecimal("0.20000")) // = 3E+1

BigDecimal("6.0000").divide(BigDecimal("0.20000")).precision() // = 1

因此,将两个精度为 5 的 BigDecimal 相除会得到精度为 1 的 BigDecimal。即使通过提供 MathContext 将精度显式设置为 5,结果也是相同的:

BigDecimal("6.0000").divide(BigDecimal("0.20000"), MathContext(5, RoundingMode.HALF_UP)) // = 3E+1

另一方面,当我设置 scale 时,我最终得到了更高的精度

BigDecimal("6.0000").divide(BigDecimal("0.20000"), 5, RoundingMode.HALF_UP).precision() // = 7

有没有办法在执行上述除法时保持精度?这是否只能通过指定scale 而不是precision 来实现?

关于scale,javadoc 指出首选 分割比例是dividend.scale() - divisor.scale()。但是,它也指出

这些尺度是返回精确算术结果的方法所使用的尺度;除了精确除法可能必须使用更大的比例,因为精确结果可能有更多位数。例如,1/32 是 0.03125。

上述情况不就是这样吗,因为确切的结果需要更多的数字?

【问题讨论】:

  • 在您需要将值转换为字符串之前,我不会担心精度。 MathContext(5, RoundingMode.HALF_UP) 将有助于在计算过程中将精度保持在一定水平,但对于计算本身而言,值是 30、30.0 还是 30.000(它始终是相同的数值)并不重要。在返回结果或将其转换为字符串时,只需在最后设置比例(这是尾随零很重要的唯一情况)。
  • @Sweeper 是 Kotlin

标签: java kotlin rounding bigdecimal


【解决方案1】:

在您的情况下,它是does not really matter,因为结果是精确的。如果您需要具体的精度(可能用于解析),请在末尾使用setScale

如果一个函数需要失去精度才能给你一个结果(例如,因为 1 除以 3),除法会抛出异常(在使用 divide 函数的情况下,因为 Kotlin div 运算符会舍入结果,失去精度)。所以除法时最好自己设置精度和舍入模式。

import java.math.BigDecimal
import java.math.RoundingMode.HALF_EVEN

fun main() {
    val a = BigDecimal("1.0")
    val b = BigDecimal("3.0")
    val c = a.divide(b, 10, HALF_EVEN)
    println(c) // 0.3333333333
    println(c.precision()) // 10
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-28
    • 1970-01-01
    • 2012-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-02
    • 1970-01-01
    相关资源
    最近更新 更多