C++의 비트 시프트 연산자

Anam Javed 2023년10월12일
  1. C++의 왼쪽 비트 시프트 연산자
  2. C++의 오른쪽 비트 시프트 연산자
  3. C++의 부동 소수점 데이터 유형에 대한 비트 시프트
  4. C++에서 배열의 비트 시프트
  5. C++의 비트 시프트 및 마스크
  6. C++의 음수 비트 시프트
  7. C++에서 Long을 사용한 비트 시프트
  8. 결론
C++의 비트 시프트 연산자

C++에서 비트 이동 연산자는 이름이 암시하는 대로 비트를 이동합니다. 프로그램의 요구 사항에 따라 비트 시프트 연산자는 이진 비트를 왼쪽 또는 오른쪽으로 이동합니다.

정수 값은 이러한 연산자(int, long, short 가능, byte 또는 char)에 적용됩니다. 일부 언어에서는 int보다 작은 데이터 유형에 시프트 연산자를 사용하면 피연산자의 크기가 자동으로 int로 조정됩니다.

이 기사에서는 관련 예제와 함께 C++의 왼쪽 및 오른쪽 시프트 연산자와 구현에 대해 자세히 설명합니다.

C++의 왼쪽 비트 시프트 연산자

왼쪽 시프트 연산자는 시프트 식의 비트를 덧셈 식의 자리 수만큼 왼쪽으로 이동합니다. 시프트 연산에 의해 비워진 비트 위치는 0으로 채워지고 끝에서 시프트된 비트는 부호 비트를 포함하여 버려집니다.

왼쪽 시프트 연산자는 두 개의 숫자를 사용합니다. 이것은 첫 번째 피연산자의 비트를 이동하고 두 번째 피연산자는 이동할 자리의 수를 결정합니다.

정수 a를 정수 b로 왼쪽 시프트하는 것은 (a<<b)로 표시되는 정수 a2^b를 곱하는 것과 같습니다(2는 b의 거듭제곱). 왼쪽 시프트 연산자는 <<로 표시됩니다.

예를 들어 M<<k. 여기서 M은 첫 번째 피연산자이고 k는 두 번째 피연산자입니다.

M=33; 이는 2진수로 100001이고 k = 2입니다. M이 2만큼 왼쪽으로 시프트되면 M=M<<2로 표시되며 M=M(2^2)이 됩니다.

따라서 M=33(2^2)=132는 10000100으로 쓸 수 있습니다.

예시:

#include <iostream>
using namespace std;

int main() {
  unsigned char x = 6, y = 7;
  cout << "x<<1 = " << (x << 1) << endl;
  cout << "y<<1 = " << (y << 1) << endl;
  return 0;
}

출력:

x<<1 = 12
y<<1 = 14

위의 코드에서 부호 없는 char xchar y 변수는 변수가 메모리의 모든 8비트를 사용하고 부호 비트(부호 있는 char에 있음)가 없는 문자 데이터 유형을 나타냅니다.

여기서 char x는 6, 즉 이진수로 00000110이고 char y는 7, 즉 이진수로 00000111입니다.

첫 번째 인쇄 문은 x의 값을 1비트 왼쪽 시프트하도록 명시합니다. 결과는 00001100입니다. 두 번째 print 문은 y 값을 1비트 왼쪽으로 시프트하라고 말합니다. 결과는 00001110입니다.

C++의 오른쪽 비트 시프트 연산자

오른쪽 시프트 연산자는 덧셈 표현식이 오른쪽으로 제공하는 자릿수만큼 시프트 표현식의 비트 패턴을 이동합니다. 시프트 연산에 의해 비워진 비트 위치는 부호 없는 값에 대해 0으로 채워집니다.

부호 비트는 부호 있는 숫자의 빈 비트 위치를 대체합니다. 숫자가 양수이면 값 0이 사용됩니다. 숫자가 음수이면 값 1이 사용됩니다.

오른쪽 시프트 연산자는 두 개의 숫자를 사용합니다. 이것은 첫 번째 피연산자의 비트를 이동하고 두 번째 피연산자는 이동할 자리의 수를 결정합니다.

정수 a를 정수 b로 오른쪽 시프트하는 것은 (a>>b)로 표시되는 정수 a2^b로 나누는 것과 같습니다(2의 거듭제곱 b). 오른쪽 시프트 연산자는 >>로 표시됩니다.

예: M>>k . 여기서 M은 첫 번째 피연산자이고 k는 두 번째 피연산자입니다.

M=32; 이는 2진수로 100000이고 k = 2입니다. M이 2만큼 오른쪽 시프트되면 M=M>>2로 표시되며 MM=M/(2^2)이 됩니다. 따라서 M=32/(2^2)=8은 1000으로 쓸 수 있습니다.

예제 프로그램:

#include <iostream>

int main() {
  unsigned char x = 6, y = 9;
  cout << "a>>1 = " << (a >> 1) << endl;
  cout << "b>>1 = " << (b >> 1) << endl;
  return 0;
}

출력:

x>>1 = 3
y>>1 = 4

위의 코드에서 부호 없는 char xchar y 변수는 메모리의 8비트를 모두 사용하는 변수의 문자 데이터 유형을 나타내며 부호 비트(signed char에 있음)는 없습니다.

여기서 char x는 6, 즉 이진수로 00000110이고 char y는 9, 즉 이진수로 00001001입니다.

첫 번째 인쇄 문은 x의 값을 1비트 오른쪽 시프트하도록 명시합니다. 결과는 00000011입니다. 두 번째 인쇄 문은 y 값을 1비트 오른쪽으로 이동하도록 명시합니다. 결과는 00000100입니다.

C++의 부동 소수점 데이터 유형에 대한 비트 시프트

