[C언어] 2의 보수 코딩
[C언어] 2의 보수 코딩
예전에 2의 보수에 대한 post를 작성 한 적이 있습니다. 문득 이 부분을 C언어로 코딩하면 재미있지 않을까 생각되어 한번 C언어로 코딩화 해보는 시간을 가져 봅니다.
1. 10진수를 2진수로 변환
C언어에서는 변수에 어떤 값을 넣더라도 그 값을 printf()문을 어떻게 출력 형식을 취하느냐에 따라서 그 결과를 다양하게 출력 할 수 있습니다. 정수를 "%0"로 취하면 8진수 형태로 출력 되고 "%x"로 취하면 16진수 형태로 출력이 됩니다. 참고로 2진수 형태는 printf()문의 출력형식은 없기 때문에 정수를 2진수 값으로 가정해서 자릿수 값을 출력해보는 코딩을 수작업으로 해보겠습니다.
예)
12 => 00001100
위와 같은 형태로 출력을 하게 만들려면 어떻게 해야 할까요. 12값을 2진수로 잘게 쪼개는 방법은 12을 계속 2로 나눈 몫을 나열하는 방법도 있지만 &연산을 이용하여 쉽게 쪼개는 방법을 취할까 합니다.
1100
&1000
--------
1000
이렇게 &연산자는 AND 연산자로 1과 1일 때 1이 나오고 1과 0일 때는 0이 나옵니다.
그래서 정수 12를 2진수로 출력 되게 하려면 다음과 같습니다.
1000 0000 => 0x80
의 값을 기준으로 12정수에 & 연산을 수행합니다. 총 8자리 비트를 비교해야 하기 때문에 루프문으로 8번 & 연산을 수행합니다. 참고로 각 자리비트를 비교해야 하기 때문에 쉬프트 연산을 별도로 0x80에 취해야 합니다.
1000 0000 => 0100 0000 => 0010 0000 ...
이런식으로 각 자리비트를 만들어서 & 연산을 수행해야 하는데 이 표현을 하려면 쉬프트 연산을 쉽게 표현이 됩니다.
b = 0x80;
b=b>>1;
이렇게 한칸씩 이동시키면 됩니다.
위 내용을 코딩화 하면,
int a=12;
int b=0x80;
int i;
int tmp[8];
for(i=0;i<8;i++){
if(a&b) tmp[i]=1;
else tmp[i]=0;
b=b>>1;
}
[결과]
이렇게 하면 12에 대한 각 자리비트의 1인지 0인지 확인을 통해 tmp[i]에 해당 자리 비트 값을 저장하게 됩니다.
2의 보수 변환
-12을 2의 보수를 취해 음수를 2진수 형태로 출력 해 볼까요.
예) 2의 보수 -12
12 =>
0000 1100
11110011
11110011+0000 0001 = 11110100
위 과정을 C언어로 코딩화 해야 합니다.
12를 2진화 해서 배열변수에 저장합니다.
for(i=0;i<8;i++){
if(a&b) tmp[i]=1;
else tmp[i]=0;
b=b>>1;
}
-12를 2의 보수를 취하기 위해서 1을 0으로 0을 1로 변환
for(i=0;i<8;i++){
printf("%d",tmp[i]);
if(tmp[i]==1) tmp[i]=0;
else tmp[i]=1;
}
마지막으로 +1을 더한다.
for(i=7;i>=0;i--){
if(tmp[i]==1) tmp[i]=0;
else {
tmp[i]=1;
break;
}
}
마지막 +1을 더하는 위 코딩을 자세히 보셔야 합니다. 약간 햇갈릴 수 있습니다. 역순으로 마지막 자리부터 1이면 +1을 하기 때문에 올림수로 계속 순차적으로 1일때는 해당 자리는 최종적으로 0이 되고 1이 올라가고 다음 비트자리가 1 or 0 이냐에 따라서 더하게 됩니다. 그런데 더하는 비트자리가 0이 되면 그 자리는 1이 되고 break 문으로 for문을 빠져 나오게 됩니다.
이렇게 해서 tmp[] 배열 변수에는 -12에 대한 2의 보수를 취한 2진수 값이 저장되게 됩니다.
3. 종합 코딩
이제는 정상적으로 위 과정이 동작하고 결과을 얻는지 확인 해야 겠지요.
[전체소스]
#include <stdio.h>
int main(int argc, char *argv[]) {
int a=12;
int b = 0x80;
int i;
int tmp[8];
for(i=0;i<8;i++){
if(a&b) tmp[i]=1;
else tmp[i]=0;
b=b>>1;
}
printf("%d => \n",a);
for(i=0;i<8;i++){
printf("%d",tmp[i]);
}
printf("\n");
for(i=0;i<8;i++){
printf("%d",tmp[i]);
if(tmp[i]==1) tmp[i]=0;
else tmp[i]=1;
}
printf("\n");
for(i=0;i<8;i++){
printf("%d",tmp[i]);
}
printf("\n");
for(i=7;i>=0;i--){
if(tmp[i]==1) tmp[i]=0;
else {
tmp[i]=1;
break;
}
}
for(i=0;i<8;i++){
printf("%d",tmp[i]);
}
printf("\n");
return 0;
}
위 코딩을 보시면 -12에 대한 2의 보수를 취한 2진수 값을 출력하는 코딩인데 왜 a에 12라는 양수가 저장되어 있냐고 이상하다고 생각하실 수 있습니다. 그 이유는 12라는 숫자를 기준으로 보수를 취하기 때문에 -12를 코딩에서는 선언할 수 없습니다. 1비트씩 쪼개서 배열변수에 넣는 거라서 양수 12를 기준으로 2의 보수를 취해 배열변수에 -12의 결과같을 얻도록 하기 위한 표현임으로 감안하셔서 보시기 바랍니다.
[결과]
마무리
문득 떠오른 2의보수에 대한 C언어 코딩을 해 보았네요. 참고로 전체소스를 보면 꽤 긴 코딩이 이루어졌습니다. 중간 중간 결과를 printf()문으로 출력하다보니 불필요한 코딩이 많아졌는데 최종결과만 출력하게 수정하여 코딩을 줄여서 깔끔하게 정리해서 보시기 바랍니다.
짱짱맨 호출에 응답하였습니다.
짱짱맨 방문에 감사합니다.
즐거운 금요일 보내세요. (dorian-lee의 개발 부계정입니다. 이제 개발 얘기는 여기에 조금씩 쓰고 있어요.)
즐거운 불금이네요. 주말 잘 보내세요.
오랜만에 왔네요 ㅡ ㅡ
넘. 바빠서리 ...
잘 지내시죠
반갑네요.
많이 바쁘셨나봐요.
1의 보수, 2의 보수가 엄청 헷갈리네요. ㅇ_ㅇ 어떻게 구분을 할 수 있나요?
https://steemit.com/kr-dev/@codingman/c--1550796253790
여기 post에 가면 설명이 잘 나와 있어요.
사실 엄청 쉽게 설명해주셨는데 ^^ 제가 부족해서 그런지 몇 번 읽어봐도 잘 모르겠습니다. 좀더 공부하고 자료주신거 보고 다시 이해해봐야겠네요. ㅎㅎㅎ 감사합니다.
1의 보수는
5-3 =2 잖아요
-3 음수를 1의 보수를 해야야
5+(-3)을 만들 수 있는데 1의 보수는 그냥 0을 1로 1을 0으로 변환합니다.
3은 0000 0011 이잖아요 8421코드로 하면요.
이것은 -3음수 1의 보수면 1111 1100 이 되잖아요. 5와 이 1의 보수를 더하면 됩니다.
0000 0101 + 1111 1100 = 1 0000 0001 이 됩니다. 최상이 비트가 1이 올림이 된 상태잖아요.
그 1을 다시 최하위 비트에 더하게 됩니다.
0000 0001 + 0000 0001 = 0000 0010이 됩니다. 이 2진수값을 10진수로 변환하면 2가 나오지요.
이해하셧는지요.
그런데 만약 2-3을 할경우 2 + (-3)을 방금처럼 계산하면 최상위 비트는 올림 1이 안나옵니다. 계산해보시면 아실거에요. 최상이 비트가 0이 된다면 다시 2+(-3) = A라 할때 A를 다시 1의 보수를 취해서 나온 수 1앞에 (-)부호를 붙여 -1로 표기하면 됩니다.
최상위비트 부호 비트라고 생각하시면 돼요.
2의 보수는 1을 0으로 0을 1로 바꾸는 것은 1의 보수가 같지만 추가로 최하위 비트에 +1을 더해주는 것이 2의 보수입니다. 이 수도 더해서 나온 수가 최상위비트가 1이냐 0이냐에 따라서 계산이 1의 보수와 비슷하게 계산이 됩니다.
만약 최상위 비트가 9번째 자리에 1의 올림 수가 나오면 그 1의 수를 버리고 최종 8bit의 값을 10진수로 하면 결과 양의 숫자가 나오고 올림 수가 0이 되면 음수로 2+(-3)=A일 때 A를 2의 보수로 변환하고 앞에 음수를 붙여주면 계산이 끝납니다.
오. 그렇군요. ㅇ_ㅇ 뭔가 대단히 복잡하네요. 사람 입장에서는 쉬운? 뺄셈이 이렇게 복잡하게 돌아가다니... 신기합니다. 그런데 예전에는 뭐 때문에 이렇게 계산했는지 궁금하네요.
컴퓨터 구조 과목에서 가산기를 배울 때 대충 배우게 됩니다.
참고로 컴퓨터 전자기기는 전기신호를 주고 받잖아요. 전기 신호는 뺄셈 음수의 신호는 없어요 전기가 흐르면 1이고 전기가 흐르지 않으면 0이 되는 건 아시잖아요.
애초 전자기기는 뺄샘이란 존재하지 않고 편의상 우리가 인간언어에 가깝게 빼기를 할 뿐이죠.
두 전기 신호가 합쳐서저 나오는 bit계산의 수치 만 존재 할 뿐이죠.
AND, OR, NOT 연산처럼요.
수를 표현할 때도 0과1로 표현하기 때문에 바이트로 해서 절반은 음수라 칭하고 절반은 양수로 칭하잖아요. 이건 인간이 이해하기 위한 해석이고요 그냥 0과1로 표기될 뿐이죠.
잡이야기로 되었지만 그냥 쉽게 전기 신호로 전류가 흐르는 데 뺄셈이 없다는 걸로 이해하시면 돼요. 그래서 계산을 할 때 뺄샘이 아닐 1의 보수 2의보수의 덧셈으로 전기신호를 계산하다고 생각하시면 될 듯요.
하위 언어 계산이라고 보시면 될 듯요. 하드웨어쪽 계산으로 보면 될려나...
아 ~~~~ 비트 연산이니깐 0 1로 표현되니깐 그렇군요. 양자컴퓨터로 바뀌면 그 연산법도 바뀔지도 모르겠네요.