『Lena's by ☆볶기!!』: Restart !!

Rorolena
[C/C++] 4. 데이터 표현의 방식
3번째 프로그래밍 포스팅이 찾아왔습니다.
이번 포스팅에선 C언어의 총채적인 데이터의
표현방법에관해서 설명을 늘어놓아 볼까 합니다.
실제 코딩에 이르기까지

한 5~6번째 포스팅까진 지루한
이론이 주욱 나열되니 인내를 다지시길 권고하는 바입니다.

[컴퓨터가 데이터를 표현하는 방식]

컴퓨터는 2진수를 기반으로 데이터를 표현하고 연산도 진행합니다.
따라서 2진수를 이해해야 C언어를 보다 정확히 이해할 수 있습다.

1. 2진수란 무엇인가? 더불어 10진수, 16진수란 무엇인가?

먼저 2진수란 두가지 기호를 이용하여 데이터를 표현하는 방식을 말합니다.
10진수와 16 진수또안 마찬가지로 각각 10과 16가지의 기호로 데이터를 표현 하는 방식인대
여기서 말하는 바는 n진수 즉 n은 데이터를 표현하는데 사용하는 기호의 개수를 의미합니다.

2. 데이터의 표현단위인 비트(bit)와 바이트(byte)

비트란 컴퓨터가 표현하는 데이터의 최소단위로써 2친수 값
하나를 저장할 수 있는 메모리의 크기를 뜻 하는 단위입니다.
이를 8개로 묶으면 바이트라는 단위가 됩니다.

3. 8진수와 16진수를 이용한 데이터 표현

C언어는 10진수 이외에 8진수와 16진수의 데이터 표현도 가능합니다.
따라서 변수 선언 후에 10진수 외의 값도 대입 할수 있는대 아래 와같이 사용합니다.

int num1 = 10;
int num2 = 0xA;
int num3 = 012;

// 진법 변환에 관한 내용입니다.
각각 10, 8, 16 진수로 변환하는 방법을 소개하겠습니다.

첫번째: 2, 8, 16진수를 10진수로 바꾸는 방법입니다.
최하위 수부터 진수^(n-1)을 곱한후 이를 전부 다하면됩니다.
가령 101110 이라는 2진수가 있으면
2^5 + 2^3 + 2^2 + 2^1와같이 계산하면 10진수를 구할수 있습니다.

두번째: 10진수를 2, 8, 16진수로 바꾸는 방법입니다.
10진수에서 각각의 진수로 변환 하는 방법은 쉽습니다.
가령 273이란 숫자를 2진수로 변환하면 아래와 같이 나누면
273/2 ... 1
136/2 ... 0
68/2 ... 0
34/2 ... 0
17/2 ... 1
8/2 ... 0
4/2 ... 0
2/2 ... 0
1

100010001 이라는 수를 얻을수 있습니다.
마찬가지로 다른 진수도 해당진수로 나누면 값을 구할수 있습니다.

세번째: 2, 8, 16진수를 각각 서로 바꾸는 방법입니다.
이경우은 계산이 아주 용이한대 이는 다음과같습니다.
2진수를 8과 16진수로 바꾸려면 최하위 수부터
각각 3과 4자리로 끈어서 그수를 바로 바꿔 쓰면 되며
반대의 경우도 각각 3과 4자리로 끈어 2진수로 바꿔 써주면 됩니다.

[정수와 실수의 표현방식]

우리는 컴퓨터가 데이터를 2진수로 표현한다는 사실을 알았지만
정수, 실수, 문자와 같은 데이터를 2진수로 어떻게 표현하는지 잘 모르고 있습니다.
이번 장에서는 이를 소개하고자 합니다.

1. 정수의 표현방식

컴퓨터가 정수와 실수 그리고 문자를 표현하는 방식에는
확실한 차이가 있는데 먼저 정수의 표현방식에 대해 설명 하겠습니다.
C언어는 보통 하나의 정수를 4바이트로 표현하지만
여기서는 1바이트를 기준으로 설명해 보겠습빈다.

- 정수의 가장 왼쪽에 존재하는 비트는 '부호비트'입니다.
컴퓨터는 각 수가 양수인지 음수인지를 표기하여 식별합니다.
즉 00000001은 양수 10000001은 음수가 되며 이를 MSB라합니다.
이는 Most Significant Bit의 약자로서 가장 중요한 비트라는 뜻을 지닙니다.

- 음의 정수를 표현할 때에는 2의 보수를 취해야 합니다.
앞의 부호 설명을 빌려 생각보면 음수를 표현할때는
음수 부호만 바꾸면 되지 않을 까 생각을 해봅니다만
아쉽게도 음의 정수를 표현할 때에는 2의 보수를 취해야 합니다.

예를들어보면
양수 00001101과 10001101을 더하면
0이 나와야 하지만 실재로는 10011010이 될뿐 입니다.

그럼 음수는 어찌 만드냐 는 아래와 같습니다.
00001101를 1의 보수를 취해줍니다.
11110010을 1을 더해주면
11110011와 같이 나옵니다.
이는 00001101의 양수로써
실재 더하면 0이나옵니다.

11110011
00001101
100000000 // 8비트기 때문에 8자리 밖의 수가 잘리면
00000000 // 0이 완성되며 이를 2의보수를 취하였다 합니다.

2. 실수의 표현방식

컴퓨터가 실수를 표현하는 방식은 조금 복잡합니다.
그러나 걱정하지 말고 여기서는 표현 방식만 이해하면됩니다.

