Article | [JS] 비트 연산자(bitwise operator)

noopy·2021년 9월 9일
0

✏️ STUDY

목록 보기
2/10

팀원들과 함께하는 모던 JS 딥다이브 스터디 2차 💕

비트연산자

비트연산자는 피연산자를 32비트 정수로 변환해 이진 연산을 수행 후 십진수로 바꿔 반환한다.
JS는 모든 숫자를 64비트 부동소수점 방식으로 저장하지만,
비트연산을 수행할 땐 32비트 정수로 변환 해 연산 수행 후 다시 64비트로 변환해 저장한다.

⚠️ 32비트 정수로 변환했을 때 초과한다면 최상위 비트를 버린다.

11100110111110100000000000000110000000000001 // 30274560
            10100000000000000110000000000001 // 20971712

연산자 목록

  • 비트 AND(&)
  • 비트 OR(|)
  • 비트 XOR(^)
  • 비트 NOT(~)
  • 왼쪽 시프트(LEFT SHIFT)(<<)
  • 오른쪽 시프트(RIGHT SHIFT)(>>)
  • 부호 없는 오른쪽 시프트(ZERO-FILL RIGHT SHIFT)(>>>)

비트 AND(&)

const a = 5; // 00000000000000000000000000000101 (0101)
const b = 3; // 00000000000000000000000000000011 (0011)

console.log(a & b) // 0001 = 1

비교 대상인 두 비트가 1이면 1을 반환한다. 두 비트가 다를 경우 0을 반환한다.

12 & 15 // 1100 & 1111 = 1100 = 12

비트 OR(|)

const a = 5; // 00000000000000000000000000000101 (0101)
const b = 3; // 00000000000000000000000000000011 (0011)

console.log(a | b) // 0101 | 0011 = 0111

비교 대상인 두 비트 중 하나라도 1이면 1을 반환한다. 둘다 0이면 0을 반환한다.

console.log(12 | 15) // 1100 | 1111 = 1111 = 15

비트 XOR(^)

const a = 5; // 00000000000000000000000000000101 (0101)
const b = 3; // 00000000000000000000000000000011 (0011)

console.log(a | b) // 0101 | 0011 = 0110 = 6

비교 대상인 두 비트가 같으면 0을, 다르면 1을 반환한다.

console.log(12 | 15) // 1100 & 1111 

비트 NOT(~) ⭐️

const a = 5; // 00000000000000000000000000000101 (0101)
const b = 3; // 00000000000000000000000000000011 (0011)

console.log(~a) // 
// 00000000000000000000000000000010 
// 11111111111111111111111111111010 // 

피연산자를 2의 보수 형식으로 부호가 있는 32비트 정수로 변환한다.

컴퓨터의 음수 표현 (보수법)

컴퓨터에는 음수란 개념이 없다. 따라서 보수라는 것을 쓴다.

보수: 보충해주는 수
ex) 1에 대한 10의 보수: -9
ex) 2에 대한 1의 보수: 1

1. 부호비트방식

최상위비트를 부호비트로 사용하는 방식
최상위비트가 0이면 양수, 1이면 음수

⚠️ 문제점) 2진수의 계산이 힘들어짐

0001 + 1001 = 1010 (-2)
1 + -1 = -2???

2. 1의 보수법

1의 보수: 음수 표현 시에 0을 1로, 1을 0으로 바꾸는 것
1을 2진수로 표현: 0001
1을 1의 보수로 표현: 1110


0010 + 1110 = 10000 🧐
2 + -1 = 0

// ⚠️ 1의 보수는 overflow 발생 시 캐리값을 결과값에 더해줘야 함.

0010 + 1110 = 0000 + 0001 = 0001
2 + -1 = 1
1101 + 0001 = 1110 ☺️
-2 + 1 = -1
0001 + 1110 = 1111 🧐
1 + -1 = -0

1의 보수는 1111(-0), 0000(+0) 이라는 2개의 0을 갖는다.

3. 2의 보수법

음수표현 시 1의 보수의 문제점을 해결하기 위해 1의 보수에서 1을 더한 것.


0010 + 1111 = 10001 = 0001
2 + -1 = 1

// 최상위비트가 1이지만 무시

1110 + 0001 = 1111
-2 + 1 = -1
1111 + 0001 = 10000 = 0000
-1 + 1 = 0

왼쪽 시프트(LEFT SHIFT)(<<)

두 개의 피연산자를 사용한다.
첫번째 피연산자는 정수,
두번째 피연산자는 왼쪽으로 shift 시킬 비트의 수.
🔥 요약: 왼쪽 시프트 = 왼쪽을 줄임.

const a = 5; 
console.log(a << 3) 
// 00000000000000000000000000000101 (0101) = 5
// (***)00000000000000000000000000101(000) = 2^5 + 2^3 = 32 + 8 = 40

// ***는 초과되서 버리는 비트

const b = 3; // 00000000000000000000000000000011 (0011)
console.log(b << 2)
// (**)000000000000000000000000000011(00) = 2^3 + 2^2 = 12

오른쪽 시프트(RIGHT SHIFT)(>>)

부호비트가 복사되어 늘어남.
부호가 변하지 않으므로 Sign-propagating(부호 유지) right shift 라는 이름이 붙었다. (길어...)
🔥 요약: 오른쪽 시프트 = 오른쪽을 줄임.

const a = 5; 
console.log(a >> 3) 
// 00000000000000000000000000000101 (0101) = 5
// (000)00000000000000000000000000000(***) = 0

const b = 3; // 00000000000000000000000000000011 (0011)
console.log(b >> 3)
// 00000000000000000000000000000011 (0011)
// (000)00000000000000000000000000000(***) = 0

const c = 150; // 00000000000000000000000010010110 (10010110)
console.log(c >> 3)
// 00000000000000000000000010010110
// (000)00000000000000000000000010010(***) = 18

부호없는 오른쪽 시프트(ZERO-FILL RIGHT SHIFT)(>>>)

0비트를 부호비트 앞으로 추가함.

const c = 150; // 00000000000000000000000010010110 (10010110)
const minusC = -150; // 11111111111111111111111101101001 

console.log(c >> 3)
// 00000000000000000000000010010110
// (000)00000000000000000000000010010(***) = 18

console.log(minusC >>> 3)
// 11111111111111111111111101101001
// 00011111111111111111111111101101(***) = 536870893

비트 연산자를 활용한 코테 문제 풀어보기

2018 카카오 신입 공채 1번

참고사이트

MDN | 비트연산자
[JavaScript 33가지 개념] 12. Bitwise Operator(비트 연산자)
연산자 (산술연산자/비트연산자)
1의 보수
2의 보수를 쓰는 이유와 2의 보수법

profile
💪🏻 아는 걸 설명할 줄 아는 개발자 되기

0개의 댓글