시프트shift 연산자는 비트의 위치를 좌우로 이동하는 연산으로 산술 시프트(<<,>>)와 논리 시프트(>>>)가 있다.
산술 시프트는 숫자의 부호 비트는 유지하면서 나머지 비트를 왼쪽(<<) 또는 오른쪽(>>)으로 이동하는 연산자다.
<<연산을 수행하면 부호 비트를 제외한 나머지 전체 비트가 왼쪽으로 이동하므로 1bit 이동할 때마다 x2의 효과가 있다.
반면 >> 연산을 수행하면 부호 비트를 제외한 나머지 전체 비트가 오른쪽으로 이동하므로 1 bit 이동할 때마다 /2의 효과가 있다.
여기서 주의해야 할 점은 이동한 이후에 발생하는 빈칸이다. 빈칸을 채우는 방식은 시프트 방향에 따라 다르다.
<<연산일 때 빈칸이 오른쪽에 생기며 0으로 빈칸이 생긴다.
반면 >> 연산일 때 빈칸은 왼쪽 부호 비트 다음에 생기며 이때는 부호 비트값과 동일한 값으로 채운다.
>> 연산에서는 삭제되는 비트 때문에 값을 2로 나눈 결과와 다르게 나타날 수 있다. 예를 들어 0b0011 >> 1을 연산하면 1.5가 아닌 1의 값이 나타나는데, 이때 발생하는 오차는 0b0011의 최하위 비트값이 시프트 과정에서 삭제되기 때문이다.
+) 양수와 음수의 산술 시프트 연산 결과를 쉽게 계산하는 방법
*>> 연산으로 발생하는 오차는 양수와 음수에서 조금 차이가 난다. 이는 앞서 2진수로 표현된 양수와 음수를 읽는 방법에서의 차이 때문이다. 당연히 실제 시프트 연산을 수행한 후 양수와 음수를 읽는 방법에 따라 데이터를 읽으면 결과를 알 수 있겠지만, 다음과 같이 간략히 정리해 기억하자.
논리 시프트 logical right shift(>>>)는 부호 비트를 포함해 전체 비트를 오른쪽으로 이동시키는 연산으로 빈칸은 모두 0으로 채운다. 부호 비트까지 이동시키므로 부호 비트가 1인 음수일 때 논리 시프트 이후에는 값이 양수로 변할 것이다.
+) 2진수를 16진수로 표현하는 방법
2진수를 16진수로 표현할 때는 2진수 4개를 하나로 묶어 16진수 1개의 값을 표현한다.
0b00111000 = 0x38
0b11110000 = 0xF0
0b1111111111111111 = 0xFFFF
이러한 논리 시프트는 '3번째 비트는 사운드 ON / OFF 여부를 나타내고, 4번째 위치는 자동완성 ON/ OFF를 의미한다.'와 같이 각 비트 위치에서의 값만이 의미가 있을 때 주로 사용하는 연산이므로 숫자의 크기나 부호는 의마기 없다. 일반적으로 논리 시프트를 이용하여 각 비트값을 알아 내는 방법은 다음과 같다.
논리 시프트를 이용해 각 비트 위치에서의 값 알아 내기
int falgs = 0b10110110;
System.out.println(flags >>> 0 & 1); // 0 : 0번째 비트값
System.out.println(flags >>> 1 & 1); // 1 : 1번째 비트값
System.out.println(flags >>> 2 & 1); // 1 : 2번째 비트값
System.out.println(flags >>> 3 & 1); // 0 : 3번째 비트값
System.out.println(flags >>> 4 & 1); // 1 : 4번째 비트값
System.out.println(flags >>> 5 & 1); // 1 : 5번재 비트값
System.out.println(flags >>> 6 & 1); // 0 : 6번째 비트값
System.out.println(flags >>> 7 & 1); // 1 : 7번째 비트값
//산술 시프트
// @ <<
System.out.println(3 << 1);
System.out.println(-3 << 1);
System.out.println(3 << 2);
System.out.println(-3 << 2);
System.out.println();
// @ >>
System.out.println(5 >> 1);
System.out.println(-5 >> 1);
System.out.println(5 >> 2);
System.out.println();
//논리 시프트(>>>)
System.out.println(3 >>> 1);
System.out.println(-3 >>> 31);
결과