본문 바로가기
C++/기초

C++ 기초 : 실수형 자료형

글: 시플마 2024. 2. 6.

정수 같은 경우 그 값에 해당하는 비트값이 명확하게 존재합니다. (2는 100, 8은 1000, 11은 1011)

이번에는 실수를 생각해 봅니다. 0과 1 사이에 얼마나 많은 수가 존재할까요? 

0.1, 0.2, 0.23, 0.4355... 컴퓨터에서 사용할 수 있는 비트 수는 한정적이기 때문에 표현하기에는 너무 많은 수입니다.

그래서 컴퓨터에서는 근삿값을 찾아 이를 표현합니다. 이러한 표현 방식을 부동소수점 방식이라고 합니다.

 

예를 들어 십진수 21.8125를 이진수로 표현해 보겠습니다.

소수점 앞에 21은 정수이므로 정확하게 이진수로 표현할 수 있습니다. 10101입니다.

소수점 이하 0.8125는 약간 복잡합니다.

 

우선, 이해를 위해 우리가 십진수에서 계산할 때를 보겠습니다. 52.1이라는 수가 있을 때

빨간 부분이(십의 자리) 10개 모여야 백 단위 수로 올라갑니다. 

마찬가지로 파란 부분이(일의 자리) 10개 모여야 십 단위 수로 올라갑니다.

초록 부분(소수 첫째 자리)도 10개가 모여야 소수점 앞 일의 자리 수를 올릴 수 있습니다.

결론은 십진수에서 십의 자리와 일의 자리는 1/10의 관계이며 일의 자리와 소수 첫째 자리도 1/10의 관계입니다.

그렇다면 이진수에서는 앞의 자리와 뒤의 자리의 관계는 1/2의 관계일 것입니다. 

 

이진수에서 계산할 때를 보겠습니다. 10101.111이라는 수가 있을 때

빨간 부분이 2개 모여야 소수점 앞에 수가 1이 될 것입니다. 십진수로 표현하면 0.5(2의 -1제곱)겠죠.

파란 부분이 2개 모여야 소수 첫째 자리가 0.5가 될 것입니다. 0.25가 두 개 모이면 되겠죠?

파란 부분은 0.25(2의 -2제곱)에 해당합니다.

초록 부분 2개 모여야 소수 둘째 자리가 0.25가 되겠죠?

초록 부분은 0.125(2의 -3제곱)에 해당할 것입니다.

 

다시 돌아가서 21.8125에거 소수점 이하를 이진수로 표현하겠습니다.

10101.1 소수점 첫째 자리는 1입니다.(0.5)

10101.11 소수점 둘째 자리는 1입니다.(0.25)

10101.110 소수점 셋째 자리는 0입니다.(0)

10101.1101 소수점 넷째 자리는 1입니다.(0.0625)

각 자리에 해당하는 십진수 값을 다 더하면 0.5 + 0.25 + 0 + 0.0625 = 0.8125가 나오는 것을 확인할 수 있습니다. 

즉, 21.8125를 이진수로 표현하면 10101.1101입니다.

 

여기서 끝이 아닙니다.

이를 32비트 컴퓨터 메모리에서 어떻게 표현되는지 알려면 정규화(소수점을 가장 앞자리로 보내는 것)를 해야 합니다.

십진수로 예를 들면 100은 0.1 x 10^3으로 표현할 수 있습니다.

10101.1101을 정규화 하면 0.101011101 x 2^5입니다. 

 

이를 이제 메모리(32bit) 상에서 어떻게 표현하는지 살펴보겠습니다.

 

 

실수를 표현할 때 메모리의 할당되는 비트 상황 (출처 : 위키백과)

 

0.101011101 x 2^5

양수이므로 부호부(1bit)에는 0이 들어갑니다.

지수 부분(8bit)은 양수이므로 가장 앞 비트에 0이 들어가고 나머지 7개 비트에 5가 들어가면 됩니다. (00000101)

가수 부분(23bit)은 소수점 이하 부분이 들어가면 됩니다.(10101110100000000000000)

 

즉, 21.8125를 메모리 상에서 표현하면 0 00000101 10101110100000000000000 입니다.

 

 


 

마찬가지로 컴퓨터에서 0.721544321라는 실수를 표현하려 합니다.

소수점 첫째 자리에 1이 들어감으로써 0.5를 확보했습니다.

소수점 둘째 자리에 1을 넣는다면 0.75가 되어 표현하려는 0.72...를 넘습니다.

결국 둘째 자리에는 0이 들어가야 하고 뒤에 남은 비트들로 최대한 0.721544321에 가까운 수를 얻어내야 합니다.

근데 0.721544321이라는 값이 딱 맞게 나올 것이라는 보장이 없습니다.

정확한 값이 나오면 좋겠지만 그렇지 않다면 비트를 많이 사용할수록 

정교한 값이 나오고 0.721544321에 가까워질 것입니다.

이것이 4byte인 float보다 8byte인 double이 정밀한 표현이 가능한 이유입니다.

 

컴퓨터에서 실수는 어디까지나 근삿값을 찾아 표현하는 것입니다.

따라서 실수와 정수와 비교해서 결과를 내는 코드나 실수와 정수를 연산하는 코드에서

생각하지 못한 결과가 나올 수 있다는 것을 명심해야 합니다.

 

특히 정수와 실수를 연산하여 정수 타입 변수에 넣는 경우

실수를 정수로 변환하는 과정을 거쳐 정수 타입 변수에 넣게 됩니다.

(반대로 실수 타입 변수에 넣을 경우, 정수를 실수로 변환하고 연산하게 됩니다.)

이는 불필요한 과정 하나를 더 거치므로 효율적이지 않은 코드입니다.

 

만약 실수와 정수를 연산해야 하는 상황이라면 아래 코드처럼 변환하는 과정을 명시해 주는 것이 좋습니다.

 

 

서로 다른 타입의 수를 연산할 때는 변환하는 타입을 명시해 주는 것이 좋다.

 

 

물론 명시한다고 하여 변환 과정을 생략하여 효율을 높여 주는 것은 아닙니다.

하지만 명시함으로써 코드를 작성한 사람이 의도적으로 계산했음을 알려주는 것이죠.

 

 

 

강의 출처 : https://www.youtube.com/watch?v=PFc4g8mxOiI&list=PL4SIC1d_ab-aOxWPucn31NHkQvNPHK1D1&pp=iAQB


 

'C++ > 기초' 카테고리의 다른 글

C++ 기초 : 논리 연산자  (0) 2024.02.09
C++ 기초 : 증감 연산자  (0) 2024.02.06
C++ 기초 : 산술 연산자  (0) 2024.02.06
C++ 기초 : 정수형 자료형  (0) 2024.02.02
C++ 기초 : 자료형  (0) 2024.02.01