컴퓨터는 2진수를 사용하기때문에 소수점을 표현하는데는 한계가 있고 오차가 발생한다.
돈과 관련된 도메인에서는 이는 매우 치명적이며 주의해야한다.
public class Test {
public static void main(String[] args) {
double a = 0.1;
double b = 0.2;
double c = 0.3;
System.out.println(a + b);
System.out.println(a + b == c);
}
}
0.30000000000000004
false
정확한 소수점 계산들을 사용하기 위해서는 각 언어에서는 이를 지원해주는 라이브러리들이 있다.
- Java : math.BigDecimal
- JS : Big.js 라이브러리
- python : import decimal 등
이들 중 java의 BigDecimal 을 다룬다.
BigDecimal은 불변의 성질을 가지며, 임의 정밀도와 부호를 가지는 10진수이다.
그리고, 원시타입이 아니므로 연산자를 사용할 수 없고, 메서드를 통하여 계산해야한다. 또한, 불변성을 가지므로 메서드를 통해 연산할 때 마다 새로운 객체를 생성한다.
Java의 BigDecimal 구성
package java.math;
public class BigDecimal extends Number implements Comparable<BigDecimal> {
private final BigInteger intVal; // = unscaled value
private final int scale;
private transient int precision;
private final transient long intCompact;
...
intVal : unscaled value를 저장한 값
intCompat : 유효숫자의 절대값이 long타입으로 표현가능하면 BigInteger대신 저장하여 메모리를 최적화한다.
scale : 소수점 오른쪽의 자릿수
precision : 총 자릿수
ex) BigDecimal.valueOf(3.14)
BigDecimal 사용시 주의점
- 계산 결과가 무한소수 같은 경우 ArithmeticException 예외가 발생한다.
(ex. BigDemical.valueOf(10).divide(BigDecimal.valueOf(3))
자리 수를 지정할 수 있다. Enum클래스의 RoundingMode참고할것
// 나누기 - 소수점 아래 첫째 자리까지 반올림
a.divide(b, 1, RoundingMode.HALF_UP);
// 나누기 - 총 자릿수를 34개로 제한하고 반올림(HALF_EVEN)
a.divide(b, MathContext.DECIMAL128);
- 생성시 double값을 이용하지 말것
근사값이 그대로 저장되어버린다.
BigDecimal bigDecimal = new BigDecimal(1.1);
System.out.println(bigDecimal);
// 1.100000000000000088817841970012523233890533447265625
String 생성자나 valueOf같은 정적 팩토리 메서드를 이용할 것
new BigDecimal("1.12"); // 1.12
BigDecimal.valueOf(1.12); // 1.12
- 동등성 비교시 compareTo()와 equals() 주의
equals()는 unscaled value과 scale을 모두 비교하는 반면, compareTo()는 unscaled value만을 비교한다. equals()는 값과 소수점 이하의 자릿수를 모두 비교하고 compareTo()는 값만 비교한다.
{
"price": 0
}
BigDecimal price = fetchAPI().getPrice(); // BigDecimal("0.0000")
response.price.equalsTo(BigDecimal.ZERO) // false
response.price.compareTo(BigDecimal.ZERO) == 0 // true
참고글:
https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html
'공부 > CS 기초이론' 카테고리의 다른 글
[JAVA / Spring] DI의 구현 방법 (0) | 2023.04.19 |
---|---|
[Web] REST API 규칙 (0) | 2023.04.14 |
[Web] URI, URN, URL 구분하기 (0) | 2023.04.12 |
[Web] REST에 대해 간단 정리 (0) | 2023.04.12 |
[Web] HTTP Method (0) | 2023.04.11 |