[BigDecimal] java 소숫점 계산 정확하게 하기
😮문제상황
public void calculateFuelTank(List<Checklist> checklists,Yata yata){
int positiveCount = (int) checklists.stream().filter(Checklist::isCheckpn).count();
int negativeCount = checklists.size() - positiveCount;
if(positiveCount>negativeCount) yata.getMember().setFuelTank(yata.getMember().getFuelTank() + 0.1);
else yata.getMember().setFuelTank(yata.getMember().getFuelTank() - 0.1);
}
}
프로젝트로 카풀 서비스를 만들던 중
카풀 후 상대에게 리뷰를 작성할 수 있는데
리뷰에서 긍정 체크리스트 항목을 더 많이 체크한 경우 해당 멤버의 매너점수를 0.1씩 올리고,
그렇지 않은 경우 0.1씩 내리는 메서드를 만들고 싶었다
그러나
요런 식으로 리뷰 점수가 0.1 씩 올라가는게 아니라
0.10000000002 이런식으로 올라가는 것이다
🔎원인
컴퓨터는 모든 숫자를 0과 1로만 표현할 수 있기에 소수를 0과 1로 표현하는 과정에서 오차가 나는 것이다
각종 프로그래밍 언어에서는 소수를 표현할 때 IEEE 754 부동 소수점 방식으로 소수를 표현하게 되는데,
java에서도 이 방식으로 소수를 계산한다.
자바의 부동 소수점 계산방식에 대한 자세한 내용은 아래 포스팅에 올려놓았다
https://develoyummer.tistory.com/66
java- IEEE 754 부동 소수점 방식
자바에서 소수의 계산시에 값이 3.02 + 1.06 = 4.08 이렇게 정확하게 떨어지지 않고 3.0800003 이런식으로 나오는 경우가 있다. 이는 자바의 소수점 계산방식 때문이다. 각종 프로그래밍 언어에서는 소
develoyummer.tistory.com
고정 소수점 방식 | 정확, 범위가 좁다 |
부동 소수점 방식 | 정확도가 떨어짐(근사치 제공) , 범위가 넓다. |
🔎BigDecimal
따라서 Java에서 정확한 소수 계산을 하고 싶다면
소수점을 정확하계 계산할 수 있게 해주는 라이브러리인 BigDecimal을 사용해주면 된다.
📌선언 및 초기화
BigDecimal num = new BigDecimal("value"); //value는 숫자가 아닌 문자 타입으로 넣어줘야 한다
📌BigDecimal 을 이용한 사칙연산
더하기 | num1.add(num2); |
빼기 | num1.subtract(num2)); |
곱하기 | num1.multiply(num2)); |
나누기 | num1.divide(num2)); |
✔해결방법
따라서 다음과 같이 변환해 주었다
public void calculateFuelTank(List<Checklist> checklists, Yata yata) {
int positiveCount = (int) checklists.stream().filter(Checklist::isCheckpn).count();
int negativeCount = checklists.size() - positiveCount;
BigDecimal ChangeNum = new BigDecimal(String.valueOf(0.1));
BigDecimal FuelTankScore = new BigDecimal(String.valueOf(yata.getMember().getFuelTank()));
if (positiveCount > negativeCount) yata.getMember().setFuelTank(FuelTankScore.add(ChangeNum).doubleValue());
else yata.getMember().setFuelTank(FuelTankScore.subtract(ChangeNum).doubleValue());
}
이제 정상적으로 잘 올라간다
참고한 자료
https://wakestand.tistory.com/202