(초보)C언어 이진수로 바꿔 출력하기

wannabe의 이미지

안녕하세요 가입하고 첫글입니다.

프로그래밍을 공부하고 있습니다.

알고리즘 책을 보기 시작했는데, 숫자를 입력 받아서 이진수로 바꿔서 출력하라고 합니다.

처음에는 이렇게 해보았습니다.

      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) 이진수로 출력하는 함수는 어떻게 만드는 것이 아름다운 것인지 궁금합니다. ^^; 답지 같은게 없어서요.

snowall의 이미지

pow함수 오차는 부동소숫점 연산에서 나오는 자연스러운 오차일겁니다.
http://kldp.org/node/132646
http://kldp.org/node/133158

일단 그건 나중에 해결하고요. 아님 해결 못할 것 같긴 하네요.

이진수로 출력하는 함수라면. 저라면 그냥 2로 나누면서 만들 것 같은데요

n=2938485; // given number
while(n>0){
printf("%d", n%2);
n/=2;
}

피할 수 있을때 즐겨라! http://melotopia.net/b

raymundo의 이미지

pow()를 써서 하실 수 있다면 (뭐 실제로는 오차 때문에 뜻대로 나오진 않았지만)

그냥 그 자리에 1, 10, 100, 1000 순으로 증가하는 변수를 하나 쓰시면 되겠네요. 1로 초기화하고 루프마다 10곱하면 되니까.

그렇지만 이 구현은 별로 좋아보이지 않는 것이, int 타입 변수로는 기껏해야 10자리까지밖에 표현을 못하겠네요. 2진수로 10자리면 1024 정도까지밖에.

- char의 배열을 넉넉히 잡고 2로 나누면서 1또는 0을 배열 원소에 채워나간 후에 역으로 출력

- 재귀호출 (2로 나눈 몫을 대상으로 재귀호출을 하고, 재귀호출에서 복귀한 후에 2로 나눈 나머지를 출력)

- 본문 코드에서 0x01과 &를 수행했는데, 그러지 말고 &의 대상을 처음에는 제일 왼쪽 비트 (1<<31), 그 다음은 그 옆 비트(1<<30), 이렇게 바꿔가며 비교

등등이 떠오르네요. 더 좋은 방법도 물론 있겠지만요.

좋은 하루 되세요!

shint의 이미지

		int n = 100;
		printf("[ 31 - 0 까지. n>>i 출력 ]\n");
		printf("%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
				n>>31 & 0x01, n>>30 & 0x01, n>>29 & 0x01, n>>28 & 0x01, n>>27 & 0x01, n>>26 & 0x01, n>>25 & 0x01, n>>24 & 0x01,
				n>>23 & 0x01, n>>22 & 0x01, n>>21 & 0x01, n>>20 & 0x01, n>>19 & 0x01, n>>18 & 0x01, n>>17 & 0x01, n>>16 & 0x01,
				n>>15 & 0x01, n>>14 & 0x01, n>>13 & 0x01, n>>12 & 0x01, n>>11 & 0x01, n>>10 & 0x01, n>>9 & 0x01, n>>8 & 0x01,
				n>>7 & 0x01, n>>6 & 0x01, n>>5 & 0x01, n>>4 & 0x01, n>>3 & 0x01, n>>2 & 0x01, n>>1 & 0x01, n>>0 & 0x01);
		printf("\n\n");
 
		printf("[ 0 - 31 까지. n>>i & 0x01 ]\n");
		int i=0;
		for(i=0; i<=31; i++)
		{
			printf("%d", n>>i & 0x01);
		}
		printf("\n\n");
 
		printf("[ 31 - 0 까지. n>>i & 0x01 ]\n");
		for(i=31; i>=0; i--)
		{
			printf("%d", n>>i & 0x01);
		}
		printf("\n");
 
[ 31 - 0 까지. n>>i 출력 ]
00000000000000000000000001100100
 
[ 0 - 31 까지. n>>i & 0x01 ]
00100110000000000000000000000000
 
[ 31 - 0 까지. n>>i & 0x01 ]
00000000000000000000000001100100

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

정상인의 이미지

효율은 그닥입니다만 '출력' 이 목적라면 문자 출력의 순서를 거꾸로 만드는 데엔 이런 어프로치도 있습니다.

void bin_recursive(int i)
{
     if(i != 0)
     {
          bin_recursive(i/2);
          printf("%d",i%2);
     }
}

사실 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
익명 사용자의 이미지

어셈블리어 수준이라면 대부분의 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 형일 경우에는 부호 비트를 적절하게 따로 처리해줘야 한다는 정도입니다.

addnull의 이미지

이런 방법도 생각해봤습니다.
우선은 입력 값 n보다 큰 2 거듭제곱 수 중에 가장 작은 수 x를 찾고,
x 를 절반씩 줄여가면서 n과 비트연산 & 을 해봤습니다.
전체 코드는 다음과 같습니다.

#include <stdio.h>
 
void printBinary(int n);
 
int main(int argc, char** argv) {
	int i;
 
	for (i = 1; i < 50; i++) {
		printBinary(i);
	}
 
	return 0;
}
 
void printBinary(int n) {
	int tmp;
 
	printf("%3d = ", n);
 
	for (tmp = 1; tmp <= n; tmp <<= 1) {
	}
 
	for (tmp >>= 1; tmp >= 1; tmp >>= 1) {
		printf("%d", !!(n & tmp));
	}
 
	printf("\n");
}

결과는 다음과 같습니다.

  1 = 1
  2 = 10
  3 = 11
  4 = 100
  5 = 101
  6 = 110
  7 = 111
  8 = 1000
  9 = 1001
 10 = 1010
 11 = 1011
 12 = 1100
 13 = 1101
 14 = 1110
 15 = 1111
 16 = 10000
 17 = 10001
 18 = 10010
 19 = 10011
 20 = 10100
 21 = 10101
 22 = 10110
 23 = 10111
 24 = 11000
 25 = 11001
 26 = 11010
 27 = 11011
 28 = 11100
 29 = 11101
 30 = 11110
 31 = 11111
 32 = 100000
 33 = 100001
 34 = 100010
 35 = 100011
 36 = 100100
 37 = 100101
 38 = 100110
 39 = 100111
 40 = 101000
 41 = 101001
 42 = 101010
 43 = 101011
 44 = 101100
 45 = 101101
 46 = 101110
 47 = 101111
 48 = 110000
 49 = 110001

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.