비트 마스크 자바

자이로 체펠리·2021년 12월 2일
0

baeldung
baeldung의 문서를 번역하고 따라함으로써 비트마스크를 알아봐보자.

1. Overview

튜토리얼에선 bitwise 연산자를 사용해 저수준의 비트마스킹을 구현하고 하나의 int 변수를 각각의 데이터를 저장하는 컨테이너로써 처리하는가를 배우게 된다.

2. 비트마스킹이란?

비트마스크는 다수의 값을 하나의 수로 이뤄진 변수에 저장하는 것을 의미한다. 하나의 숫자로서 변수를 바라보는 것이 아니라, 각 값을 비트의 관점으로 바라본다.
비트는 0이나 1로 이뤄지기 때문에 참이나 거짓으로 생각할 수 있다. 또한 비트의 그룹을 자를수 있고, 그들을 작은 숫자 변수 혹은 문자열로 취급할 수 있다.

2-1 예시

최소의 메모리를 사용하여 int 변수안에 유저의 계정의 모든 정보를 저장할 필요가 있다고 가정하자.
먼저 8bits는 유저의 계정이 "활성화 되었는가?" 혹은 "프리미엄인가?"와 같은 불린 정보를 저장할 것이다.
이제 24bits가 남았다, 이것을 3개의 캐릭터로 전환함으로써 우리는 유저의 식별자로 사용할 것이다.

2-2 encoding

유저의 id 는 "AAA" 이고 active와 preminum 상태이다(첫째와 둘째 비트에 저장된다.) 바이너리 형태의 표현은 이렇게 된다.

String stringRepresentation = "01000001010000010100000100000011";

stringReprestation은 Integer의 빌트인 메서드 parseUnsignedInt를 사용하면 int형으로 쉽게 인코딩 할 수 있다.

int intRepresentation = Integer.parseUnsgnedInt(stringRepresentation, 2);
assertEquals(intReresentation, 1094795523);

2-3 decoding

이 프로세스는 Integer #toBinaryString 메서드를 사용하면 반대로 할 수도있다.

String binaryString = Integer.toBinaryString(intRepresentation);
String stringRepresentation = padWithZeros(binaryString);
assertEquals(stringRepresentation, "01000001010000010100000100000011");

3. Extracting one bit

3.1 first bit

어카운트 변수의 첫번째 bit를 확인하기 위해서, bitwise 'and' 연산자와 비트마스크화한 1이 필요하다. 바이너리화한 1은 첫번째 비트가 1이고 나머지는 모드 0으로 이뤄져있기 때문에 첫번째 비트를 제외하고 변수의 모든 비트를 지워버릴 것이다.

10000010100000101000001000000011
00000000000000000000000000000001
-------------------------------- &
00000000000000000000000000000001

연산후에 0과 같지 않은지 확인해야한다.

intRepresentation & 1 != 0

3.2 bit at arbitray position

다른 임의의 자리에 비트를 확인하기 위해서, 적절한 마스크를 생성하고, 주어진 자리의 비트를 제외하고 모두 0으로 리셋해야한다. 가장 쉬운 방법은 shift를 사용하는 것이다.

1<< (position -1)

position이 3이라면 다음과 같은 연산이 이뤄진다.

00000000000000000000000000000001
=>
00000000000000000000000000000100

and 연산을 하면 다음과 같다.

10000010100000101000001000000011
00000000000000000000000000000100
-------------------------------- &
00000000000000000000000000000000

메서드는 다음과 같다.

private boolean extractValueAtPosition(int intRepresentation, int position) {
    return ((intRepresentation) & (1 << (position - 1))) != 0;
}

4. Extracting multiple bits

정수로 부터 다수의 bits를 추출하기 위해 비슷한 메서드를 사용할 것이다. 유저의 account 변수로 부터 마지막 3바이트를 추출하고, 문자열로 변환해 보자.
첫번째로 첫번째 8비트를 우측으로 shift 함으로써 지울 필요가 있다.

int lastThreeBites = intRepresentation >> 0;
String StringRepresentation = getStringRepresentation(lastTreeBites);
assertEquals(stringRepresentation, "00000000010000010100000101000001");

int는 32bint이기 때문에 여전히 stringRepresentation은 32bits이다. 우리가 관심있는건 24bits이기 때문에 나머지 bits는 0으로 초기화 했다.
이제 바이너라화한 stringRepresentation을 8개의 character그룹으로 나누고, 그것들을 char 변수로 파싱하고, 이를 이어붙여 문자열 로 만들것이다.
편리하게 하기위해 빈 bytes는 무시한다.

Arrays.stream(stringRepresentation.split("(?<=\\G.{8})"))
 .filter(eightBits -> !eightBits.equals("00000000"))
 .map(eightBits -> (char)Integer.parseInt(eightBits, 2))
 .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append)
 .toString();
profile
"경의를 표해라. 경의를 갖고 회전의 다음 단계로 나아가는 거다…… [LESSON 4] 다."

0개의 댓글