들어가며
비트를 대상으로 하는
연산이라고 하면
언뜻 하드웨어 컨트롤을
떠올리기 쉽다.
그러나 일반 응용 프로그램의
개발에서도
비트를 대상으로 하는
연산이 많이 쓰인다.
비트 연산자의 이해
비트 연산자는 각각의
비트를 대상으로
연산을 진행하는 연산자이며,
피연산자는 반드시
정수이어야 한다.
실수를 대상으로 하는
비트 연산은
의미가 없기 때문에
자바는 이를 지원하지
않는다.
위의 표에 있는 연산자들을
이해하기에 앞서
비트 단위 연산이 의미하는
바를 이해할 필요가 있다.
이에 다음 예제를 통해서
비트 단위 연산의 의미를
설명하고자 한다.
public class temp {
public static void main(String[] args){
byte n1 = 13;
byte n2 = 7;
byte n3 = (byte)(n1 & n2); // 비트 연산 &의 결과는 int형
System.out.println(n3);
}
}
/*
출력 결과
5
*/
위 예제에서는 다음 문장을
통해서
비트 단위 & 연산을 진행하고
있다.
& 연산은 비교의 대상이 되는
두 비트가 모두 1인 경우에만
1을 반환하여 연산 결과를
구성하는 연산자이다.
byte n3 = (byte)(n1 & n2);
위의 문장에서 형 변환을
하는 이유는
& 연산도 int형 연산을
하기 때문이다.
(부족한 부분을 0으로 채워서
int형 연산을 진행한다.)
즉 위의 문자에서 피연산자는
byte형이지만
연산 결과는 int형이다.
그럼 연산의 결과가
만들어지는 과정을
다음 그림을 통해서
관찰하자.
위 그림을 통해서 알 수
있는
비트 연산자의 특성 2가지는
다음과 같다.
- 비트 연산자는 각각의 비트를 대상으로 연산을 진행한다.
- 그리고 각 비트를 대상으로 진행된 연산 결과를 묶어서 하나의 연산 결과를 반환한다.
참고로 위 그림에서는 byte형 변수
n1과 n2를 대상으로
연산의 과정을 설명하였다.
즉, int형 연산을 위해 0을
채우는 부분에 대한 것은
그림에서 생략되었다.
비트 연산자
비트 연산자의 연산 특성에
대해 이해하였으니,
이어서 비트 연산자를
하나씩 소개하겠다.
먼저 소개할 연산자는
다음과 같다.
& 연산자
비트 단위로 AND 연산을 한다.
& 연산자는 && 연산자와
성격이 유사하다.
& 연산자는 두 비트가
모두 1일 때
1을 반환하여 하나의
연산 결과를 구성한다.
다음은 & 연산에 대한
진리표다.
이어서 소개할 연산자는
다음과 같다.
그리고 이는 || 연산자와
성격이 유사하다.
| 연산자
비트 단위로 OR 연산을 한다.
즉, | 연산자는 두 비트 중
하나라도 1이면
1을 반환하여 하나의
연산결과를 반환한다.
진리표는 다음과 같다.
마지막으로 다음 두 연산자를
소개하겠다.
이 중에서 ~ 연산자는
! 연산자와 성격이 유사하다.
^ 연산자
비트 단위로 XOR 연산을 한다.
~ 연산자
1이면 0을, 0이면 1을 반환하는 연산을 한다.
XOR 연산이란 두 비트
값이 서로 다른 경우에만
1을 반환하는 연산을
의미한다.
이 둘에 대한 진리표는
다음과 같다.
그럼 다음 예제를 통해서
지금까지 설명한 4개의
비트 연산자들의
비트 연산의 결과를 보이도록
하겠다.
public class temp {
public static void main(String[] args){
byte n1 = 5; // 0000 0101
byte n2 = 3; // 0000 0011
byte n3 = -1; // 1111 1111
byte r1 = (byte)(n1 & n2); // 0000 0001
byte r2 = (byte)(n1 | n2); // 0000 0111
byte r3 = (byte)(n1 ^ n2); // 0000 0110
byte r4 = (byte)(~n3); // 0000 0000
System.out.println(r1); // 1
System.out.println(r2); // 7
System.out.println(r3); // 6
System.out.println(r4); // 0
}
}
/*
출력 결과
1
7
6
0
*/
비트 쉬프트 연산자
비트 쉬프트 연산자는
피연산자의 비트 열을
왼쪽 또는 오른쪽으로
이동시킨 결과를 반환하는
연산자이다.
이 연산자도 2개의 피연산자가
필요한 이항 연산자이며,
피연산자는 모두 정수이어야
한다.
비트 쉬프트 연산자의
연산 방식은 다음과 같다.
변수 A와 Z가 존재할 때
다음의 형식으로 문장을
구성할 수 있다.
이때 A와 Z는 상수도
될 수 있다.
int num = A << Z;
// 이때 A와 Z는 변수다.
그리고 위의 문장이 갖는
의미는 다음과 같다.
A의 비트 열을 Z만큼 왼쪽으로 이동시켰을 때의
값을 변수 num에 저장하라.
일단 이 정도의 이해를
가지고 다음 예제를 보자.
이 예제를 통해서 비트
쉬프트 연산이 지니는
특별한 의미도 함께
설명하겠다.
public class temp {
public static void main(String[] args){
byte num;
num = 2; // 0000 0010
System.out.print((byte)(num << 1) + " "); // 0000 0100
System.out.print((byte)(num << 2) + " "); // 0000 1000
System.out.print((byte)(num << 3) + " " + '\n'); // 0001 0000
num = 8; // 0000 1000
System.out.print((byte)(num >> 1) + " "); // 0000 0100
System.out.print((byte)(num >> 2) + " "); // 0000 0010
System.out.print((byte)(num >> 3) + " " + '\n'); // 0000 0001
num = -8; // 1111 1000
System.out.print((byte)(num >> 1) + " "); // 1111 1100
System.out.print((byte)(num >> 2) + " "); // 1111 1110
System.out.print((byte)(num >> 3) + " " + '\n'); // 1111 1111
}
}
/*
출력 결과
4 8 16
4 2 1
-4 -2 -1
*/
위 예제에서는 다음과 같이
변수 num의 비트 열을
왼쪽으로 밀어서 얻은
결과를 출력하고 있다.
이 때 오른쪽의 빈공간은
0으로 채워진다.
System.out.print((byte)(num << 1) + " "); // 값이 2배 증가함.
위의 실행 결과에서 보이듯이
비트 열을 왼쪽으로 한 칸
밀고
빈 공간을 0으로 채울
때마다
그 값은 2배씩 증가한다.
이어서 다음 문장을 보자.
다음과 같이 >> 연산을
통해서
변수 num의 비트 열을
오른쪽으로 밀면
이로 인해 만들어지는
빈 공간은
가장 왼쪽에 위치한 비트와
동일한 값으로 채워진다.
즉, 부호 비트가 0이면 0을,
1이면 1을 채운다.
System.out.print((byte)(num >> 1) + " "); // 값이 2배 감소함.
그리고 이때 반환되는 값은
num에 저장된 값을
2로 나눈 결과이다.
즉, >> 연산을 통해서
비트 열을
한칸씩 오른쪽으로 밀 때마다
2로 나눈 결과가 반환된다.
참고 및 출처
|