본문 바로가기
코딩/C 언어

C언어 코드 최적화 2장. 비트연산을 사용하자.

by DIYver 2020. 10. 14.

C언어 코드 최적화 방법은 여러가지가 있다.

이전에 나눗셈을 사용하지 않는것을 다뤄봤었다.

이번에는 비트연산을 사용하는 것이 얼마나 빠르게 코드를 작동시키는지 다뤄보도록 하자.

 

비트(bit)라는 것은 데이터에서 가장 기본이 되는 값으로,

0과 1로 이루어져 있다.

 

1 byte 는 8 bit 이다.

우리가 사용하는 int 자료형은 4byte 로 32bit 크기라고 할 수 있겠다.

 

 

아무튼 이런 비트연산을 하면 왜 코드 작동 속도가 빨라지는지 이론상 원리로 알아보자.

 

1. 비트 연산( OR, AND, XOR 등)은 컴퓨터에서 가장 빠르게 실행되는 연산이다.

그러므로 이러한 연산을 사용하면 좋을 수 밖에 없다.

 

코드에서 예를 들어보면,

struct HUMAN {
	int is_Alive;
	int is_Walking;
	int is_Jumping;
	int is_Eating;
}

우리는 생각없이 코딩을 한다면 위와 같이 코딩을 하게 될 것이다.

상태를 나타내는 변수들로 int자료형을 사용하였다.

 

 

 

위의 코드를 최적화 시키면 어떻게 할 수 있을까?

 

아래 코드를 이해해보자.

#include <stdio.h>

#define ALIVE 0x1
#define WALKING 0x2
#define JUMPING 0x4
#define EATING 0x8

void main{
	
    byte my_status = ALIVE | WALKING | EATING ;
	
    
    return 0;
}

#define 을 통해서 상태변수들을 정의하였는데,

ALIVE는 1 

WALKING 은 2

JUMPING 은 4

EATING 은 8

 

로 정의하였다. 

 

이걸 이진수로 확인하자면

 ALIVE 는 0001

WALKING 은 0010

JUMPING 은 0100

EATING 은 1000

 

이 된다.

 

따라서 main() 안의

my_status = ALIVE | WAKING | EATING 

의 뜻은 

0000 0001 | 0000 0010 | 0000 1000 의 결과로

0000 1011의 값이 된다.

 

 

기존의 코드는 불필요하게 int 자료형을 4개나 사용하였다.

하지만 아래의 코드는 int 자료형 크기의 1/4 밖에 안되는 byte에 필요한 값을 다 저장하였다.

 

아무래도 이런 표현은 접해본 적이 없다면 당연히 낯설것이다.

하지만 코드 최적화를 위해서는 필수적인 작업이라 할 수 있다.

 

 

 

 

 

 

 

2. 또다른 비트연산 

 

C언어를 배우다보면 필수적인 코스가 있다.

어떤 입력받은 수가 홀수인지 짝수인지 구별하는 것 말이다.

 

우리는 흔히 나머지 연산을 사용하곤 했다.

예를 들면

if( num % 2 == 1)
{
	printf("홀수입니다.\n");
}
else
{
	printf("짝수입니다.\n");
}

위와 같이 말이다.

 

그런데 전에도 말했듯이

나누기 같은 연산이 들어가면 속도가 매우 느려진다.

 

위의 코드를 최적화 한다면 아래와 같이 할 수 있겠다.

 

if( num & 1)
{
	printf("홀수 입니다.\n");
}
else
{
	printf("짝수 입니다.\n");
}

"아니 이게 가능해?" 라고 물을 수 있겠다.

& 는 비트 연산자로, 

num 의 이진수와 1 과의 AND 연산을 하는 것이다.

 

예를 들어, num이 9 라고 한다면 이진수로 1001 이 되고,

1과 AND 연산을 하게되면 1001 & 1 = 0001 이 된다.

0001 은 1 이므로 TRUE 값이 되어, 홀수라는 것이 출력된다.

 

결국에는 끝자리만 확인하면 되는 것이다.

 

비트연산을 이해했다면 위의 상황이 될 경우 더 쉽게 

코드를 작성할 수 있을 뿐더러

연산속도가 더 빨라지므로 1석 2조라 할 수 있겠다~!

 

 

 

 

실제로 반복테스트를 해보면서 

연산속도 차이가 어떻게 되는지 알아보자.

 

#include <stdio.h>
#include <stdlib.h>
#include <time.h>



void main()
{
	clock_t start, end;
	float res;
	start = clock();

	srand(time(NULL));

	
	int count_holsu = 0;

	for (int i = 0; i < 100000; i++)
	{
		int random = rand();
		if (random % 2 == 1)
		{
			count_holsu++;
		}
	}
	printf("홀수 카운트 : %d \n", count_holsu);

	end = clock();
	res = (float)(end - start) / CLOCKS_PER_SEC;

	printf("\n소요시간 : %.3f \n", res);
	return;
}

위의 코드처럼 

랜덤 수를 입력받아 홀수인지 구별하는 과정을 십만번 반복한다.

 

결과는 10ms 가 소요되었다.

평균적으로 9ms 정도 소요되는 것을 확인할 수 있었다.(디버그모드)

 

 

 

 

최적화 시킨 코드를 테스트해보자.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>



void main()
{
	clock_t start, end;
	float res;
	start = clock();

	srand(time(NULL));

	
	int count_holsu = 0;

	for (int i = 0; i < 100000; i++)
	{
		int random = rand();
		if (random & 1)
		{
			count_holsu++;
		}
	}
	printf("홀수 카운트 : %d \n", count_holsu);

	end = clock();
	res = (float)(end - start) / CLOCKS_PER_SEC;

	printf("\n소요시간 : %.3f \n", res);
	return;
}

예상했던 대로 약간 더 빠른 연산결과를 확인할 수 있었다.

평균적으로 7~8 ms 가 소요된 것으로 보인다.(디버그 모드)

 

 

 

 

결론을 내자면

코드 최적화를 할 줄 안다면

코드도 더 쉽게 작성할 수 있으며

빠른 연산속도를 얻을 수 있다!

 

 

 

 

 

<이전 글>

1.  c언어 코드 최적화 1장. 나눗셈을 사용하지 말자.

 

c언어 코드 최적화 1장. 나눗셈을 사용하지 말자.

C언어는 오랜 역사를 갖고 있으며, 더 발전한 C++ 언어 역시 많은 곳에서 사용되고 있다. 특히 컴퓨터보다는 제한된 성능의 기계에서 사용하고는 한다. 보통 우리는 임베디드 시스템이라고 부른��

diyver.tistory.com

 

댓글