2의 보수를 구하는 다른 방법은 1의 보수의 맨 오른쪽에서 왼쪽 방향으로 0이 나올 때까지 반대로 써주고 나머지는 그대로 써주면 됨.
이진수를 1의 보수로 변환하는 방법
이진수 : 00011000
1의 보수 : 11100111
2의 보수 : 11101000
1의 보수의 맨 오른쪽에서 왼쪽 방향으로 0 이 나올 때까지 반대로 씀.
변수
a[5] : 한 자리씩 입력 받은 이진수 5자리가 저장될 배열
b1[5] : 1의 보수가 저장될 배열
b2[5] : 2의 보수가 저장될 배열
i : 배열의 위치를 지정해주는 변수
c : 자리올림수가 저장될 변수
main() { int a[5], b1[5], b2[5]; // a 이진수, b1 1의 보수, b2 2의 보수 int i, c = 1; // c는 자리올림수 for(i = 0; i < 5; i++) { scanf("%d", &a[i]); b1[i] = 1 - a[i]; // 이진수 각 자리수를 1에서 빼면 1의 보수 } for(i = 5; i >= 0; i--) { b2[i] = b1[i] + c; // 맨 오른쪽 요소부터 자리올림수(1)를 더해 2의 보수를 만듦 b2[i] = b2[i] % 2; // 2진수이므로 해당 2의 보수 자리수가 2를 넘으면 0으로 만듦 c = b1[i] * c; // 자리올림이 발생하는 경우는 현재 자리올림수가 1이고, 1의보수 현재 위치 값이 1인 경우 // 두 수를 곱하면 자리 올림수가 결정됨 } for (int k = 0; k < 5 ; k++) printf("%d", a[k]); // 입력된 이진수 출력 printf(" "); for (int k = 0; k < 5; k++) printf("%d", b1[k]); // 1의 보수 출력 printf(" "); for (int k = 0; k < 5; k++) printf("%d", b2[k]); // 2의 보수 출력}
2의 보수 쉽게 구하기
알고리즘의 이해
2의 보수를 구하는 다른 방법 한 가지는 이진수의 맨 오른쪽에서 왼쪽 방향으로 1이 올때까지 그냥 써주고 나머지는 반대로 써주면 됨.
이진수 : 01100
2의 보수 : 10100
100까진 그대로, 앞 01은 반대로 = 10100
변수
a[5] : 이진수 자료가 저장될 배열, 01010이 저장되었다고 가정
b[5] : 2의 보수가 저장될 배열
i, j : 배열의 위치를 지정해주는 변수
main() { int i, j; int a[5] = { 0, 1, 0, 1, 0 }, b[5]; for (i = 4; i >= 0; i--) { if (a[i] == 1) // 1이 나올 때부터 반대로 바꿈 break; b[i] = a[i]; // 1이 안나오면 그대로 } b[i] = a[i]; // 만난 시점까진 그대로 적어주고 그 다음부터 for (j = i-1; j >=0; j--) b[j] = 1 - a[j]; // 반대로 바꿈 for(int k =0; k < 5;k++) printf("%d", a[k]); // 이진수 출력 printf(" "); for(int k = 0; k < 5; k++) printf("%d", b[k]); // 2의 보수 출력}
2의 보수로 표현된 값의 2의 보수를 구하시오. (보수의 보수 구하기)
알고리즘의 이해
2의 보수의 보수 구하기는 바로 위 문제처럼 구할 수 있지만 여기선 다른 방법 이용.
보수는 음수를 표현할 때 사용.
보수로 표현된 수치에 대한 10진수 값을 알아내려면 보수로 표현된 수치를 다시 보수로 표현해야 함.
위에서 학습한 2의 보수 구하는 과정을 역으로 진행하면 2의 보수에 대한 2의 보수를 구할 수 있음.
즉, 2의 보수는 ‘2진수’ -> '1의보수(0은 1, 1은 0)' -> '2의보수(1의 보수 +1)’ 과정을 통해 구함.
역 과정 ‘2의 보수’ -> ‘1의 보수(2의보수 -1)’ -> '이진수(0은 1, 1은 0)’ 을 통해 2의 보수에 대한 보수, 즉 원래 이진수를 구할 수 있음.
예)
2의 보수 : 11111010
1의 보수로 변환 : 11111001
1의 보수에 대한 1의 보수(2진수)를 구함 : 00000110
10진수로 변환하고 음수 부호를 붙임 : -6
배열의 각각의 요소에 1자리씩 저장된 2진수에서 1을 빼는 과정은 오른쪽에서부터 첫 번째 1이 나올 때까지는 0을 1로 바꿔주고 첫 번째로 나오는 1은 0으로 바꿔줌. 그리고 그 왼쪽부터는 그대로 옮겨줌.
첫 번째 1을 찾고, 첫 번째 1이 나올 때 까지 0을 1로 바꿔주고 1을 0으로 바꿔줌.
맨 오른쪽에서 부터 확인, 첫 번째로 1이 나왔을 때는 감수를 0으로 하여 피감수인 2의 보수를 그대로 1의 보수 배열에 전달.
피감수가 0이고 감수가 1이면 아직 첫 번째로 나온 1이 아니므로 피감수 0을 1로 변환해서 1의 보수 배열에 저장시켜야 함.
1의 보수를 원래의 수로 만든다는 것은 1의 보수를 다시 1의 보수로 표현하면 됨
실기 문제로 2진수를 10진수로 변환하는 문제가 출제 가능,
2진수 첫 번째 비트가 0이면 양수, 그냥 10진수로 변환
2진수 첫 번째 비트가 1이면 음수, 2의 보수로 표현된 것이니 10진수로 변환하고 마이너스를 붙임
변수
a[5] : 한 자리씩 입력 받은 2의 보수 5자리가 저장될 배열
b[5] : 2의 보수의 1의 보수가 저장될 배열
i : 배열의 위치를 지정해 주는 변수
c : 감수가 저장될 변수
#include <stdio.h>#include <math.h>main() { int a[5], b[5]; int i, c; for (i = 0; i <= 4; i++) scanf("%d", &a[i]); // 2의 보수를 입력 받음 c = 1; // 초기 감수값을 1로 지정 for (i = 4; i >= 0; i--) { b[i] = a[i] - c; // 2의 보수에 1을 빼면 1의 보수 if (a[i] == 0 && c == 1) // 2의 보수가 1을 안만났다면 감수 1로 유지, 만나면 0으로 바꿈. c = 1; else c = 0; b[i] = abs(b[i]); // 감수를 빼서 -1일 때 1로 바꿔줌. } for (i = 0; i <= 4; i++) // 1의 보수의 1의 보수는 이진수 b[i] = 1 - b[i]; for (int k = 0; k <= 4; k++) printf("%d", a[k]); // 2의 보수 출력 printf(" "); for (int k =0; k <= 4; k++) printf("%d", b[k]); // 이진수 출력}
0 또는 1로 입력되는 다섯 개의 숫자를 배열에 입력 받아 그레이 코드 또는 이진수로 변환하시오.
(그레이 코드 변환하기)
알고리즘의 이해
그레이코드 : 이진법 부호의 일종으로, 연속된 수가 1개의 비트만 다른 특징을 지님. 연산에는 쓰이진 않고 주로 데이터 전송, 입출력 장치, 아날로그-디지털 간 변환가 주변장치에 쓰임.
xor연산 : 연산하는 두 개의 값이 같으면 0, 다르면 1을 출력
이진수를 그레이 코드로 변환하기
첫 번째 그레이 비트는 이진수 비트를 그대로 내려쓰고, 두 번째 그레이 비트부터는 변경할 이진수의 해당 번째 비트와 그 왼쪽 비트를 xor연산하여 씀. (이진수만 xor 연산)
이진수 1011을 입력 받았다면?
그레이코드 : 1110
첫 번째 비트 그대로 씀, 그리고 이진수 오른쪽에 있는 해당 번째 비트와 xor연산
그레이 코드를 이진수로 변환하기
첫 번째 이진수 비트는 그레이 비트를 그대로 내려 씀, 두 번째 이진수 비트부터는 왼쪽에 구해 놓은 2진수 비트와 변경할 그레이 코드의 해당 번째 비트를 xor연산해서 씀. (이진수와 그레이비트 xor)
그레이코드 1001을 입력 받았다면?
이진수 : 1110
변수
input[5] : 한 자리씩 입력 받은 이진 자료가 저장될 배열
cont[4] : 이진수나 그레이 코드로 변환된 자료가 저장될 배열
i : 배열의 위치를 지정해주는 변수
조건
배열의 첫 번째 비트가 0이면 나머지 네 개의 비트는 이진수므로 그레이 코드로 변환하여 출력
배열의 첫 번째 비트가 1이면 나머지 네 개의 비트는 그레이코드이므로 이진수로 변환하여 출력
#include <stdio.h>main() { int i; int input[5], cont[4]; printf("숫자 5개 입력, 첫번째가 숫자가 0이면 이진수->그레이코드, 1이면 그레이코드->이진수 : \n"); for (i = 0; i <= 4; i++) { scanf("%d", &input[i]); } cont[0] = input[1]; // 첫 번째 비트는 그대로 가고 if (input[0] == 1) { // 그레이코드 -> 이진수 for (i = 0; i <= 2; i++) { if (input[i + 2] == cont[i]) // 그레이코드 비트와 이진수 옆 비트 xor연산 cont[i + 1] = 0; else cont[i + 1] = 1; } } else { // 이진수 -> 그레이코드 for (i = 0; i <=2; i++) { if (input[i + 1] == input[i + 2]) // 이진수 비트끼리 xor연산 cont[i + 1] = 0; else cont[i + 1] = 1; } } if (input[0] == 1) printf("이진수 "); else printf("그레이코드 "); for (i = 0; i <= 3; i++) printf(" %d ", cont[i]);}
100건 이내의 12자리로 구성된 숫자를 더하는 순서도를 작성하시오. (큰 수 더하기 - 10진수 더하기)
단, 12자리의 숫자는 각 자리가 분리되어 배열에 입력됨. 예를들어 999,999,999,999라면 999999999999와 같이 입력됨.
단, 배열의 첫 번째 요소로 0을 입력 받으면 계산 후 결과를 출력하고 프로그램을 종료한다.
단, 결과 값이 들어갈 배열에는 초기값으로 0이 들어 있다고 가정한다.
알고리즘의 이해
정수의 범위에서 벗어나는 큰 수를 더하면 실수로 계산되어 오차가 발생.
이런 경우 각각의 자릿수를 분리하여 덧셈하면 아무리 큰 수라도 자릿수에 관계없이 오차가 발생하지 않게 계산 가능.
예를 들어 987 + 999를 각각의 자릿수를 분리하여 자릿수끼리 더하면
9 8 7
9 9 9
18 17 16 // 1을 하나씩 올림
여기서 16은 그냥 16, 17은 170, 18은 1800이 됨.
10을 윗자리로 올려서 6, 18
10을 다시 윗자리로 올려서 8, 19
10을 다시 윗자리로 올려서 9가 되고 윗자리 1이 됨.
1 9 8 6
이 원리를 이용하면 아주 큰 정수를 오차 없이 더할 수 있음.
변수
a[12] : 입력 받은 숫자를 각각의 자리로 분리하여 저장할 배열, 즉 253을 입력 받으면 a[1]에 2, a[2]에 5, a[3]에 3을 각각 저장
b[14] : a배열에 저장된 숫자를 각각의 자릿수별로 누적할 배열, 100건 이내의 자료를 누적하므로 a배열보다 자릿수가 2자리 많음. b 배열에는 초기 값으로 0이 들어 있음.
i : 배열의 위치를 지정해 주는 변수
j : 배열의 시작 위치를 지정해 주는 변수
mok : 배열 각 자리에 있는 값을 10으로 나눈 몫이 저장될 변수
nmg : 배열 각 자리에 있는 값을 10으로 나눈 나머지가 저장될 변수
#include<stdio.h>main() { int i, j, mok, nmg; int a[12], b[14] = { 0 }; // 문제에서 결과값이 저장될 배열 b, 초기값 0으로 초기화 while (1) { for (i = 0; i <= 11; i++) scanf("%d",&a[i]); // 숫자 하나씩 입력 if (a[0] == 0) // 0을 a[0]에 입력받으면 입력 중지 break; else for (i = 0; i <=11; i++) // 입력받은 값을 b에 저장, 자릿수가 올라갈 수 있어서 앞 2자리 비워둠 b[i + 2] += a[i]; } for (i = 13; i >= 1; i--) { mok = b[i] / 10; nmg = b[i] - mok * 10; // 각 칸별로 10으로 나눔, 몫을 윗자리에 더함 b[i] = nmg; // 나머지만 남김 b[i - 1] += mok; } if (b[0] == 0) // b[0] 첫자리가 0이라면(수가 크지 않으면) j = 1; // 출력을 위해 사용하는 인덱스 j를 1로 바꿈 else // 입력된 수가 커서 첫 자리부터 수가 시작되면 j를 0으로 가리킴 j = 0; for (i = j; i <= 13; i++) printf("%d ", b[i]);}
배열 x(10)과 y(10)에 이진수가 각각 입력되어 있다. 두 이진수의 덧셈 결과를 이진수 형태로 출력하는 순서도를 작성하되 덧셈의 결과 MSB(최상위 비트)에서 올림수가 발생하면 “OVERFLOW!!”를 출력한다.
(이진수 더하기)
알고리즘의 이해
최상위 비트는 맨 왼쪽의 비트를 말함. 맨 왼쪽의 비트에서 자리올림이 발생하면 자리올림수를 저장할 공간이 없기 때문에 overflow 출력.
overflow : 연산의 결과값이 기억 용량을 초과하여 넘쳐나는 상태
한 자리 이진수 세 개를 더할 때 결과가 10이면, 합이 10이 아니고 합은 0, 자리 올림수가 1
이진수를 덧셈할 때는 각각을 분리해서 각각의 배열에 넣은 다음 오른쪽 끝에서 왼쪽 방향으로 진행하면서 한 자리씩 더하면 됨.
오른쪽에서 왼쪽으로 진행하는 이유는 자리올림을 고려해야 하기 때문. 각각의 자리를 더할 때 결과가 2 이상이면 자리올림이 발생한 것.
자리올림수를 그 왼쪽의 자리를 덧셈할 때 같이 더해줌
변수
b1[10], b2[10] : 덧셈할 이진수가 저장되어 있는 배열
a[10] : 덧셈의 결과가 저장될 배열
z : 자리올림수 발생 여부를 판단하기 위한 변수
c : 자리올림수가 저장될 변수
j : 배열의 위치를 지정해 주는 변수
main() { int i, z, c, j; // c는 자리올림수, z는 자리올림수 발생 여부 판단하는 변수 int b1[10], b2[10], a[10]; // 입력받을 2진수 배열 두개 b1, b2, 합을 저장할 배열 a for (i = 0; i <= 9; i++) scanf("%d", &b1[i]); for (i = 0; i <= 9; i++) scanf("%d", &b2[i]); z = 0, c = 0, j = 9; // 배열의 끝위치를 지정할 첨자 j.(이진수의 맨 우측부터 합할테니까) do { z = b1[j] + b2[j] + c; if (z < 2) { // 배열 한칸의 합 + 자리올림수 가 2보다 작으면 그냥 저장 c = 0; a[j] = z; } else { // 2보다 클 경우 c = 1; a[j] = z - 2; // 2진수 이므로 자리올림수를 뺀 나머지를 저장 } j--; } while (j >= 0); if (c == 0) { do { j++; printf("%d", a[j]); } while(j < 9); } else // 자리올림수 c 가 1일 경우 배열의 크기를 초과하므로 오버플로우 출력 printf("OVERFLOW!!");}