부동 소수점?
- 정수 부분과 소수 부분 모두 다 가진 값을 말합니다.
- 자바에 부동 소숫값을 담는 데이터 유형은 총 두 가지 입니다.
- double과 float
double
- 기본적인 부동 소수 리터럴 유형
- 8바이트
- 어떤 부동소수 연산이던 결과는 항상 double
double dbl = 34.5678;
float
- 4바이트
- 부동 소숫값 뒤에 꼭 f를 붙여함
float f = 34.5; //에러
float f = 34.5f;
float f = 34.5F;
형변환 오류
- 큰 타입→ 작은 타입으로 변환 할 때 오류가 발생합니다.
- 위를 예로 들자면 double → float로 변환시 에러가 난다는걸 확인할 수 있습니다
public class main
{
public static void main(String[] args)
{
double dbl = 3.45;
float f = dbl;
}
}
//incompatible types: possible lossy conversion from double to float
// float f = dbl;
^
//1 error
- 이는 전 글에서 말했던 명시적 형변환으로 간단히 해결할 수 있습니다
부동소수점에 형변환 적용하기
명시적 형변환
- 큰 타입 → 작은 타입
public class main
{
public static void main(String[] args)
{
double dbl = 3.45;
float f = (float) dbl;
System.out.println(f);
}
}
// 3.45
암묵적 형변환
- 작은 타입 → 큰 타입
public class main
{
public static void main(String[] args)
{
float f2 = 3.45f;
double dbl2 = f2;
System.out.println(dbl2);
}
}
// 3.450000047683716
- 여기서 보면 출력값이 이상한걸 확인하실 수 있습니다.
- 아래에서 자세히 살펴보도록 하겠습니다
부동소수점의 문제점
System.out.println(34.56789876 + 34.2234);
//출력값 : 68.79129875999999
- 갑자기 9는 어디서 나온걸까요?
💡 대부분의 부동소수 오차는 IEEE 754 표준의 이진 부동소수 표현 방식 때문입니다. 10진수를 2진수로 바꿀 때 일부 소수가 무한 이진소수로 변환되어 정확히 저장되지 못합니다. (참고)
- 따라서 부동소수는 소숫점값을 명료하게 나타내지 않아서 결과의 정확성이 요구되는 것에는 부동소수 데이터 유형을 계산에서는 float와 double을 사용하지 않는 게 좋습니다
- 정확한 결과를 원한다면 BigDecimal 클래스를 사용해야합니다
BigDecimal 클래스
- BigDecimal은 자바 클래스
import java.math.BigDecimal;
public class main
{
public static void main(String[] args)
{
BigDecimal number1 = new BigDecimal("34.56789876");
BigDecimal number2 = new BigDecimal("34.2234");
System.out.println(number1.add(number2));
}
}
//출력값: 68.79129876
- 여기서 중요한 점은, 자바에서 BigDecimal 클래스는 변경 불가능하다는 점
- BigDecimal 객체는 불변(Immutable) 클래스입니다. 한 번 생성된 값은 변경할 수 없고, 연산 시 새로운 객체를 반환합니다.
BigDecimal에 문자열을 넣는 이유?
- 정확성을 올리기 위해서
import java.math.BigDecimal;
public class main
{
public static void main(String[] args)
{
BigDecimal number1 = new BigDecimal(34.56789876);
BigDecimal number2 = new BigDecimal(34.2234);
BigDecimal number3 = number1.add(number2);
System.out.println(number3);
}
}
///68.79129875999999654823113814927637577056884765625
- double 타입을 사용해서 만들었더니 출력값이 매우 이상해졌습니다
- 정확한 것을 원한다면 문자열을 사용!!
BigDecimal 끼리만 연산이 가능해요
import java.math.BigDecimal;
public class main
{
public static void main(String[] args)
{
BigDecimal number = new BigDecimal("11.5");
BigDecimal number2 = new BigDecimal("23.45678");
int i = 5;
System.out.println(number.add(i));
}
}
- 이렇게 타입이 다른데 더할 경우 에러가 발생합니다
- 무조건 BigDecimal 끼리만 연산해주세요
import java.math.BigDecimal;
public class main
{
public static void main(String[] args)
{
BigDecimal number = new BigDecimal("11.5");
BigDecimal number2 = new BigDecimal("23.45678");
int i = 5;
System.out.println(number.add(new BigDecimal(i)));
}
}
//출력값: 16.5
(BigDecimal 메서드 같은 경우 이 글에서 배우고 있습니다!)
예제 BigDecimal로 이자 계산기 만들기
import java.math.BigDecimal;
public class SimpleInterestCalculator {
private BigDecimal principal;
private BigDecimal interest;
public SimpleInterestCalculator(String principal, String interest) {
this.principal = new BigDecimal(principal);
this.interest = new BigDecimal(interest);
}
public BigDecimal calculateTotalValue(BigDecimal noOfYears) {
BigDecimal interestRate = this.interest.divide(new BigDecimal("100"));
// 2. 총 이자 계산 (원금 * 이율 * 기간)
// (Principal * Rate * Time)
BigDecimal totalInterest = this.principal.multiply(interestRate).multiply(noOfYears);
// 3. 총액 계산 (원금 + 총 이자)
// (Principal + Total Interest)
BigDecimal totalValue = this.principal.add(totalInterest);
// 4. 총액 반환
return totalValue;
}
}
import java.math.BigDecimal;
public class SimpleInterestCalculatorRunner
{
public static void main(String[] args)
{
SimpleInterestCalculator calculator = new SimpleInterestCalculator("4500.00", "7.5");
// '5'는 문자형, 5는 숫자형 → 문자 '5'는 내부적으로 아스키코드 53으로 처리됩니다.
BigDecimal totalValue = calculator.calculateTotalValue(new BigDecimal("5"));
System.out.println(totalValue);
}
}
✍️ 요약
Java의 float와 double은 부동소수점 오차를 가질 수 있습니다.
정확한 계산이 필요한 금융, 이자 계산, 금액 처리에서는 BigDecimal 클래스를 사용해야 합니다.
특히 new BigDecimal("문자열") 형태로 선언하면 오차 없이 안전하게 연산할 수 있습니다.
📚 참고자료
'Programming Language > Java' 카테고리의 다른 글
| [WIL] 자바의 객체지향부터 BigDecimal까지 — 실수와 학습의 한 주 (0) | 2025.10.20 |
|---|---|
| [TIL] Java 불리안, 문자형, 그리고 정적 메서드 정리 (0) | 2025.10.19 |
| [TIL] Java 자료형과 형변환 완전 정리 (Wrapper Class · 진수 체계) (0) | 2025.10.18 |
| [TIL] 자바(Java) 생성자(Constructor) 완벽 정리: 메소드 오버로딩과 함께 사용하는 예제 (0) | 2025.10.16 |
| [TIL] Java 객체의 상태와 캡슐화 - Setter, Getter로 배우는 OOP 기본 (0) | 2025.10.15 |