C++에서는 float가 오류를 표시하므로 비트 시프트할 수 없지만 그 이유는 무엇입니까? float가 특별한 형식으로 저장되기 때문입니다.

float의 32비트는 유효숫자와 지수의 두 가지 범주로 나뉩니다. 시프트는 잠재적으로 지수 범주에서 유효 범주로 또는 그 반대로 비트를 이동할 수 있습니다.

예시:

#include <stdio.h>

int main(int ar, char *arg[]) {
  float testFl = 2.5;

  printf("testFloat (before): %f\n", testFl);
  testFl = testFl << 1;
  printf("testFloat (after): %f\n", testFl);
  return 0;
}

출력:

error: invalid operands to binary << (have 'float' and 'int')

오른쪽 시프트 또는 왼쪽 시프트는 모든 비트를 축소합니다.

C++에서 배열의 비트 시프트

크기가 n이고 정수 m인 배열 ar[]이 있습니다.

목표는 존재하는 모든 배열 요소에 대해 오른쪽 시프트 연산을 수행하여 모든 배열 요소를 > m으로 만드는 것입니다. 그렇게 할 수 없으면 -1을 인쇄하십시오.

예시:

Input: ar[] = { 21, 22, 23, 19 }, m = 34
Output: { 26, 26, 27, 25 }

Explanation:
ar[0] = 10101
After 1 right shift, 11010 → 26
ar[1] = 10110
After 3 right shift, 11010 → 26
ar[2] = 10111
After  1 right shift, 11011 → 27
ar[3] = 10011
After 2 right shift, 11001 → 25

암호:

#include <bits/stdc++.h>
using namespace std;

int setBitNumber(int n) {
  int m = log2(n);
  return m;
}

bool check(int ar[], int m, int n) {
  for (int i = 0; i < n; i++) {
    if (ar[i] <= m) return false;
  }
  return true;
}

void modifyArray(int ar[], int m, int n) {
  for (int i = 0; i < n; i++) {
    if (ar[i] > m)
      continue;
    else {
      int bits = setBitNumber(ar[i]);
      int el = ar[i];
      for (int j = 0; j < bits; j++) {
        if (el & 1) {
          el >>= 1;
          el |= (1 << bits);
        } else {
          el >>= 1;
        }
        if (el > m) {
          arr[i] = el;
          break;
        }
      }
    }
  }

  if (check(ar, m, n)) {
    for (int i = 0; i < n; i++) cout << ar[i] << " ";
  } else
    cout << -1;
}

int main() {
  int ar[] = {21, 22, 23, 19};
  int n = sizeof(ar) / sizeof(ar[0]);
  int m = 24;
  modifyArray(ar, m, n);
  return 0;
}

출력:

[26, 26, 27, 25]

프로그램에서 수행되는 주요 작업은 배열 순회입니다. 어레이 ar[i]의 각 요소에 대해 오른쪽 시프트 작업을 수행합니다.

ar[i] > m인 경우 조건이 확인됩니다. 그것이 사실이라면 어레이 ar[i]를 업데이트하고, 그렇지 않으면 계속하십시오.

배열 ar[i] ≤ m의 요소가 있으면 -1을 인쇄하고, 그렇지 않으면 ar[i] 배열을 인쇄합니다.

C++의 비트 시프트 및 마스크

마스크는 유지해야 하는 비트와 지워야 하는 비트를 지정합니다.

예시:

Mask:   00001111b
Value:  01010101b

값에 마스크를 적용할 때 첫 번째(상위) 4비트를 지우고 마지막(하위) 4비트를 유지하려고 합니다. 결과적으로 하위 4비트를 검색했습니다.

출력:

Mask:   00001111b
Value:  01010101b
Result: 00000101b

비트 시프트 연산자는 마스킹 작업과 함께 숫자에서 비트를 하나씩 벗겨내는 데 자주 사용됩니다. 다음 예제에서는 부호 없는 문자를 별도의 비트 배열로 나누는 방법을 설명합니다.

unsigned char y = 0xD5;
unsigned char bit[8];
unsigned char mask = 1;
for (int x = 7; x >= 0; x--) {
  bits[x] = y & mask;
  y = y >> 1;
}

C++의 음수 비트 시프트

왼쪽 및 오른쪽 시프트 연산자를 사용하여 음수를 입력하면 안 됩니다. 피연산자 중 하나가 음의 정수이면 결과는 정의되지 않은 동작입니다.

예를 들어 1 >> -11 << -1의 결과는 모두 정의되지 않습니다.

#include <iostream>

int main() {
  unsigned char x = -6, cout << "a>>1 = " << (a >> 1) << endl;
  return 0;
}

출력:

error: undefined behavior in C

C++에서 Long을 사용한 비트 시프트

데이터 유형 long은 32비트 또는 64비트로 비트 시프트하는 데 사용됩니다.

예시:

32비트의 경우,

unsigned long A = (1L << 37)

64비트의 경우,

unsigned long long A = (1ULL << 37);

프로그램을 사용하여 다음을 구현하려면:

#include <stdio.h>

int main(void) {
  long long y = 1ULL;

  // Left shift 40 times
  y <<= 20;
  y <<= 20;

  printf("y is %lld\n", y);
  return 0;
}

출력:

y is 1099511627776

여기에서 64비트 변수 long long y가 사용되었으며 1ULL은 부호 없는 long long int 상수(64비트)입니다. 변수 y가 40번 이동되고 인쇄됩니다.

결론

이 기사에서 우리는 C++의 비트 시프트 연산자에 대해 논의했습니다. C++의 왼쪽 및 오른쪽 시프트 연산자에 대해 자세히 배웠습니다.

관련 문장 - C++ Operator