1. 비트(bit)란 ? 

컴퓨터에서 정보를 나타내는 최소 단위. 8비트 = 1바이트.



2. 비트와 2진법의 관계

초기 컴퓨터는 전기가 통하냐(1), 안통하냐(0)를 판단해서 데이터를 처리하도록 설계되었기 때문에, 0과 1만을 사용하는 2진법의 연산을 하는 것이 컴퓨터의 전통이 되어왔다. 여담으로 컴퓨터의 전원버튼의 이미지도 0과 1을 합쳐서 만들어진 것이라고 한다. 0이면 전원이 꺼진거고, 1이면 전원이 켜진 것이다.

컴퓨터 전원버튼


아무튼 1과 0으로 이루어진 2진법으로 정보를 표시하는 단위를 비트라고 이름 붙이게 되었다.


그럼 1비트로 표현할 수 있는 정보는? 

0

1

이렇게 두가지이다. 


그럼 2비트로 표현할 수 있는 정보는?

00

01

10

11

이렇게 4가지이다.


그럼 3비트로 표현할 수 있는 정보는?

000

001

010

100

011

101

110

111

이렇게 8가지이다.


위와 같이, n비트로 표현할 수 있는 정보의 가짓수는 2의 n제곱 가지이다.


3. 비트연산이란? 

한개, 또는 여러개의 비트단위 데이터를 가지고 연산을 진행하여, 원하는 결과값을 도출해내는 방법이다.



And 연산. 두 정보의 각 자릿수를 비교해서, 둘 다 1인 자리는 1로, 아닌 자릿수들은 0으로 결과값을 도출.




or연산. 두 데이터의 각 자릿수를 비교해서 둘 중 아무나 1이라면 그 자릿수를 1로 해서 결과값을 도출.




xor 연산. 두 데이터의 각 자릿수를 비교해서 두 값이 서로 다른 자릿수는 1로, 같은 경우에는 0으로 판단해서 결과값을 도출.




not 연산. 각 자릿수가 1이라면 0으로, 0이라면 1로 뒤집어서 결과값을 도출.




왼쪽 시프트 연산. << 1이라면 왼쪽으로 모든 데이터를 이동시킨다.




오른쪽 시프트 연산. >> 2라면 모든 비트의 자릿수를 오른쪽으로 2만큼 이동시킨다.




4. 비트연산의 실제 예


예를 들어, 내가 4비트짜리 정보를 가지고 책가방 내에 학용품의 유무를 표현한다고 해보자.

왼쪽부터 시작해서 책, 필통, 공책, 자 라고 해보자. 내가 책과 공책은 있는데 필통과 자는 없다고 한다면, 그것을 4비트로 표현한다면 아래와 같다.


4비트로 표현해본 내 학용품 소지 유무.



내가 공책을 가지고 있는가? 라는 것을 비트 연산을 이용해 알아내보자.



내가 공책을 가지고 있는가?




시프트 연산을 사용하는 경우도 엄청 많지만, 현실에서 많이 사용하는 경우는 바로 LED전광판이다. 

보통 지하철에서 이번역과 내리는 곳을 설명할 때 LED전광판을 사용하는데, 이때 글씨가 왼쪽으로 흐르는 것처럼 표현할 때 왼쪽 시프트 연산자를 사용하게 된다.

0은 led불이 꺼져있는 상태, 1은 켜져있는 상태이고, 시프트 연산을 이용해서 불을 한칸씩 이동시키는 것이 가장 기초적인 led전광판의 흐르는 글씨의 원리이다. 아두이노에서 led불을 사용할 때도 시프트 연산을 사용하기도 한다.




5. 유니티에서의 비트연산

int는 기본적으로 4byte 크기의 변수이기 때문에 비트로 따지자면 32비트 크기의 데이터이다. 그래서 밑의 주석에 보면 32자리의 비트숫자로 표시한걸 볼 수 있다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using UnityEngine;
 
public class Bit : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        int a = 10// 2진법으로 0000 0000 0000 0000 0000 0000 0000 1010
        int b = 7//  2진법으로 0000 0000 0000 0000 0000 0000 0000 0111
        int result = 0;
 
        result = a & b;
        Debug.Log("and 연산 : " + result); //결과는 2이다.  2진법으로 0000 0000 0000 0000 0000 0000 0000 0010
 
        result = a | b;
        Debug.Log("or 연산 : " + result); //결과는 15이다.  2진법으로 0000 0000 0000 0000 0000 0000 0000 1111
 
        result = a ^ b;
        Debug.Log("xor 연산 : " + result); //결과는 13이다.  2진법으로 0000 0000 0000 0000 0000 0000 0000 1101
 
        result = ~a;
        Debug.Log("not 연산 : " + result); //결과는 -11이다.  2진법으로 1111 1111 1111 1111 1111 1111 1111 0101
 
        result = a << 1;
        Debug.Log("left shift 연산 : " + result); //결과는 20이다. 2진법으로 0000 0000 0000 0000 0000 0000 0001 0100
 
        result = a >> 1;
        Debug.Log("left shift 연산 : " + result); //결과는 5이다.  2진법으로 0000 0000 0000 0000 0000 0000 0000 0101
    }
}
cs



not 연산에서  음수가 되는 부분은 1의 보수, 2의 보수 개념을 알아야 하는데 복잡하니까 나중에 따로 다루겠다.





위에서처럼 숫자 연산을 할때 뿐만 아니라, 유니티 내에서 비트연산, 특히 시프트 연산을 사용하는 경우가 있다. 바로 LayerMask이다.


유니티에는 레이어라는 개념이 있는데, 특정 레이어에 소속된 게임오브젝트끼리만 물리충돌이 일어나게 하거나, 카메라를 특정 레이어에 소속된 게임오브젝트만 선별해서 모니터에 그리도록 할 수 있다.

유니티의 레이어 설정


유니티의 레이어 마스크는 레이어의 정보를 비트로 판별한다. 예를 들어 위 사진의 우측상단에서

Default레이어의 레이어 마스크 : 0000

TransparentFX레이어의 레이어 마스크 : 0001

Ignore Raycast레이어의 레이어 마스크 : 0010


이런식으로 오른쪽을 시작으로 하나의 비트 자릿수를 하나의 레이어가 상징하고 있다. 마치 위의 학용품 예제에서 우측기준 두번째 자릿수를 공책이 대표하듯 말이다.

내가 Enemy레이어의 레이어 마스크를 스크립트 내에서 사용하고 싶다고 해보자. Enemy레이어의 번호는 8번이므로, 2진수로 보자면 1000 0000 레이어마스크를 사용해야하고, 그것은 시프트 연산자를 이용하면 1<<8이다.


보통 게임오브젝트를 감지하는 RayCast를 사용할 때 특정 레이어에 속한 게임오브젝트만 감지하고 싶을 때 매개변수 중에 layerMask를 넣는데, 이때 방법은 2가지이다.


1
2
3
4
5
6
7
8
9
10
11
12
private void Update()
{
    if (Physics.Raycast(transform.position, transform.forward, Mathf.Infinity, 1 << 8))
    {
        Debug.Log("enemy!(shift)");
    }
 
    if (Physics.Raycast(transform.position, transform.forward, Mathf.Infinity, LayerMask.GetMask("Enemy")))
    {
        Debug.Log("enemy!(name)");
    }
}
cs



두개의 레이캐스트 모두 Enemy를 잘 감지하는 것을 알 수 있다.

+ Recent posts