본문 바로가기

Programming/Programming 지식

실수 연산시 유의점

프로그래밍에서 실수 연산을 할 때, 종종 생각하던 것과 다른 값이 나오는 경우를 보신적이 있으실겁니다.

흔한 예를 들면 10 / 3을 소수점까지 표현하도록 계산하면 3.3333333…이 된다고 생각하실 것 같습니다. 하지만 컴퓨터는 3.33333….35라는 결과를 출력합니다.

public class BlogData {

	public static void main(String[] args) {
		double d1 = 10;
		double d2 = 3;
		
		System.out.println(d1 / d2);
	}
}

[ 10 / 3의 실수연산 ]

누군가는 적당한 자리에서 올림하거나 내림한 경우가 아니냐고 말씀하실 수도 있을것 같습니다. 물론 일상생활에서도 무한하게 이어지는 숫자를 특정한 자리에서 올림하거나 내림하는 경우는 드물지 않습니다. 하지만 왜 마지막 자리가 내림한 3도 아니고, 올림한 4도아닌 5일까요

 

이런 경우는 실수의 연산에서 더 자세하게 볼수 있습니다. 아래의 예시를 보면서 확인해보면

public class BlogData {

	public static void main(String[] args) {
		//실수의 연산 1
		double d1 = 1 - 0.25;
		double d2 = 0.75;
		
		if(d1 == d2) {
			System.out.println("d1과 d2의 값은 같습니다!");
		}else {
			System.out.println("d1과 d2의 값은 다릅니다!");
		}
		
		//실수의 연산 2
		double d3 = 1 - 0.71;
		double d4 = 0.29;
		
		if(d3 == d4) {
			System.out.println("d3과 d4의 값은 같습니다!");
		}else {
			System.out.println("d3과 d4의 값은 다릅니다!");
		}
	}
}

 

위의 코드를 보면 d1과 d2는 둘다 0.75일 것이고, d3와 d4는 둘다 0.29일 것입니다. 그렇다면 실수의 연산 1, 2의 결과는 둘다 값이 같다는 결과가 나와야 합니다. 하지만 실제 코드 수행 결과를 확인하면 두 결과값은 서로 다릅니다.

 

같은 느낌, 다른 결과

위와 같은 결과가 나오는 것을 확인할 수 있습니다. 두 결과의 차이가 나는 이유는 컴퓨터가 값을 저장할 때, 2진수로 변환하여 계산하기 때문에 이런 차이가 발생하게 됩니다. 확인을 위해 테스트로 위의 데이터를 2진수화 해보겠습니다.

 

실수의 2진수 변환 과정은 다음과 같습니다.

 1. 변환할 실수에 2를 곱하고, 결과값이 1보다 크다면 1의 자리의 수를 넘겨줍니다.

 2. 남은 소수점 아래 자리의 수가 0이 아니라면 다시 2를 곱하고, 위의 과정을 반복합니다.

 

설명이 쉽지 않네요. 실제로 위의 값을 가지고 해보도록 하겠습니다.

 1) 0.75를 2진수로 변환

   0.75 * 2 = 1.5 이므로 1을 넘기면 0.5가 남습니다.

   0.5 * 2 = 1.0 이므로 1을 넘기면 0이 남습니다. (남은 수가 0이므로 계산 종료)

   => 0.75는 0.11(2)입니다.

   

   그럼 검산을 해볼까요?

   0.11(2) = (1/2 * 1) + (1/4 * 1) = 3/4 = 75/100 = 0.75(10)

   계산이 맞은걸 확인 했으니 다음으로 d3, d4의 값을 2진수 변환 해보겠습니다.

 

 2) 0.29를 2진수 변환

   0.29 * 2 = 0.58 이므로 0을 넘기면 0.58이 남습니다.

   0.58 * 2 = 1.16 이므로 1을 넘기면 0.16이 남습니다.

   0.16 * 2 = 0.32 이므로 0을 넘기면 0.32가 남습니다.

   0.32 * 2 = 0.64 이므로 0을 넘기면 0.64가 남습니다.

   0.64 * 2 = 1.28 이므로 1을 넘기면 0.28이 남습니다.

   0.28 * 2 = 0.56 이므로 0을 넘기면 0.56이 남습니다.

 

혹시 눈치 채셨는지 모르겠지만 소수점 2번째 자리의 수가 8, 6, 2, 4, 8순으로 반복되는 것을 알수 있습니다. 이 말은 이 수는 무한으로 반복될것이라고 이해할수 있을 것 같습니다. 이런경우 같은 값이지만 같은 값이 아닌 상황이 발생하게됩니다. 때문에 우리는 딱 떨어진 수를 주었지만 컴퓨터는 다른 결과값을 저장하는 경우가 발생할 수 있습니다.

 

위와 같은 이유로 switch( ) ~case 구문에서는 double형의 사용을 금지하고 있습니다. 위의 경우와 같이 전혀 다른 값이 발생할 가능성이 높기 때문입니다. 그러므로 실수형의 연산시에는 각별히 유의해야 골때리는 버그를 좀 덜 볼수 있을 것 같습니다.^^

 

 

'Programming > Programming 지식' 카테고리의 다른 글

Selection Sort(선택정렬)  (0) 2020.04.23