TIL 비트연산자 (feat 이진법)

flobeeee·2021년 8월 21일
0

Today I Learned

목록 보기
17/35
post-thumbnail

⚡ 공부하게 된 계기

다중 조건에 대해 검색 쿼리를 날리는 부분이 있다.
조건을 여러 개 체크한 뒤에 해당 조건을 1개라도 충족하는 결과물을 가져와야 했다.
기존에 작성되어 있는 코드는 너무 복잡해서, 비트연산자를 적용해보라는 미션이 있었다.

⚡ 예시

좋아하는 계절을 조건으로 사람을 검색해본다고 상황을 가정하자.
만약에 검색조건에서 가을이 들어오면 바비와 콩심이를 결과값으로 가져와야 한다.

const season = {
  1: '봄',
  2: '여름',
  4: '가을',
  8: '겨울',
}

// 데이터 베이스라고 생각하자
const users = [
  { '이름': '미미', '좋아하는 계절': 1 }, // 봄
  { '이름': '쥬쥬', '좋아하는 계절': 2 }, // 여름
  { '이름': '바비', '좋아하는 계절': 5 }, // 봄, 가을
  { '이름': '콩심이', '좋아하는 계절': 15 }, // 봄, 여름, 가을, 겨울
]

⚡ before 로직

  1. 데이터 베이스에 있는 좋아하는 계절의 값을 가져온다.
  2. 값을 가공한다 (이 과정이 복잡합니다. 이진수로 변환해서 뒤집고 자릿수 확인하고..)
    미미의 경우 [1]로 변환한다.
    쥬쥬의 경우 [2]로 변환한다.
    바비의 경우 [1, 4]로 변환한다.
    콩심이의 경우 [1, 2, 4, 8]로 변환한다.
  3. 검색 조건에 따라 2에서 포함하는 값이 있으면 해당 결과를 보낸다.
    조건으로 [1]이 들어온 경우, 미미, 바비, 콩심이를 반환한다.
    조건으로 [2]이 들어온 경우, 쥬쥬, 콩심이를 반환한다.
    ...

⚡ 비트연산자란 ?

비트 연산은 한 개 혹은 두 개의 이진수에 대해 비트 단위로 적용되는 연산이라고 한다. (위키백과)
나는 십진수를 이진수로 바꿔서 연산이 되는 것으로 이해했다. (이 부분을 활용했다.)

const season = {
  1: '봄',
  2: '여름',
  4: '가을',
  8: '겨울',
}

const users = [
  { '이름': '미미', '좋아하는 계절': 1 }, // 봄
  { '이름': '쥬쥬', '좋아하는 계절': 2 }, // 여름
  { '이름': '바비', '좋아하는 계절': 5 }, // 봄, 가을
  { '이름': '콩심이', '좋아하는 계절': 15 }, // 봄, 여름, 가을, 겨울
]

표를 참고하여 이 숫자들을 이진수로 바꿔보자.

: 1 =>1
여름: 2 => 10
가을: 4 => 100
겨울: 8 => 1000

미미: 1 => 1
쥬쥬: 2 => 10
바비: 5 (1+4) => 101
콩심이: 15 (1+2+4+8) => 1111

숫자를 더해서 이진수를 확인하면 규칙이 보인다.

십진수를 이진수로 변환했을 때,
1의 자리가 1이면 봄이 있다는 뜻이다. 0이면 봄이 없다는 뜻이다.
10의 자리가 1이면 여름이 있다는 뜻이다. 0이면 없다.
100의 자리가 1이면 가을이 있다는 뜻이다. 0이면 없다.
1000의 자리가 1이면 겨울이 있다는 뜻이다. 0이면 없다.
예를 들어 1010인 경우, 10의 자리와 1000의 자리가 1 이므로, 여름과 겨울 데이터를 포함한다는 뜻이다.

⚡ 비트연산자 적용 로직

비트연산자 중에 이런 게 있다. 겹치는 값을 리턴하는 연산자이다.
겹치는 값이 없으면 0을 리턴한다.

// 여름 + 겨울 = 10
console.log(10 & 1) // 0 
console.log(10 & 2) // 2
console.log(10 & 4) // 0
console.log(10 & 8) // 8

이 연산자를 활용해서 새로운 로직을 작성했다.
before 로직을 비교해서 설명하겠다.

  1. 데이터 베이스에 있는 좋아하는 계절의 값을 가져온다.
  2. 값을 가공한다
    (이 과정이 복잡합니다. 이진수로 변환해서 뒤집고 자릿수 확인하고..)
    미미의 경우 [1]로 변환한다.
    쥬쥬의 경우 [2]로 변환한다.
    바비의 경우 [1, 4]로 변환한다.
    콩심이의 경우 [1, 2, 4, 8]로 변환한다.
  3. 검색 조건에 따라 2에서 포함하는 값이 있으면 해당 결과를 보낸다.
    조건으로 [1]이 들어온 경우, 미미, 바비, 콩심이를 반환한다.
    조건으로 [2]이 들어온 경우, 쥬쥬, 콩심이를 반환한다.
    ...
  1. 1에서 가져온 값과, 검색 조건으로 들어온 값에 & 연산자를 적용한다.
  2. 결과값이 0이면 제외하고, 0이 아니면 해당 유저를 내보낸다.

⚡ 후기

평소 검색과 결과를 보내주는 방식에 관심이 많다.
예전 팀 프로젝트인 땅땅마켓에서도 검색결과 값을 보내주는 로직을 작성했었다.
그 땐 기본 데이터가 많이 없어서, 최대한 많은 결과를 보여주기 위해
키워드가 타이틀과 설명란에 있으면 모두 내보냈다.

하지만 많은 데이터가 있는 경우, 비효율적인 로직이라고 생각한다.
너무 많은 결과 값을 보내줄 수 있기 때문이다.
이 부분을 보완하는 방법에 대해 태그를 다는 방식을 생각했었다.

비트연산자는 여러 조건들에 맞는 결과값을 찾는 데 필수라고 느꼈다.
배워서 바로 적용했을 때 뿌듯했다.
이전에 작성되어 있던 로직도 멋있었지만, 그 길었던 코드를 짧게 수정할 수 있어서 놀라웠다.
더 배우고싶다. 열심히 공부해야겠다.


참고 : 현실에서 유용한 Bitwise 연산 및 활용 모음

profile
기록하는 백엔드 개발자

0개의 댓글