부동 소수점 오류
double, float와 같은 Primitive 변수를 사용하다보면 연산결과가 이상하게 나오는 경우가 있다.가령 예를들어서 0.3 + 0.4를 했을 때 0.70000000000000004 라는 결과가 나오는 경우처럼 말이다.이는 소수점을 다룰 때 부동소수점 오류로 인해 소수점이 제대로 표현되지 않는 문제가 발생하는 것이다.float와 double은 부동소수점 표현방식으로 구현 되어있는데, 부동소수점 표현 방식은 고정 소수점 표현 방식에 비해 표현범위가 넓지만 2진수를 사용하기 때문에 소수를 표현할 때 오차가 발생한다. 그래서 이런 문제를 예방하고자 BigDecimal을 사용한다고 한다.
부동소수점 오류에 대해서는 시간이 된다면 더욱 자세하게 정리를 해보겠다.
오늘은 BigDecimal에 대해서 공부해보자.
BigDecimal이란
BigDecimal은 불변의 성질을 띄며 임의 정밀도와 부호를 지니는 10진수 이다. BigDecimal은 객체 간의 연산마다 새로운 객체를 생성하는데 float나 double과 같은 기본 타입에 비해 속도가 느리다는 단점이 있다. 하지만 정확도 면에서는 우수하기 때문에, 돈계산과 같은 소수점 오차마저 정확해야하는 분야에서는 BigDecimal을 사용해야 한다. BigDecimal은 개념적으로 임의 정밀도 정수형인 unscaled value와 소수점 오른쪽의 자릿수를 나타내는 32비트 정수인 scale로 구성된다.
BigDecimal 생성
BigDecimal()을 사용할 때는 인자값을 문자열로 넘겨서 생성한다. 문자열을 넘겨주지 않는다면 부동소수점 오류가 그대로 나타나게 된다.
val bigDecimal1 = BigDecimal("100.125") // 문자열로 넘겨줌
println(bigDecimal1)
val bigDecimal2 = BigDecimal.valueOf(100.125) // 숫자로 넘겨줌
println(bigDecimal2)
즉, double을 통해서 BigDecimal을 생성하면 안 된다. 앞서 언급했듯이 double은 근삿값을 담고 있기 때문에 BigDecimal에 이 근삿값이 고스란히 담기게 된다.
대신 String 생성자나 valueOf() 정적 팩터리 메서드를 사용해서 BigDecimal을 생성해야 한다. valueOf() 메서드는 double을 String으로 변환한 후 BigDecimal을 생성한다.
BigDecimal 연산
val decimal1 = BigDecimal("100.15")
val decimal2 = BigDecimal("10.5")
// 덧셈 연산
println(decimal1 + decimal2)
println(decimal1.plus(decimal2))
// 뺄셈 연산
println(decimal1 - decimal2)
println(decimal1.minus(decimal2))
// 곱셈 연산
println(decimal1 * decimal2)
println(decimal1.times(decimal2))
// 나눗셈 연산
println(decimal1 / decimal2)
println(decimal1.div(decimal2))
// 나머지 연산
println(decimal1 % decimal2)
println(decimal1.rem(decimal2))
BigDecimal 비교
BigDecimal은 compareTo라는 메소드를 사용하여 비교할 수 있다.
decimal1.compareTo(decimal2) 기준 decimal1이 크면 1을 반환하고 작으면 -1을 반환한다. decimal2과 같을 경우에는 0을 반환한다.
val decimal1 = BigDecimal("100.15")
val decimal2 = BigDecimal("10.5")
val compare = decimal1.compareTo(decimal2)
println(compare) // decimal1이 크면 1 같으면 0 작으면 -1
참고
https://velog.io/@simsubeen/20231130TIL-Kotlin-BigDecimal
'Programming Language > Kotlin' 카테고리의 다른 글
[Kotlin] const val에 대해서 공부하자 (0) | 2024.05.28 |
---|---|
[Kotlin] lateinit, lazy 에 대해서 공부하자 (0) | 2024.05.28 |
[Kotlin] Flow Retry 연산자 (0) | 2024.03.03 |
[Kotlin] Dispatchers in Kotlin Coroutines (0) | 2024.03.02 |
[Kotlin] Flow zip 연산자로 long- running tasks in parallel 처리하기 (0) | 2024.03.02 |