Java 기반 프로그램에서 소수점에 대한 정확한 계산이 필요하거나 화폐 단위를 다룰 때는 BigDecimal을 사용하는데요.
자바에서 숫자를 표현하는 데이터 타입에 대해서 간단하게 살펴보고, 이어서 BigDecimal을 사용해야 하는 이유는 무엇인지 살펴보겠습니다.
Java에서 숫자를 표현하기 위한 데이터 타입
자바에서 숫자를 표현하기 위해 사용하는 데이터 타입은 크게 '정수형 데이터 타입'과 '실수형 데이터 타입'으로 나눠집니다.
- 정수형 데이터 타입(Integer Types)
데이터 타입 (자료형) | 크기 | 저장 가능한 값의 범휘 |
byte | 1byte (8bit) | -128 ~ +127 |
short | 2byte (16bit) | -32,768 ~ + 32,767 |
int | 4byte (32bit) | -2,147,483,648 ~ +2,147,483,647 (약 -21억 ~ +21억) |
long | 8byte (64bit) | -9,223,372,036,854,775,808 ~ +9,223,372,036,854,775,807 (약 -900경 ~ +900경) |
- 실수형 데이터 타입 혹은 부동소수점 타입(Floating-Point Types)
데이터 타입 (자료형) | 크기 | 저장 가능한 값의 범위 |
float | 4byte (32bit) | 1.40239846E-45f ~ 3.40282347E+38f |
double | 8byte (64bit) | 4.94065645841246544E-324 ~ 1.79769313486231570E+308 |
float은 소수점 이하 6자리, double은 소수점 이하 15자리의 정밀도를 가지고 있으며, double은 소수점을 가지는 수 중에서 float 보다 더 큰 소수점을 가지는 숫자를 담을 때 적합합니다.
(E notation은 exponent 즉, 지수 표기입니다. 4.9E-324는 4.9*10^-324를 의미합니다.)
BigDecimal을 사용하는 이유
double val = 0.0;
for (int i=0; i<10; i++) {
val += 0.1;
}
System.out.println("val : " + val); // val : 0.9999999999999999
System.out.println("0.1 + 0.2 == 0.3 ? " + (0.1 + 0.2 == 0.3)); // 0.1 + 0.2 == 0.3 ? false
위 예시를 통해 알 수 있는 것처럼 실수형 타입(부동소수점 타입)인 float, double은 정확한 표기가 필요한 외화 환율이나 화폐를 다룰 때는 적절하지 않은데요. 이러한 결과가 나타나는 이유는 '부동소수점의 부정확성' 때문입니다.
java에서 float과 double 타입은 애초에 과학, 공학 계산을 위해 설계되었으며, 넓은 범위의 수에 대한 근사치를 빨리 산출하기 위한 이진 부동소수점 연산을 수행합니다.
컴퓨터에서 부동소수점을 표현하기 위해 사용하는 형식은 여러 가지가 있지만, 현재 거의 대부분이 호환성을 위해 미국 전기전자공학회(IEEE)에서 표준화한 IEEE 754 형식을 사용하고 있는데요.
부동소수점의 부정확성에 대한 원인은 위 이미지의 예시와 같이 IEEE 754 표준에 의해 정수, 소수 등과 같은 숫자가 2진으로 저장되기 때문에 나타납니다.
(십진수 0.1은 이진수로 바뀌면서 무한 소수가 되고, 컴퓨터는 가장 근사한 값을 반환하는데 여기에서 부정확성이 나타나는 것입니다.)
=> 따라서 소수점에 대한 정확한 계산이 요구되거나 화폐 단위를 다룰 때는 BigDecimal을 사용해야 하는 것입니다.
BigDecimal의 특징 (간단하게)
BigDecimal은 원시 타입이 아니기 때문에 연산자를 사용할 수 없으며 add, multiply, divide 등의 메서드를 사용하여 연산해야 합니다.
또한 불변성(Immutable)을 가지고 있는데, 때문에 연산 메서드를 사용하면 객체 내부의 값이 변경되는 것이 아니라 연산 결괏값을 갖는 새로운 객체가 생성되어 반환됩니다.
때문에 원시 타입의 연산에 비해 속도가 느리다는 단점이 있지만, 정확도를 위해서는 무조건 BigDecimal을 사용해야 합니다.
< 참고 자료 >
'Programming > Java' 카테고리의 다른 글
Java 정규표현식 사용하기(Regular Expression) (0) | 2022.09.07 |
---|---|
LocalDate 해당 월의 마지막 날짜 구하는 방법 (0) | 2022.09.04 |
Java 위도 경도에 따른 거리 계산(내 주변 반경) (2) | 2022.08.03 |
@MappedSuperclass 조금 다르게 사용해보기 (0) | 2022.07.18 |
Java 클라이언트 요청 IP 가져오는 방법(HttpServletRequest) (0) | 2022.06.07 |