본문 바로가기
카테고리 없음

[JAVA]Non-terminating decimal expansion; no exact representable decimal result

by 리승연 2025. 3. 5.
반응형

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을 사용하고, 적절한 반올림을 적용하는 것이 필수! 

반응형