기초개념인 java 비트연산을 정리해보도록 하겠습니다.

 

비트연산은 2개의 이진수에 대해서 연산하는 것을 말합니다.

컴퓨터는 이진수로 대화를 하고 있기 때문에 이 비트연산을 알아두는 것이 기본일 것 같습니다.

 

컴퓨터가 숫자를 표현하는 방법

컴퓨터는 0,1을 활용해서 데이터를 표현합니다. 숫자 2의 경우 0010 로 표현하게 됩니다.

 

[0] [0] [1] [0] <-- 각 자리수를 공간이라고 생각하면 4개의 공간을 사용하고 있습니다.  

컴퓨터는 이 공간하나를 bit라고 정의해서 연산을 하고 있습니다.

 

위의 2를 표현한 이진수는 4bit로 표현했다고 말할 수 있습니다.

 

일반적으로 컴퓨터는 8bit의 공간을 기준으로 사용합니다.

 

8개의 bit를 1 byte로 표현합니다. 

1byte공간이 1024개로 할당하면 1kb(1024byte)가 됩니다.

1024개 만큼 커질수록 mb,gb,tb로 치환되는 단위를 사용합니다.

 

컴퓨터가 사용하는 최소단위인 bit의 연산으로 컴퓨터는 대화를 하게 됩니다. 지금 블로그 화면에 노출되는 모든데이터도 0,1로 표현된 bit들을 연산해 우리가 이해할 수 있는 모습으로 변환된 것입니다.

 

그 가장 기초적인 부분에 대해 확인해보겠습니다.

 

1. AND 연산 (&)

두 수의 각자리수에 대해 둘다 1일경우 1로 변환하는 것을 말합니다.

십진수 9와 11을 이진수로 변환해 비교해보겠습니다.

         1001
AND 1011
=       1001

코드로 확인해보겠습니다.

public class bit {
    public static void main(String[] args) {

        int a = 9;
        int b = 11;

        System.out.println(Integer.toBinaryString(a)); //바이너리로 변환
        System.out.println(Integer.toBinaryString(b)); //바이너리로 변환
        System.out.println("10진수 : " + (a & b));
        System.out.println("2진수 : " + Integer.toBinaryString(a & b));

    }
}

 

2. OR 연산 ( | )

두 수의 각자리수가 하나만 1이면 1로 변환합니다.

십진수 9와 11을 이진수로 변환해 비교해보겠습니다.

     1001  
OR 1011
=   1011 

코드로 확인해보겠습니다.

package bit;

public class bit {
    public static void main(String[] args) {

        int a = 9;
        int b = 11;

        System.out.println(Integer.toBinaryString(a)); //바이너리로 변환
        System.out.println(Integer.toBinaryString(b)); //바이너리로 변환
        System.out.println("10진수 : " + (a | b));
        System.out.println("2진수 : " + Integer.toBinaryString(a | b));

    }
}

 

3. XOR 연산 (^)

두 수의 각 자리수가 다른 경우 1로 변환합니다.

십진수 9와 11을 이진수로 변환해 비교해보겠습니다.

         1001
XOR  1011
=       0010

코드로 확인해보겠습니다.

package bit;

public class bit {
    public static void main(String[] args) {

        int a = 9;
        int b = 11;

        System.out.println(Integer.toBinaryString(a)); //바이너리로 변환
        System.out.println(Integer.toBinaryString(b)); //바이너리로 변환
        System.out.println("10진수 : " + (a ^ b));
        System.out.println("2진수 : " + Integer.toBinaryString(a ^ b));

    }
}

3. NOT 연산 (~)

각 자리수를 반대로 변환하는 것을 의미합니다.

십진수 9를 이진수로 변환해 테스트해보겠습니다.

NOT 1001 = 0110

코드로 확인해보겠습니다.

package bit;

public class bit {
    public static void main(String[] args) {

        int a = 9;
        int b = 11;

        System.out.println(Integer.toBinaryString(a)); //바이너리로 변환
        System.out.println("10진수 : " + ~a);
        System.out.println("2진수 : " + Integer.toBinaryString(~a));

    }
}

 

 

9를 NOT연산하는 경우 10진수 -10이 출력됩니다. -10을 이진수로 변환하는 경우11111111111111111111111111110110 가 출력되는데요.  제일 아래에서 설명드리니겠습니다.

 

4. SHIFT 연산( <<, >>)

 

4-1. << 연산

이진수의 각자리를 왼쪽으로 N칸 밀고 제일 첫째자리는 0으로 채워주는 연산입니다.

3을 2칸 SHIFT연산 하세요
3 << 2

= 3 * 2^2 = 12

이진수 3

0 1 1

2칸 왼쪽으로 밀기 (뒤에 0을 2개 채우기) , 결과값은 12

