BigDecimal에 대한 짧은 이야기
코틀린에서 BigDecimal(2)/BigDecimal(2.5)
의 결과는 1
이라는 사실, 알고 계셨나요?
저는 막연히 알아서 잘(?) 계산해 줄 거라고 생각했는데, 그게 아니더라고요.
BigDecimal
은 precision
과 scale
로 이루어져 있다고 합니다.
precision
: 유효숫자의 개수scale
: 소수점 아래의 숫자 개수
코틀린의 /
연산자는 사실 .div(other)
함수를 호출하는데, BigDecimal.div
는 이렇게 생겼습니다.
// https://github.com/JetBrains/kotlin/blob/924c28507067cbfbf78a6509ea89eabe496e34ca/libraries/stdlib/jvm/src/kotlin/util/BigDecimals.kt#L40
@kotlin.internal.InlineOnly
public inline operator fun BigDecimal.div(other: BigDecimal): BigDecimal = this.divide(other, RoundingMode.HALF_EVEN)
그리고 BigDecimal.divide
는 이렇게 생겼죠.
// https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/math/BigDecimal.java
public BigDecimal divide(BigDecimal divisor, int roundingMode) {
return this.divide(divisor, scale, roundingMode);
}
즉, 코틀린에서 두 개의 BigDecimal
로 a/b
를 하면, a.div(b)
→ a.divide(b, RoundingMode.HALF_EVEN)
→ a.divide(b, a.scale, RoundingMode.HALF_EVEN)
순으로 실행됩니다. b
의 scale
이 몇 자리이든 상관없이 a
의 scale
에 따라 계산되는 거죠!
앞의 2 / 2.5
예제에서는, 정답은 0.8
이지만 BigDecimal(2)
의 scale
이 0이기 때문에 소수점 아래 자릿수가 0이 되도록 반올림(HALF_EVEN
)하여 1
이 나오게 됩니다.
컴퓨터가 소수점 첫 번째 자리에서 반올림을 하다니 낚인 기분이지만, 앞으로는 BigDecimal(2).divide(BigDecimal(2.5), 4, RoundingMode.DOWN)
같은 식으로 유효 숫자 개수와 올림/내림 방식을 명확히 입력해 주면 될 것 같아요.
더 나은 방법을 알고 있거나, 글에 오류가 있다면 알려주시면 감사하겠습니다!
Dani Soohan Park (@heartade)
Follow this blog at Fediverse: @heartade@blog.heartade.dev
Follow my shorter shoutouts at Fediverse: @heartade@social.silicon.moe
Follow me at Bluesky: @heartade.dev