Processing math: 100%
본문 바로가기
JAVA BASE/lang & util

14. [자바] BigDecimal클래스

by staticClass 2020. 12. 28.

BigDecimal클래스?

double타입으로 표현할 수 있는 값도 범위가 넓은 편이지만 정밀도가 최대 13자리 밖에 되지 않고
실수형의 특성상 오차를 피할 수 없다.
하지만 BigDecimal을 이용한다면 더 큰 실수를 다룰수 있다.

private final BigInteger intVal; // 정수(unscaled value)
private final int scale; // 지수(scale)
private transient int precision // 정밀도(percision) - 정수의 자릿수

위의 코드는 클래스 내부에 정의된 멤버변수인데 정수부분 지수부분 정밀도를 각 변수에 담아 사용하고 있다
BigDecimal에 123.45를 담는다 했을 때 12345×102 로 표현 가능하며
이 값이 BigDecimal에 담기면 intVal의 값은 12345가 되고 scale의 값은 2가 된다.
scale의 값은 소수점 이하의 자리수를 의미한다 그리고 percision의 값은 5가 되는데
이 값은 정수의 전체 자리수를 의미한다.

BigDecimal val = new BigDecimal("123.45");
System.out.println(val.unscaledValue()); // 12345
System.out.println(val.scale()); // 2
System.out.println(val.precision()); // 5

BigDecimal의 생성

BigDecimal을 생성할 때는 문자열로 숫자를 표현하는 것이 일반적이다.

BigDecimal val;
val = new BigDecimal("123.4567890"); // 문자열로 생성
val = new BigDecimal(123.456); // double타입의 리터럴로 생성
val = new BigDecimal(123456); // int, long 타입의 리터럴로 생성가능
val = BigDecimal.valueOf(123.456); // 생성자 대신 valueOf(double)사용
val = BigDecimal.valueOf(123456); // 생성자 대신 valueOf(int)사용

한가지 주의할 점은 double타입의 값을 매개변수로 갖는 생성자를 사용하면
오차가 발생할 수 있다.

System.out.println(new BigDecimal(0.1)); // 0.10000000000000000555111...
System.out.println(new BigDecimal("0.1")); // 0.1

다른 타입으로 변환

String toPlainString() // 다른 기호 없이 숫자로만 표현
String toString() // 필요하면 지수형태로 표현할 수 있음

toPlainString(), toString() 둘 다 반환결과가 같지만
인스턴스를 생성 시 1.0e22와 같은 지수형태의 리터럴을 사용하면 다른 결과를 얻는 경우가 있다.

BigDecimal val = new BigDecimal(1.0e-22);
System.out.println(val.toPlainString); // 0.00000000000000000000010...
System.out.println(val.toString); // 1.000000000000000048...5E-22

Number로 부터 상속받은 변환 메서드들이 있다.

BigDecimal val = new BigDecimal("123.45");
val.intValue();
val.longValue();
val.floatValue();
val.doubleValue();

정수형으로 변환하는 메서드 중 이름 끝에 'Exact'가 붙은 것들은 변환한 결과가
변환한 타입의 범위에 속하지 않으면 ArithmeticException을 발생시킨다.

val.byteValueExact()
val.shortValueExact()
val.intValueExact()
val.longValueExact()
val.toBigIntegerExact()

BigDecimal의 연산

실수형에 사용할 수 있는 모든 연산자와 계산을 쉽게 해주는 메서드가 있다.

BigDecimal add(BigDecimal val) // 덧셈(this + val)
BigDecimal subtract(BigDecimal val) // 뺄셈(this - val)
BigDecimal multiply(BigDecimal val) // 곱셈(this * val)
BigDecimal divide(BigDecimal val) // 나눗셈(this / val)
BigDecimal remainder(BigDecimal val) // 나머지(this % val)

연산결과의 정수, 지수, 정밀도가 달라진다.

// value, scale, precision
BigDecimal bd1 = new BigDecimal("987.654"); // 987654, 3, 6
BigDecimal bd2 = new BigDecimal("1.0"); // 10, 1, 2
BigDecimal bd3 = bd1.multiply(bd2); // 9876540, 4, 7
System.out.println(bd3); // 987.6540

divide(), setScale() - 반올림

나눗셈을 처리하기 위한 다양한 방법이 존재한다. 나눗셈의 결과를 반올림하는 방법을 선택 할수 있고
몇번째 자리(scale)에서 반올림 할지 정할 수 있다.
BigDecimal이 오차없이 실수를 저장한다고 해도 나눗셈의 오차는 어쩔 수 없다.

BigDecimal bd1 = new BigDecimal("3");
BigDecimal bd2 = new BigDecimal("2");
BigDecimal bd3;
bd3 = bd1.divide(bd2); // bd3 = 1.5
bd1.divide(bd2, RoundingMode.HALF_UP); // 나눗셈을 한 뒤에 반올림 : 2
bd3.setScale(0, RoundingMode.HALF_UP); // 1.5를 반올림
상수설명
CEILING올림
FLOOR내림
UP양수일 때는 올림, 음수일 때는 내림
DOWN양수일 때는 내림, 음수일 때는 올림(UP과 반대)
HALF_UP반올림(5이상 올림, 5미만 버림)
HALF_EVEN반올림(반올림 자리의 값이 짝수면 HALF_DOWN, 홀수면 HALF_UP)
HALF_DOWN반올림(6이상 올림, 6미만 버림)
UNNECESSARY나눗셈의 결과가 딱 떨어지는 수가 아니면, ArihmeticException발생

1.0/3.0처럼 나눗셈의 결과가 무한소수인 경우, 반올림 모드를 지정해주지 않으면 ArihmeticException이 발생한다.

MathContext

반올림 모드와 정밀도를 하나로 묶은 클래스이다

BigDecimal bd1 = new BigDecimal("123.456");
BigDecimal bd2 = new BigDecimal("1.0");
bd1.divide(bd2, 2, HALF_UP); // 123.46
bd1.divide(bd2, 2, new MathContext(2, HALF_UP))); // 1.2E+2

댓글