0 1 1 0 0

 

4-2.  >> 연산

이진수의 각자리를 오른쪽으로 N칸 밀고 밀면서 사라지는 자리수는 삭제해버린다.


16을 3칸 SHIFT연산 하세요

16  >> 3


=16 / 2^3 = 2

 

16을 이진수로 표현하면 아래와 같이 1 0 0 0 0

1 0 0 0 0

>>3  즉, 오른쪽으로 3칸 이동 시키겠습니다. (뒤 3칸을 자르고 앞을 0으로 채웁니다.)

출력값은 2가 됩니다. 

 

여기서 중요한 것은 맨앞을 동일한 부호비트로 채운다는 점입니다. 항상 0으로 채우는 것은 아닙니다.

음수일 경우 1로 채워주게됩니다. 

 

부호비트와 관련 된 자세한 설명은 맨 아래에서 설명드리겠습니다.

0 0 0 1 0

 

4-2.  >>> 연산

위와같이 오른쪽 SHIFT에 >가 하나 더 추가된 경우에는 오른쪽 SHIFT연산을 할 경우 항상 양수만 고려하겠다는 뜻입니다. 즉, 오른쪽으로 밀고 남은 공간을 항상 0으로 채우겠다는 뜻입니다.

>>>연산을 할 경우 무조건 양수만 출력됩니다.

 

 

SHIFT연산을 코드로 구현하면 아래와 같습니다.

package bit;

public class bit {
    public static void main(String[] args) {

        System.out.println(3 <<2);
        System.out.println(Integer.toBinaryString((3 <<2)));

        System.out.println(16 >> 3);
        System.out.println(Integer.toBinaryString((16 >> 3)));

        System.out.println(-16 >>> 3);
        System.out.println(Integer.toBinaryString((-16 >>> 3)));

    }
}

 

 

5. 부호비트와 Integer 의 범위

 

Integer 값의 범위는  -2^31 ~ 2^31-1 입니다. 이는 어떻게 산출된 것일까요?

 

Intger는 4byte, 즉 32개의 bit를 사용합니다. 32개의 bit공간을 1로 채운 값은 4,294,967,295이 됩니다.

하지만, 위와 같이 사용할 경우 음수표현을 할 수 없어 음수 표현을 위해 맨앞의 자리를 부호로 사용하게 됩니다. 

 

아래와 같이 0,1일때 각각 양수, 음수로 표현하게됩니다. 이를 부호비트라고 합니다.

 

0 == 양수

1 == 음수

 

32번째
(부호비트)
31번째 30번째 .... ..... ... 3번재 2번째 1번째
0 1 1 .... ..... .,... 1 1 1

위와 같이 32개의 공간에서 맨앞자리는 부호비트로 사용하게 됩니다.

그럼 표현할 수 있는 숫자는 양수일 경우 2^31 -1개가 됩니다.

여기서 -1을 해주는 이유는 제일 첫번째 bit의 최대 값이 1이기 때문입니다. 

 

예를들어 아래와 같이 4bit짜리 공간이 있다고 하면, 모두 1로 채웠을때의 값은 1+2+4+8 = 15입니다.

맨 앞 bit가 1이기 때문에 2^4 -1 값까지만 표현가능 한 것입니다. 이 bit가 31개까지 늘어나면 동일하게

2^31-1만큼까지만 표현 가능한 것입니다.

1 1 1 1

 

자 그럼 음수의 범위는 어떻게 될까요?

첫번째 부호비트가 1이고 나머지 31개의 자리도 모두 1인 경우를 -1로 표현합니다. 

부호비트가 0일때 즉 양수일때 가장 큰 값을 부호비트가 1인 음수일 경우에는 가장 작은 값으로 치환합니다.

32번째
(부호비트)
31번째 30번째 .... ..... ... 3번재 2번째 1번째
1 1 1 .... ..... .,... 1 1 1

 

위의 NOT연산에서 9를 NOT 연산 할 경우 11111111111111111111111111110110 이 출력된 것을 잠시 살펴보면,

 

원래 숫자 9는 32BIT로 표현하면 아래 와 같이 5번째~32번째는 모두 0으로 표현 될 것 입니다.

32번째
(부호비트)
31번째 30번째 .... ..... 4번째 3번재 2번째 1번째
0 0 0 0 0 1 0 0 1

 

NOT연산은 모든 자리를 반대로 변환하기 때문에 아래와 같이 변환 된 것입니다. 이는 양수에서 가장 큰 수 가 음수에서 가장 작은 수가 되는 음수 표현방식에 따라서 -10이 출력되게 됩니다.

 

32번째
(부호비트)
31번째 30번째 .... ..... 4번째 3번재 2번째 1번째
1 1 1 1 1 0 1 1 0

 

LIST
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기