Java 또는 데이터베이스 관련 개발을 하다 보면 "Non-terminating decimal expansion; no exact representable decimal result" 오류를 만날 수 있습니다.
이 오류는 소수점 무한 반복(순환 소수)로 인해 정확한 표현이 불가능한 경우 발생합니다.
1. 오류 원인
1) 부동소수점 연산에서 발생
Java에서 double 또는 float을 사용하여 연산할 때, 무한히 반복되는 소수(순환소수)를 정확하게 표현할 수 없는 경우 발생합니다.
📌 예제 코드 (Java)
public class DecimalExpansionExample {
public static void main(String[] args) {
double result = 1.0 / 3.0;
System.out.println(result); // 0.333333333333...
}
}
💡 1/3 = 0.33333… (순환소수) 로, Java의 double 타입은 이를 정확히 저장할 수 없음
2) BigDecimal 사용 시 발생
BigDecimal을 사용할 때, 무한 반복 소수의 결과를 정확하게 표현하지 못할 경우 오류가 발생할 수 있습니다.
📌 예제 코드 (BigDecimal)
import java.math.BigDecimal;
public class BigDecimalErrorExample {
public static void main(String[] args) {
BigDecimal a = new BigDecimal("1");
BigDecimal b = new BigDecimal("3");
// 오류 발생: 무한소수 결과를 정확히 표현할 수 없음
BigDecimal result = a.divide(b);
System.out.println(result);
}
}
🚨 오류 발생
Exception in thread "main" java.lang.ArithmeticException:
Non-terminating decimal expansion; no exact representable decimal result
💡 1 / 3은 무한 반복 소수(0.3333...)가 되므로 BigDecimal은 정확한 표현을 할 수 없음 → 오류 발생
2. 해결 방법 3가지
1) BigDecimal에서 소수점 자리수 제한 설정 (setScale)
BigDecimal을 사용할 때 setScale(자리수, 반올림 방식)을 설정하면 무한소수 문제를 해결할 수 있습니다.
✔ 해결 코드
import java.math.BigDecimal;
import java.math.RoundingMode;
public class BigDecimalSolution {
public static void main(String[] args) {
BigDecimal a = new BigDecimal("1");
BigDecimal b = new BigDecimal("3");
// setScale을 이용하여 소수점 10자리까지 표현하고 반올림
BigDecimal result = a.divide(b, 10, RoundingMode.HALF_UP);
System.out.println(result); // 0.3333333333
}
}
✅ 해결 방법:
- .divide(나누는 값, 소수점 자리수, 반올림 방식) 사용
- RoundingMode.HALF_UP → 반올림하여 값 표현
다만, 이미 연산된 BigDecimal 값을 다른 자리수로 변환할 필요가 있다면 setScale()을 사용할 수도 있습니다.
✔ 해결 코드
BigDecimal result = a.divide(b, 10, RoundingMode.HALF_UP).setScale(4, RoundingMode.HALF_UP);
✅ 해결 방법:
- .divide()에서 직접 scale을 설정하면 setSacle()을 사용할 필요없음
- 하지만, 연산 후 특정 자리수로 변환하고 싶다면 setScale() 사용 가능
2) MathContext를 사용하여 정밀도 설정
또 다른 방법은 MathContext를 사용하여 연산의 정밀도를 조절하는 것입니다.
✔ 해결 코드
import java.math.BigDecimal;
import java.math.MathContext;
public class BigDecimalMathContextSolution {
public static void main(String[] args) {
BigDecimal a = new BigDecimal("1");
BigDecimal b = new BigDecimal("3");
// MathContext를 사용하여 정밀도 설정
BigDecimal result = a.divide(b, new MathContext(10));
System.out.println(result); // 0.3333333333
}
}
✅ 해결 방법:
- new MathContext(정밀도)를 활용하여 연산 시 정밀도를 미리 설정
3) double 또는 float 사용 시 반올림 처리
부동소수점(double, float)에서 발생하는 문제를 해결하려면 소수점 자릿수를 제한하는 방법이 있습니다.
✔ 해결 코드
public class DoublePrecisionSolution {
public static void main(String[] args) {
double value = 1.0 / 3.0;
// String.format을 이용하여 소수점 4자리까지 표현
System.out.println(String.format("%.4f", value)); // 0.3333
}
}
✅ 해결 방법:
- String.format("%.nf", 값)을 사용해 소수점 n자리까지만 표현
3. 결론
✔ BigDecimal을 사용할 때는 반드시 setScale() 또는 MathContext()를 설정해야 함
✔ double, float 연산 시 String.format()을 활용하여 표현 가능
✔ 무한 소수를 정확하게 표현할 수 없기 때문에, 반올림을 사용하여 해결
✔ Java에서 정확한 소수점 연산을 원한다면 BigDecimal을 사용하고, 적절한 반올림을 적용하는 것이 필수!