- 실수를 표현하는 기본방식
일단 실수를 어찌 표현해볼지 2바이트로 상상을 해봅시다.
통상 사람들은
부호 소수점이상 소수점이하
  1        0000001    00000101
이런식으로 생각할수 있으나
이는 표현할수 있는 실수가 적어서
명백히 사고적 오류입니다.

그럼 어찌 표현을 해야하냐는 ±(1.m)×2^e-127이 공식에서 출발합니다.
이를 바꿔보자면 아래와같이 표현할수 있습니다.

부호 ┌─E─┐ ┌─ M─┐
  1      0000001    00000101

- 컴퓨터가 실수를 표현하는 방식에는 오차가 존재한다.
위의 방식대로 연산하면 확실히 표현할수 있는 실수가 매우 넓어집니다.
하지만 이방식이 정확한 실수를 표현하는것은 아닙니다.
이방식은 모든 실수를 표현할수 없습니다.
이는 가장 대표적예로 2^e-127에서 발생하는대
이 연산은 절때 0을 만들수 없습니다.

이를 가리켜 부동 소수점 오차라 하는대
즉 우리가 보는 실수는 아주 가까운 근사치를 보여줄 뿐입니다.
이는 아래의 소스를통해 확인할수 있습니다.

int main(void)
{
int i;
float num = 0.0;

for(i=0; i<100; i++)
num += 0.1;

printf("0.1을 100번 더한 결과: %f \n", num);
return 0;
}



[
비트 연산자]

앞장에서 소개하지 못한 비트 연산자를 소개하겠습니다.
비트 연산자는 주로 하드웨어 관련 프로그래밍에서 주로쓰지만
C에서도 프로그램의 여러 최적화를 목적으로 사용됩니다.

&: num1 & num2 비트단위로 AND 연산을 한다.
|: num1 | num2 비트단위로 OR 연산을 한다.
^: num1 ^ num2 비트단위로 XOR 연산을 한다.
~: ~num1 단항 연산자로서 피연산자의 모든 비트를 반전시킨다.
<<: num<<2 피연산자의 비트 열을 왼쪽으로 이동시킨다
>>: num>>2 피연산자의 비트 열을 오른쪽으로 이동시킨다

위 내용중 <<와 >> 연산자는 비트 이동 연산자라 해서 비트 연산자와는 성향이 다르나
흔히 비트 연산자의 범주에 포함시켜 이야기하기때문에 알아 두기 바랍니다.

1. &연산자: 비트단위 AND
& 연산은 두 개의 비트가 모두 1일 때 1을 반환하는 연산이며 다음과 같습니다.

0 & 0 0을 반환
1 & 0 0을 반환
0 & 1 0을 반환
1 & 1 1을 반환

2. |연산자: 비트단위 OR
| 연산은 두 개의 비트 중 하나라도 1이면 1을 반환하는 연산이며 다음과 같습니다.

0 | 0 0을 반환
1 | 0 1을 반환
0 | 1 1을 반환
1 | 1 1을 반환

3. ^연산자: 비트단위 XOR
^ 연산은 두 개의 비트가 서로 다른 경우에 1을 반환하는 연산이며 다음과 같습니다.\

0 ^ 0 0을 반환
1 ^ 0 1을 반환
0 ^ 1 1을 반환
1 ^ 1 0을 반환

4. ~연산자: 비트단위 NOT
~ 연산은 비트를 0에서 1로, 1에서 0으로 반전시키며 다음과 같습니다.

~0 1을 반환
~1 0을 반환

5. << 연산자: 비트의 왼쪽 이동(Shift
)
<< 연산자는 두 개의 피연산자를 요구하며 다음의 의미를 갖습니다.

num1 << num2 num1의 비트 열을 num2칸씩 왼쪽으로 이동시킨 결과를 반환
8 << 2 정수 8의 비트열을 2칸씩 왼쪽으로 이동시킨 결과를 반환

여기서 주목할점이 하나 있는대
비트의 열을 왼쪽/오른쪽으로 1칸씩 이동시킬 때마다 정수의 값이 두배씩 차이납니다.
이는 꼭 기억 할필요가 있는대 곱겜과 나눗셈 연산을 사용하지 않고도
동일한 효과를 준다는것은 바로 성능의 향상으로 이어진다는 사실입니다.

6. >> 연산자: 비트의 오른쪽 이동(Shift)
>> 연산자와 << 연산자의 가장 큰 차이점은 비트열을 이동시키는 방향에 있습니다.
가령 00001111을 오른쪽으로 2번 이동시키면 00000011이 됩니다.
여기서 정수라면 정상적으로 2찬을 이동하며 끝을 00으로 채웁니다.
하지만 음수는 이야기가 달라질수 있는데

CPU의 종에따라서 0을 채우기도하고 음수유지를위해 1을 채우는 CPU도 있습니다.
다음코드로 테스트를 해보도록 합시다. (필자는 결과값이 -4, -2가 나왔습니다.)

int main(void)
{
int num = -16;
printf("%d \n", num>>2);
printf("%d \n", num>>3);
return 0;
}

이번 포스팅인
비교적 짧게 끝난것 같습니다.

음 앞으로 상수와 기본 자료형과
표준 입출력에 관한것까지 대략적
이론설명이 주욱 이어지면
그다음부턴 소스를통해
간략한 설명 만으로 내용을
진행할 예정입니다.

이점 양해하시고 인내하시기 바랍니다.