부동소수점 연산
부동소수점 연산은 일반적인 산술 연산과는 달리 예측하기 어려운 결과를 낼 수 있는 특별한 세계라고 볼 수 있습니다. 이는 부동소수점의 내부 표현 방식과 연산 과정에서 발생하는 근사치 사용 때문입니다.
부동소수점 연산의 예상과 현실
다음 코드를 살펴보겠습니다:
double d1 = 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1;
System.out.println("d1 == 1 ? " + (d1 == 1.0));
이 코드의 결과를 예상해보면, 대부분의 사람들은 true
가 출력될 것으로 생각할 것입니다. 하지만 실제로는 false
가 출력됩니다.
이는 부동소수점 추가 연산이 수행되고 반올림되는 방식 때문에 발생하는 현상입니다. 각 0.1의 덧셈마다 작은 오차가 누적되며, 최종적으로 1.0과 정확히 일치하지 않는 값이 됩니다.
부동소수점 연산의 원리
Java에서 부동소수점 연산은 IEEE 754 표준을 따릅니다. 이 표준은 부동소수점 수를 비트로 표현하는 방식을 정의합니다. 하지만 이 표준의 구체적인 내용은 이 책의 범위를 벗어나므로 자세한 설명은 생략하겠습니다.
부동소수점 연산의 주의사항
- 등식 비교 피하기:
// 피해야 할 코드
if (x == y) {
// ...
}
// 권장되는 방법
public static boolean nearlyEqual(double a, double b, double epsilon) {
final double diff = Math.abs(a - b);
return diff <= epsilon;
}
if (nearlyEqual(d1, 1.0, 0.00001)) {
// d1과 1.0이 거의 같다고 간주
}
- 반올림 오차 관리:
double total = 0.0;
for (int i = 0; i < 1000000; i++) {
total += 0.000001;
}
System.out.println(total);
// 출력: 0.9999999999999989 (예상보다 작음)
- BigDecimal 사용:
import java.math.BigDecimal;
BigDecimal bdTotal = new BigDecimal("0.0");
for (int i = 0; i < 1000000; i++) {
bdTotal = bdTotal.add(new BigDecimal("0.000001"));
}
System.out.println(bdTotal);
// 출력: 1.00000000000000000000
- 특수한 값 처리:
double result = Double.POSITIVE_INFINITY;
if (!Double.isFinite(result)) {
System.out.println("무한대 또는 NaN");
}
부동소수점 연산 최적화 기법
- 중간 결과 저장: 연산 과정에서의 중간 결과를 저장하여 반올림 오차를 줄입니다.
- 정밀도 높은 타입 선택: 필요한 경우 double 대신 float를 사용하여 메모리를 절약할 수 있습니다.
- 알고리즘 선택: 가능한 경우 정수 연산을 사용하거나 고정소수점 연산을 고려해봅니다.
정리
부동소수점 연산은 강력하지만 예측하기 어려운 동작을 할 수 있습니다. 특히 금융 계산이나 과학적 계산 등 정확도가 중요한 분야에서는 더욱 주의가 필요합니다. 개발자는 이러한 특성을 이해하고 적절히 다루면 부동소수점 연산의 장점을 최대한 활용하면서도 잠재적인 문제를 회피할 수 있습니다.
'JAVA' 카테고리의 다른 글
JAVA 블록 [코딩백과 with JAVA] (0) | 2024.12.21 |
---|---|
JAVA 표현식 - 명령문 (코딩백과 with JAVA] (0) | 2024.12.21 |
JAVA 표현식 [코딩백과 with JAVA] (1) | 2024.12.21 |
JAVA 비트 연산자, 시프트 연산자 [코딩백과 with JAVA] (0) | 2024.12.21 |
JAVA instanceof 연산자 [코딩백과 with JAVA] (0) | 2024.12.21 |