(초보)C언어 이진수로 바꿔 출력하기
안녕하세요 가입하고 첫글입니다.
프로그래밍을 공부하고 있습니다.
알고리즘 책을 보기 시작했는데, 숫자를 입력 받아서 이진수로 바꿔서 출력하라고 합니다.
처음에는 이렇게 해보았습니다.
int input = 0; scanf("%d", &input); //역순으로 출력되는 문제가 있음 do { printf("%d", input & 0x01); input = input >> 1; } while (input > 0); printf("(2)\n");
input에 입력 받은 후에 0x01과 &를 해서 가장 오른쪽 비트를 출력하고, input을 오른쪽으로 쉬프트해주고... 하는 식입니다.
이렇게 했더니 1100(2) 이어야 하는 결과가 0011(2) 으로, 100(2) 이어야 하는 출력 결과가 001(2) 이런 식으로 거꾸로 출력되는 문제가 생겼습니다.
그래서 이렇게 고쳐봤습니다.
int input, temp, temp2 = 0; do { temp = temp + ( (int)pow(10, temp2) ) * ( input & 0x01 ) ); input = input >> 1; temp2++; } while (input > 0); printf("%d(2)\n", temp);
지저분하죠? ^^; temp변수는 출력 결과를 저장하게 되는 변수이고, temp2는 자리수를 저장하는 변수입니다.
지금 생각해보니 꼭 저렇게 하지 않아도 되겠네요.
아무튼 일의자리는 10의 0제곱, 십의자리는 10의 1제곱, 십의자리는 10의 2제곱... 이라는 점을 생각했습니다.
그래서 pow() 함수를 사용했구요. temp변수에는 하나 하나 결과로 출력할 값이 저장되어 갑니다.
그런데 문제가 생겼습니다. pow()함수가 정확한 답을 안 돌려주더군요. 1, 10, 99, 1000, 9999,... 이런 식으로 값을 돌려주는 것을 확인했습니다.
꼼수를 써서
temp = temp + ( (int)(pow(10, temp2) + 0.1 ) * ( input & 0x01 ) );
이렇게 고치니 결과는 잘 나옵니다만, 지금은 10의 제곱의 간단한 연산이라 문제가 안 되도, 나중에는 이 오차 때문에 문제가 될 일이 있겠다 싶습니다.
질문 요약 1) pow() 함수의 오차는 왜 생기고 어떻게 해결해야 하나요?
질문 요약 2) 이진수로 출력하는 함수는 어떻게 만드는 것이 아름다운 것인지 궁금합니다. ^^; 답지 같은게 없어서요.
pow함수 오차는 부동소숫점 연산에서 나오는
pow함수 오차는 부동소숫점 연산에서 나오는 자연스러운 오차일겁니다.
http://kldp.org/node/132646
http://kldp.org/node/133158
일단 그건 나중에 해결하고요. 아님 해결 못할 것 같긴 하네요.
이진수로 출력하는 함수라면. 저라면 그냥 2로 나누면서 만들 것 같은데요
피할 수 있을때 즐겨라! http://melotopia.net/b
pow()를 써서 하실 수 있다면 (뭐 실제로는 오차
pow()를 써서 하실 수 있다면 (뭐 실제로는 오차 때문에 뜻대로 나오진 않았지만)
그냥 그 자리에 1, 10, 100, 1000 순으로 증가하는 변수를 하나 쓰시면 되겠네요. 1로 초기화하고 루프마다 10곱하면 되니까.
그렇지만 이 구현은 별로 좋아보이지 않는 것이, int 타입 변수로는 기껏해야 10자리까지밖에 표현을 못하겠네요. 2진수로 10자리면 1024 정도까지밖에.
- char의 배열을 넉넉히 잡고 2로 나누면서 1또는 0을 배열 원소에 채워나간 후에 역으로 출력
- 재귀호출 (2로 나눈 몫을 대상으로 재귀호출을 하고, 재귀호출에서 복귀한 후에 2로 나눈 나머지를 출력)
- 본문 코드에서 0x01과 &를 수행했는데, 그러지 말고 &의 대상을 처음에는 제일 왼쪽 비트 (1<<31), 그 다음은 그 옆 비트(1<<30), 이렇게 바꿔가며 비교
등등이 떠오르네요. 더 좋은 방법도 물론 있겠지만요.
좋은 하루 되세요!
저는 이런 방식이 좋던데요.
----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.
매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.
각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com
'출력' 이라면 효율은 그닥입니다만 이런 어프로치도
효율은 그닥입니다만 '출력' 이 목적라면 문자 출력의 순서를 거꾸로 만드는 데엔 이런 어프로치도 있습니다.
사실 c언어로 비트연산은 잘 안해봐서 모르겠습니다만 효율적으로 하려면 대강 어셈블리 기준 이런 느낌으로 짜면 될 거 같습니다만..
1.r1에 값을 저장
2.r2에 0b01000000..하여튼 이런 식의 값을 저장
3.r4 = 0
4.r1 AND r2 -> r3
5.test r3값
6.beq -> print 0 if r4 == 1
7.bne -> print 1 and set r4 = 1
8.cmp r2,0b01
9.beq 종료
10.(종료위치로 점프하지 않았을 경우)r2 = r2 / 2
11. 3번으로 jump
rotate를 사용할 수도 있습니다.
어셈블리어 수준이라면 대부분의 CPU가 rotate 명령을 지원하기 때문에 계산이 쉽지만
C에서는 직접적인 rotate 명령을 지원하지 않습니다. 하지만 비트 연산을 사용하여
어렵지 않게 구현하여 사용할 수 있습니다.
예를 들어 32bit 변수라면(여기서는 num)
uint32_t num;
for(i = 0; i < 32; i++)
{
num = (num << 1) | (num >> 31);
printf("%d", num & 1);
}
단점이라면 signed 형일 경우에는 부호 비트를 적절하게 따로 처리해줘야 한다는 정도입니다.
저는 이런 느낌으로?
이런 방법도 생각해봤습니다.
우선은 입력 값 n보다 큰 2 거듭제곱 수 중에 가장 작은 수 x를 찾고,
x 를 절반씩 줄여가면서 n과 비트연산 & 을 해봤습니다.
전체 코드는 다음과 같습니다.
결과는 다음과 같습니다.
댓글 달기