BigDecimal?
BigDecimal은 Java 언어에서 숫자를 정밀하게 저장하고 표현할 수 있는 유일한 방법
사용하는 이유
Java 에서의 실수
float
와 double
이 있다. 정수형 int
, long
타입과 동일하게 각각 4, 8바이트의 메모리 공간을 사용하지만 실수를 가수와 지수 부분으로 나누어 표현하는 부동 소수점 방식을 기반으로 정수보다 더 넓은 범위의 값을 표현할 수 있다.
참고로 자바에서는 실수 연산에서 double
타입을 기본적으로 사용한다.부동소수점 방식의 문제
Java 에서 사용하는 소수점 방식으로 컴퓨터는 실수 표현을 근사값으로 표현하기 때문에 오차가 존재한다.
Test
@Test
void test() {
double a = 100.0000000005;
double b = 10.0000000004;
assertThat(a - b).isEqualTo(90.0000000001);
}
결과
위와 같은 문제가 있기 때문에 BigDecimal 객체를 사용 한다
사용방법
선언
@Test
void initBigDecimal() {
//문자열로 초기화해야 정확한 값 사용가능.
//double 타입을 그대로 초기화하면 기대값과 다른 값을 가진다.
//0.01000000000000000020816681711721685132943093776702880859375
BigDecimal a = new BigDecimal(0.01);
//문자열로 초기화
//0.01
BigDecimal b = new BigDecimal("0.01");
//double#toString을 이용하여 문자열로 초기화
//0.01
BigDecimal c = BigDecimal.valueOf(0.01);
}
valuOf()
메서드의 경우 기존에 생성된 값의 객체가 있으면 캐싱 해놓은 값에 바로 접근 할 수 있기 때문에 더 빠르다
연산
비교 연산
@Test
void bigDecimal() {
BigDecimal a = new BigDecimal("0.01");
BigDecimal b = new BigDecimal("0.010");
// 객체의 레퍼런스 주소에 대한 비교 연산자로 객체의 주소가 다르므로 false (new 연산자를 사용하여 서로 다른 주소를 가짐)
// false
boolean result = (a == b);
// System.out.println(result);
// 소수점 맨 끝의 0까지 완전히 값이 동일해야 true 반환
// false
result = a.equals(b);
// System.out.println(result);
// 소수점 맨 끝의 0을 무시하고 값이 동일하면 0, 적으면 -1, 많으면 1을 반환
// 0
int result2 = a.compareTo(b);
// System.out.println(result2);
}
사칙 연산
BigDecimal add(BigDecimal val) //덧셈
BigDecimal subtract(BigDecimal val) //뺄셈
BigDecimal multiply(BigDecimal val) //곱하기
BigDecimal divide(BigDecimal val) //나누기
BigDecimal remainder(BigDecimal val) //나머지
소수점 처리
// 소수점 이하를 절사한다.
// 1
new BigDecimal("1.1234567890").setScale(0, RoundingMode.FLOOR);
// 소수점 이하를 절사하고 1을 증가시킨다.
// 2
new BigDecimal("1.1234567890").setScale(0, RoundingMode.CEILING);
// 음수에서는 소수점 이하만 절사한다.
// -1
new BigDecimal("-1.1234567890").setScale(0, RoundingMode.CEILING);
// 소수점 자리수에서 오른쪽의 0 부분을 제거한 값을 반환한다.
// 0.9999
new BigDecimal("0.99990").stripTrailingZeros();
// 소수점 자리수를 재정의한다.
// 원래 소수점 자리수보다 작은 자리수의 소수점을 설정하면 예외가 발생한다.
// java.lang.ArithmeticException: Rounding necessary
new BigDecimal("0.1234").setScale(3);
// 반올림 정책을 명시하면 예외가 발생하지 않는다.
// 0.123
new BigDecimal("0.1234").setScale(3, RoundingMode.HALF_EVEN);
// 소수점을 남기지 않고 반올림한다.
// 0
new BigDecimal("0.1234").setScale(0, RoundingMode.HALF_EVEN);
// 1
new BigDecimal("0.9876").setScale(0, RoundingMode.HALF_EVEN);
<aside>
💡 • RoundingMode.HALF_EVEN
은 Java의 기본 반올림 정책으로 금융권에서 사용하는 Bankers Rounding와 동일한 알고리즘이다. 금융권에서는 시스템 개발시 혼란을 막기 위해 요구사항에 반올림 정책을 명확히 명시하여 개발한다.
</aside>