이번 포스팅에서는 2진수의 특성과 비트연산을 활용해서 할수 있는 여러가지 프로그래밍적인 기법을 알아보겠다.
성능을 위해서 실제로 우리가 작성한 코드를 컴파일러 수준에서 앞으로 배울 연산들로 바꿔주는 경우도 있다. 이렇게 2진수를 활용한 여러가지 꼼수(?)들을 사용해서 기계가 어떻게 연산을 처리하는지에 대해 조금 더 잘 이해해보도록 하자.
2^0
, 즉 1이다.// 짝수 구분
if (num % 2 == 0)
{
// do something
}
// 홀수 구분 1
if (num % 2 == 1)
{
// do something
}
// 홀수 구분 2
if (num % 2 != 0)
{
// do something
}
if ((num & 0x1) == 0) /* 짝수 */
{
}
if ((num & 0x1) != 0) /* 홀수 */
{
}
0x1
인 마지막 비트만 켜져있는 1을 &
연산하면 마지막 num
변수의 마지막 비트만 남게 되고, 마지막 비트만 0인지 아닌지 비교 가능하다num & 0x1
를 통해서 num
의 값에 있는 첫번째 비트를 제외한 비트들은 전부 &연산을 통해서 0으로 만들어 버렸다. 즉, 마스킹(masking)했다.if ((num & 0x80000000) == 0) // 양수
{
}
if ((num & 0x80000000) != 0) // 음수
{
}
(num & 0x80000000) == 0
이란 말은 최상위 비트가 세팅이 안되어있다는 말이니깐 양수int main(void)
{
char a = 'A';
char mask = 1 << 5;
a = a ^ mask;
printf("%c\n", a); /* A */
a = a ^ mask;
printf("%c\n", a); /* a */
return 0;
}
0b00010000
을 만들어서 XOR연산을 해주면 대소문자 스위칭 가능하다.int
가 32비트고 0 혹은 1로 불리언을 표현할 수 있기 때문에, int
하나에 boolean
32개 모을수 있다.flag = 0b01010101;
mask = 0b00000010;
flag = flag | mask; /* 1 */
mask
에서 켜져있는 비트가 OR연산 때문에 1로 바뀐다. 나머지 비트는 mask
에서 0으로 세팅되어 있어서 OR연산이기 때문에 그대로 간다flag = 0b01010111;
mask = 0b00000010;
flag = flag & ~mask; /* 1 */
mask
를 NOT연산으로 뒤집으면 0b11111101
이 된다.0b11111101
랑 flag
랑 AND 연산을 하면 타겟비트가 0으로 세팅되어 있기 때문에 무조건 0이 된다flag = 0b01010111;
mask = 0b00000010;
flag = flag ^ mask; /* 켜기 */
flag = flag ^ mask; /* 끄기 */
flag
랑 mask
를 XOR 연산하면, mask
에서 나머지 비트가 전부 0으로 세팅되어 있기 때문에 같은건 0, 다른건 1이 되어서 나머지비트는 원본값으로 들어온다.char property_flags = 0;
char mask = 0;
char ATTACK_NONE = 0;
char ATTACK_FIRE = 1;
char ATTACK_ICE = 2;
char ATTACK_WIND = 3;
char ATTACK_ARCANE = 4;
char ATTACK_SIZE = 5;
mask = (1 << ATTACK_NONE) | (1 << ATTACK_WIND);
property_flags = property_flags ^ mask; /* 켜기, 9 */
property_flags = property_flags ^ mask; /* 끄기, 0 */
property_flags = property_flags | mask; /* 켜기, 9 */
property_flags = property_flags & ~mask; /* 끄기, 0 */
배송방법 2개
색상 16개
모양 8개
int
에 위의 데이터를 다 넣을 수 있다.반복문을 돌면서 비트 하나하나 확인
int is_two_squared(int number)
{
int n = number;
if (n == 0) {
return FALSE;
}
while (n != 1)
{
if (n % 2 != 0) {
return FALSE;
}
n = n / 2;
}
return TRUE;
}
2진수의 특징을 이용한 방법
int is_two_squared(int number)
{
int flag = number - 1;
if ((flag & number) == 0) {
return TRUE;
}
return FALSE;
}
number
가 2진수라면 뺐을 때 앞에있는 모든 비트가 1로 바껴있을 것이다&
연산을 하면 0이된다