BigDecimal에 대한 짧은 이야기

코틀린에서 BigDecimal(2)/BigDecimal(2.5)의 결과는 1이라는 사실, 알고 계셨나요?

저는 막연히 알아서 잘(?) 계산해 줄 거라고 생각했는데, 그게 아니더라고요.

BigDecimalprecisionscale로 이루어져 있다고 합니다.

코틀린의 / 연산자는 사실 .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);
    }

즉, 코틀린에서 두 개의 BigDecimala/b 를 하면, a.div(b)a.divide(b, RoundingMode.HALF_EVEN)a.divide(b, a.scale, RoundingMode.HALF_EVEN) 순으로 실행됩니다. bscale이 몇 자리이든 상관없이 ascale에 따라 계산되는 거죠!

앞의 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