[알고리즘] 비트 조작하기
by Jewoo.Song
비트 연산자
- NOT
- NOT 연산은 각 자릿수의 값을 반대로 바꾸는 연산이다.
- NOT 0111 = 1000
- x = ~y;
- OR
- OR 연산은 두 값의 각 자릿수를 비교해, 둘 중 하나라도 1이 있다면 1을, 아니면 0을 계산한다.
- 0101 OR 0011 = 0111
- x = y
|
z;
- XOR
- XOR 연산은 두 값의 각 자릿수를 비교해,값이 0으로 같으면 0, 값이 1로 같으면 0, 다르면 1을 계산한다.
- 0101 XOR 0011 = 0110
- x = y ^ z;
- AND
- AND 연산은 두 값의 각 자릿수를 비교해, 두 값 모두에 1이 있을 때에만 1을, 나머지 경우에는 0을 계산한다.
- 0101 AND 0011 = 0001
- x = y & z;
예제
- 0110 + 0110 = 1100
- 0110 * 2와 같다 = (0110 « 1)
- 0110을 왼쪽으로 한 번 시프트
- 같은 값을 더하는 것은 왼쪽으로 한 번 시프트하는 것과 같다.
- 0100 * 0011 = 1100
- 0100은 4와 같으므로, 0011에 4를 곱하면 답을 얻을 수 있다.
- 2^n으로 곱하는것은 n만큼 왼쪽으로 시프트 하는 것과 같다.
- 즉, 왼쪽으로 두 번 시프트 (0011«2)
- 1101 ^ (~1101) = 1111
- 어떤비트를 NOT한 값과 그비트를 XOR하면 항상 1이다.
- 즉, a^(~a)는 모든 비트가 1
- 1101 & (~0 « 2) = 10000
- ~0은 모든 비트가 1이다.
- « 2를 하면 마지막 비트 두 개는 0이되고, 나머지는 1이 된다.
- « n을 하면 마지막 n개의 비트가 0이 된다.
- 이 값과 다른 값을 AND 연산하면 마지막 두 비트의 값을 삭제한 값이된다.
비트 조작 할 때 알아야 할 사실들과 트릭들
Os
는 모든 비트가 0인 값이고,1s
는 모든 비트가 1인 값을 나타낸다.^
- x
^
0s = x - x
^
1s = ~x - x
^
x = 0
- x
&
- x
&
0s = 0 - x
&
1s = x - x
&
x = x
- x
|
- x
|
0s = x - x
|
1s = 1s - x
|
x = x
- x
2의 보수와 음수
컴퓨터는 일반적으로 정수를 저장할 때 2의 보수 형태로 저장한다. 양수를 표현할 때는 아무 문제 없지만 음수를 표현할 때는 그 수의 절댓값에 부호비트를 1로 세팅한 후 2의 보수를 취한 형태로 표현한다.
- n비트 숫자에 대한 2의 보수는 2^n에 대한 보수값과 같다.
- 이때, n은 부호비트를 뺀 나머지 값을 표현할 때 사용되는 비트의 수이다.
- 2의 보수 표현 방법
- -K를 N비트의 2진수로 표현하면 concat(1, 2^n-1 -K)이다.
- 또는, 양수로 표현된 이진수를 뒤집고, 1을 더해준 후 부호비트를 맨 앞에 붙여주는 방법이 있다.
- 예) -3
- 3 //양수로 표현
- 011 //이진수 변환
- 100 // ~
- 101 // + 1
- 1101 // 부호 붙이기
산술 우측 시프트 vs 논리 우측 시프트
- 산술 우측 시프트
- 기본적으로 2로 나눈 결과와 같다.
>>
연산과 같다.- 부호비트는 바꾸지 않는다.
- 논리 우측 시프트
- 일반적으로 비트를 옮길 때 보이는 것처럼 움직인다.
>>>
연산과 같다.- 비트를 옆으로 옮긴 후 최상위 비트에 0을 넣는다.
- 10110101 = -75
- 01001010 (75) => 비트를 뒤집고 +1을 해주면 2의 보수로 표현된 음수를 얻을 수 있다.
- 01011010 = 90
일작적인 비트 작업들
Get : 특정 비트 값 얻어내기
- 1을 i비트만큼 시프트해서 00010000과 같은 값을 만든다.
- AND 연산을 통해 num의 i번째 비트를 제외한 모든 비트를 삭제한다.
- 이 값을 0과 비교하고, 값이 0이 아니라면 i번째 비트는 1이고, 0이라면 i번째 비트는 0이다.
boolean getBit(int num, int i) { return ((num & (1 << i)) != 0); }
Set : 특정 비트값 채워넣기
- 1을 i만큼 왼쪽으로 시프트하여 00010000과 같은 값을 만든다.
- 그 다음 그 값을 num과 OR연산한다.
- i번째를 제외한 나머지 비트들은 0과 OR연산을 하게 되므로 num에 아무 영향을 끼치지 않는다.
int setBit(int num, int i) { return num | (1 << i); }
Clear: 특정 비트값 지우기
- Set을 반대로 한 것과 같다.
- NOT 연산자를 이용해 (00010000)을 11101111과 같이 만든 뒤 num과 AND 연산을 수행한다.
- 그러면 나머지 비트의 값은 변하지 않은 채 i번째 비트값만 삭제된다.
int clearBit(int num, int i) { int mask = ~(1 << i); return num & mask; }
Update : 특정 비트 값 갱신하기
- setBit와 clearBit에서 이용한 방법을 섞어서 구현.
- 우선 11101111과 같은 값을 이용해서 i번째 비트값을 삭제한다.
- 그 뒤 바꾸자고 하는 값 v를 i번 쉬프트한다.
- num의 i번째 비트만 v로 갱신한다.
int updateBit(int num, int i, int v) { int mask = ~(1 << i); return (num & mask) | (v << i); }
참고
- https://ko.wikipedia.org/wiki/비트_연산
- 코딩인터뷰 완전정복
Subscribe via RSS