10진수를 2진수로 변환하는 방법은 여러 가지입니다.
1. 비트 연산을 이용한 방법
2. 배열을 이용한 방법
3. 재귀를 이용한 방법
위 세 가지 방법을 제공합니다.
난이도: 배열 > 비트 > 재귀
(필자의 개인적인 의견입니다.)
1. 비트 연산을 이용한 방법
// 10진수 -> 2진수 변환 (반복적 버전: 비트) void ten_to_two(unsigned n) { unsigned a = 0x80000000; // 1000 0000 0000 0000 0000 0000 0000 0000(2) <약 21억> for (int i = 0; i < 32; i++) { if ((a & n) == a) printf("1"); else printf("0"); a >>= 1; } }
a와 n(사용자가 입력한 값)을 and연산해봅시다!
<사용자가 입력한 값: 10 -> 2진수로 1010>
1000 0000 …. 과 1010(n)이랑 and연산하면
0000.. 0000으로 32비트가 모두 0이 나옵니다.
그럼 언제 1이 나올까요?
a가 오른쪽으로 시프트되서 0000….1000이 됐을 때,
1010과 and연산을 하면 1이 나옵니다.
같은 이치로
a가 오른쪽으로 시프트되서 0000….0010이 됐을 때,
1010과 and연산을 하면 1이 나옵니다.
그럼 결국 0000….1010이 나오게 됩니다!
a를 오른쪽으로 시프트했을 때, a의 1의 자리와 n의 1의 자리가 같으면
1을 출력하는 알고리즘입니다.
2. 배열을 이용한 방법
// 10진수 -> 2진수 변환 (반복적 버전: 배열) void ten_to_two_2(unsigned n) { // 동적 배열 생성 int size = 1; int *a = (int*)calloc(sizeof(int)*size); // 배열에 원소 넣기 ex) 11 => 1 1 0 1 (2로 나누고 나머지 값) for (int i = 0; n != 0; i++) { a[i] = n % 2; n /= 2; if (n != 0) { size++; a = realloc(a, sizeof(int)*size); } } // 배열 원소 거꾸로 출력 for (int i = size - 1; i >= 0; i--) { printf("%d", a[i]); } free(a); }
위 방법은 일상생활에서 10진수를 2진수로 바꾸는 방법입니다.
11이 n이라고 가정해봅시다!
11에서 2를 나누면 -> 5…1
5에서 2를 나누면 -> 2…1
2에서 2를 나누면 -> 1…0
1에서 2를 나누면 -> 0…1
위 수식에서 나온 나머지를 거꾸로 쓰면 ‘1011’이고 이는 11의 2진수입니다.
위 방법을 그대로 C언어로 적용하였습니다.
n은 2를 나눈 값으로 계속 바뀌고, 나머지는 배열에 저장됩니다.
3. 재귀를 이용한 방법
// 10진수 -> 2진수 변환 (재귀적 버전) void ten_to_two_j(unsigned n) { if (n < 2) { // n==1 (이전 n이 2이거나 3) printf("%d", n); } else { ten_to_two_j(n / 2); printf("%d", n % 2); } }
위는 배열을 이용한 방법과 거의 유사합니다.
다만 변수 n의 값을 변경하지 않고 재귀함수에 (n/2)을 인수로 넘겼습니다!
로직은 아래 그림을 참고해주세요!!
재귀를 이용하면 별도의 작업없이
가장 마지막 나머지부터 출력한다는 장점이 있습니다!
– Main 함수 및 실행
int main() { unsigned num = 0; printf("-1 입력시 종료됩니다.\n\n"); while (num != -1) { printf("숫자를 입력하세요 \n(4294967295까지 처리 가능): "); scanf_s("%u", &num); printf("\n반복적 버전 : 비트\n"); ten_to_two(num); // 반복적 버전 : 비트 printf("\n\n반복적 버전 : 배열\n"); ten_to_two_2(num); // 반복적 버전 : 배열 printf("\n\n재귀적 버전\n"); ten_to_two_j(num); // 재귀적 버전 printf("\n\n"); } return 0; }