맨위로가기

비트 연산

"오늘의AI위키"는 AI 기술로 일관성 있고 체계적인 최신 지식을 제공하는 혁신 플랫폼입니다.
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.

1. 개요

비트 연산은 컴퓨터에서 데이터를 비트 단위로 조작하는 연산으로, 논리 연산과 시프트 연산으로 나뉜다. 논리 연산에는 NOT, AND, OR, XOR 등이 있으며, 각 비트 단위로 불리언 연산을 수행한다. 시프트 연산은 비트를 왼쪽 또는 오른쪽으로 이동시키는 연산으로, 산술 시프트, 논리 시프트, 순환 시프트 등이 있다. 비트 연산은 장치 드라이버, 저수준 그래픽, 통신 프로토콜 등 다양한 분야에서 활용되며, 비트 마스크, 팝카운트 등의 기법으로 특정 비트를 추출하거나 확인할 수 있다. C/C++, Java, JavaScript, Pascal 등 다양한 프로그래밍 언어에서 비트 연산자를 제공하며, 시프트 연산 시 비트 수 초과 등의 경우에 주의해야 한다.

더 읽어볼만한 페이지

  • 프로그래밍 구성체 - 형 변환
    형 변환은 프로그래밍에서 변수의 데이터 타입을 변경하는 것으로, 암시적 형 변환과 명시적 형 변환으로 나뉘며, 객체 지향 프로그래밍에서는 업캐스팅과 다운캐스팅이 발생하고, 각 언어는 고유한 규칙과 방법을 제공하며 잘못된 형 변환은 오류를 유발할 수 있다.
  • 프로그래밍 구성체 - 연산자 오버로딩
    연산자 오버로딩은 프로그래밍 언어에서 기존 연산자를 사용자 정의 자료형에 대해 재정의하여 내장 자료형처럼 다루도록 하는 기능으로, 코드 가독성과 표현력을 높이지만 남용 시 코드 의미를 모호하게 만들 수 있다.
비트 연산
기본 정보
이름비트 연산
종류컴퓨터 과학
정의하나 이상의 비트 패턴 또는 이진수에 작용하는 기본 연산
종류이항 연산
단항 연산
비트 연산자AND (&)
OR (|)
XOR (^)
NOT (~)
비트 시프트 (<<, >>, >>>)
연산 종류
AND두 비트가 모두 1일 때 1을 반환
OR두 비트 중 하나라도 1일 때 1을 반환
XOR두 비트가 서로 다를 때 1을 반환
NOT비트를 반전 (0은 1로, 1은 0으로)
왼쪽 시프트 (<<)비트를 왼쪽으로 이동시키고, 빈 자리는 0으로 채움
오른쪽 시프트 (>>)비트를 오른쪽으로 이동시키고, 빈 자리는 부호 비트로 채움 (산술적 시프트)
부호 없는 오른쪽 시프트 (>>>)비트를 오른쪽으로 이동시키고, 빈 자리는 0으로 채움 (논리적 시프트)
활용
마스크특정 비트를 선택하거나 수정하는 데 사용
플래그 설정특정 조건이나 상태를 나타내는 데 사용
암호화간단한 암호화 알고리즘에 사용될 수 있음
하드웨어 제어하드웨어를 직접 제어하는 데 사용
데이터 압축데이터 압축 알고리즘에 사용

2. 비트 연산의 종류

등가style="border-top:none" |0NOT
(p OR q)
(NOT p)
AND q
NOT
p
p AND
(NOT q)
NOT
q
p XOR qNOT
(p AND q)
style="border-top:none" |p AND qNOT
(p XOR q)
q(NOT p)
OR q
pp OR
(NOT q)
p OR q1



복잡한 비트 연산 표현식은 불 대수를 통해 단순화할 수 있다. 이는 고급 프로그래밍 언어를 효율적인 기계어로 변환하는 컴파일러 작성에 유용하다.

=== NOT (비트 단위 NOT) ===

'''NOT''' 연산은 각 자릿수의 값을 반대로 바꾸는 단항 연산이다. 0은 1로, 1은 0으로 바꾼다.

:NOT 0111

:= 1000

C / C++에서는 `x = ~y;`와 같이 사용한다. 델파이에서는 `x := not y;`와 같이 사용한다.

이 연산은 어떤 값의 1의 보수를 구하거나, 2의 보수를 구할 때 중간 단계로 사용될 수 있다. 2의 보수 산술을 사용하면 `NOT x = -x − 1`이 된다. 부호 없는 정수의 경우, `NOT x = 255 - x` (8비트 기준)처럼 범위 중간 지점을 기준으로 숫자를 "거울 반사"하는 효과를 낸다. 회색조 이미지 반전에 활용할 수 있다.

`~(~x) = x`이다. '''비트 반전'''이라고도 한다.

=== AND (비트 단위 AND) ===

'''AND''' 연산은 두 값의 각 자릿수를 비교해, 두 값 모두에 1이 있을 때에만 1을, 나머지 경우에는 0을 계산한다.

비트 1비트 2결과
000
010
100
111



:0101

:AND 0011

:= 0001

C / C++에서는 `x = y & z;`와 같이 사용한다. 델파이에서는 `x := y and z;`와 같이 사용한다.

4비트 정수의 비트 AND 연산


'''비트 AND'''는 이진 연산으로, 두 개의 동일한 길이의 이진 표현에서 각 쌍의 해당 비트에 대해 논리 AND 연산을 수행한다. 두 비트가 모두 1이면 결과 비트는 1, 그렇지 않으면 0이다.

:010'''1''' (10진수 5)

:AND 001'''1''' (10진수 3)

:= 000'''1''' (10진수 1)

이는 '''비트 마스크''' 연산으로, 특정 비트가 설정(1)되었는지 또는 지워졌는지(0) 확인하는 데 사용된다. 0 값은 관심 없는 비트를 마스크한다.

또한, 레지스터의 선택된 비트(플래그)를 지우는 데 사용되어, 여러 불리언 값을 효율적으로 저장할 수 있다. 최하위 비트 값을 확인하여 이진수의 패리티를 쉽게 확인할 수 있다.

=== OR (비트 단위 OR) ===

'''OR''' 연산은 두 값의 각 자릿수를 비교해, 둘 중 하나라도 1이 있다면 1을, 아니면 0을 계산한다.

비트 1비트 2결과
000
011
101
111



:0101

:OR 0011

:= 0111

C / C++에서는 `x = y | z;`와 같이 사용한다. 델파이에서는 `x := y or z;`와 같이 사용한다.

4비트 정수의 비트 OR


'''비트 단위 OR'''은 두 개의 같은 길이의 비트 패턴을 입력으로 받아, 같은 위치의 비트마다 논리적 OR을 수행하여 같은 길이의 비트 패턴을 출력하는 연산이다. 각 비트 위치에서 입력된 두 비트 중 하나라도 1이면, 출력 비트는 1이 된다.

:0101

:OR 0011

:= 0111

비트 단위 OR은 비트열이 플래그 열로 취급될 때 자주 사용된다. 즉, 각 비트가 개별적으로 부울 값을 나타내는 경우이다. 어떤 이진수 값과 하나 이상의 1을 포함하는 비트열을 비트 단위 OR하면, 후자의 비트열에서 1이 있는 위치가 결과 비트열에서도 1이 된다.

:0010

:OR 1000

:= 1010

MIPS 아키텍처에서는 명령어 집합을 축소하기 위해 비트 단위 OR을 사용한다. 레지스터 간 로드 명령어 대신, 제로 레지스터와 다른 레지스터의 비트 단위 OR 결과를 저장하는 방식으로 레지스터 간 로드를 구현한다.

=== XOR (비트 단위 XOR) ===

'''XOR''' 연산은 두 값의 각 자릿수를 비교해, 값이 같으면 0, 다르면 1을 계산한다.[21]

비트 1비트 2결과
000
011
101
110



:0101

:XOR 0011

:= 0110

C / C++에서는 `x = y ^ z;`와 같이 사용한다. 델파이에서는 `x := y xor z;`와 같이 사용한다.

4비트 정수의 비트 XOR


'''비트 XOR'''은 이항 연산으로, 동일한 길이의 두 개의 비트 패턴에서 각 쌍의 해당 비트에 대해 논리 배타적 OR 연산을 수행한다. 두 비트 중 하나만 1인 경우 1, 둘 다 0이거나 둘 다 1인 경우 0이다.

:0'''10'''1 (10진수 5)

:XOR 0'''01'''1 (10진수 3)

:= 0'''11'''0 (10진수 6)

비트 XOR은 레지스터에서 선택된 비트를 반전(토글)하는 데 사용될 수 있다.

어셈블리어 프로그래머와 최적화 컴파일러는 XOR을 사용하여 레지스터의 값을 0으로 설정하는 지름길로 사용한다. 값에 대해 XOR 연산을 수행하면 항상 0이 생성된다.[21] 같은 레지스터를 지정한 XOR 명령을 실행하여 같은 레지스터로 되돌림으로써 그 내용을 0으로 만들 수 있다.

== 시프트 연산 ==

'''비트 시프트'''는 값을 수치량보다는 일련의 비트로 취급하기 때문에, 때때로 비트 연산으로 간주된다. 이러한 연산에서 숫자는 왼쪽 또는 오른쪽으로 이동하거나 "시프트"된다. 컴퓨터 프로세서의 레지스터는 고정된 너비를 가지므로, 일부 비트는 한쪽 끝에서 레지스터 밖으로 "시프트 아웃"되고, 같은 수의 비트가 다른 쪽 끝에서 "시프트 인"된다. 비트 시프트 연산자 간의 차이점은 시프트 인된 비트의 값을 결정하는 방식에 있다.[17]

비트 시프트는 크게 시프트 연산(한 방향으로 단순하게 이동시키는 조작)과 로테이트 연산(비트 열의 선두와 꼬리를 이은 것처럼 순환시키는 조작(「순환 시프트」, 「환상 시프트」, 「비트 회전」이라고도 함)으로 나뉜다[17]

전 비트를 일률적으로 이동하는 조작을 "논리 시프트"(logical shift)라고 한다. 한편, 오른쪽 시프트 시 최상위 비트만 움직이지 않고 저장하는 시프트 조작을 "산술 시프트"(arithmetic shift)라고 하며, 이는 최상위 비트를 부호 비트로 하는 "부호 있는 정수"를 처리하는 데 적합하다[17]

컴퓨터 프로세서 내 레지스터의 비트 수(자릿수)는 유한하므로 이에 대한 시프트 연산(한 방향으로 단순하게 이동시키는 조작)은 몇몇 비트가 레지스터에서 튀어나온다. 밖에서 들어오는 비트와 튀어나오는 비트를 어떻게 처리하느냐에 따라 여러 종류가 있다.

=== 산술 시프트 ===

왼쪽 산술 시프트


오른쪽 산술 시프트


'''산술 시프트'''에서 양쪽 끝에서 시프트된 비트는 버려진다. 왼쪽 산술 시프트에서는 0이 오른쪽에 시프트되어 들어오고, 오른쪽 산술 시프트에서는 부호 비트(2의 보수에서 MSB)가 왼쪽에 시프트되어 들어와 피연산자의 부호를 유지한다.[22]

다음은 8비트 레지스터를 2의 보수로 해석한 예이다.

:00010111 (10진수 +23) 왼쪽 시프트

:= 0010111'''0''' (10진수 +46)

:10010111 (10진수 −105) 오른쪽 시프트

:= '''1'''1001011 (10진수 −53)

첫 번째 경우, 가장 왼쪽 숫자가 레지스터의 끝을 지나 시프트되었고, 새로운 0이 가장 오른쪽 위치로 시프트되었다. 두 번째 경우, 가장 오른쪽 1이 시프트되어 나갔고 (아마도 캐리 플래그로), 새로운 1이 가장 왼쪽 위치로 복사되어 숫자의 부호를 유지했다. 여러 번의 시프트는 때때로 특정 자릿수만큼 한 번의 시프트로 단축된다. 예를 들어:

:00010111 (10진수 +23) 왼쪽 2자리 시프트

:= 010111'''00''' (10진수 +92)

''n''만큼의 왼쪽 산술 시프트는 2''n''을 곱하는 것과 동일하며 (산술 오버플로가 발생하지 않는 경우), 2의 보수 값의 ''n''만큼의 오른쪽 산술 시프트는 2''n''으로 나눈 값의 바닥을 취하는 것과 동일하다.

C/C++에서는, 왼쪽 시프트와 오른쪽 시프트는 "<<"와 ">>"로 표시된다. 시프트할 너비는 오른쪽 피연산자에 의해 지정할 수 있다.

:x = y << 2;

이 예에서는, ''y''를 2자리 왼쪽으로 산술 시프트한 결과를 ''x''에 저장한다.

1비트의 왼쪽 산술 시프트는 2배하는 것과 같다. 1비트의 오른쪽 산술 시프트는, '''값이 음수가 아니면''' 2로 나누고 나머지를 버리는 것과 같다.

음의 값을 오른쪽으로 산술 시프트한 경우에는, 시프트해서 넘쳐난 비트가 1이라면(복수 시프트의 경우에는, 넘쳐난 비트 안에 1이 있는 경우에는), 결과에 1을 더하면, 2 또는 2의 거듭제곱으로 나누고 나머지를 버리는 것과 같아진다.

=== 논리 시프트 ===

오른쪽 논리적 시프트


'''논리적 시프트'''에서는 버려진 비트를 대체하기 위해 0이 삽입된다. 따라서 논리적 좌측 시프트와 산술적 좌측 시프트는 정확히 동일하다.

그러나 논리적 우측 시프트는 부호 비트를 복사하는 대신 최상위 비트에 0 비트 값을 삽입하므로 부호 없는 이진수에 이상적이며, 산술적 우측 시프트는 부호 있는 2의 보수 이진수에 이상적이다.

=== 순환 시프트 (비트 회전) ===

또 다른 형태의 시프트는 ''순환 시프트'', ''비트 단위 회전'' 또는 ''비트 회전''이다. 이 연산은 때때로 ''캐리 없음 회전''이라고도 하며, 비트가 레지스터의 왼쪽과 오른쪽 끝이 연결된 것처럼 "회전"된다.

왼쪽 시프트 동안 오른쪽에 시프트되는 값은 왼쪽에서 시프트된 값이고, 오른쪽 시프트 연산의 경우 그 반대이다. 이는 기존의 모든 비트를 유지해야 할 필요가 있을 때 유용하며, 디지털 암호학에서 자주 사용된다.

2. 1. 논리 연산

등가style="border-top:none" |0NOT
(p OR q)
(NOT p)
AND q
NOT
p
p AND
(NOT q)
NOT
q
p XOR qNOT
(p AND q)
style="border-top:none" |p AND qNOT
(p XOR q)
q(NOT p)
OR q
pp OR
(NOT q)
p OR q1



복잡한 비트 연산 표현식은 불 대수를 통해 단순화할 수 있다. 이는 고급 프로그래밍 언어를 효율적인 기계어로 변환하는 컴파일러 작성에 유용하다.

;NOT (비트 단위 NOT)

'''NOT''' 연산은 각 자릿수의 값을 반대로 바꾸는 단항 연산이다. 0은 1로, 1은 0으로 바꾼다.

:NOT 0111

:= 1000

C / C++에서는 `x = ~y;`와 같이 사용한다. 델파이에서는 `x := not y;`와 같이 사용한다.

이 연산은 어떤 값의 1의 보수를 구하거나, 2의 보수를 구할 때 중간 단계로 사용될 수 있다. 2의 보수 산술을 사용하면 `NOT x = -x − 1`이 된다. 부호 없는 정수의 경우, `NOT x = 255 - x` (8비트 기준)처럼 범위 중간 지점을 기준으로 숫자를 "거울 반사"하는 효과를 낸다. 회색조 이미지 반전에 활용할 수 있다.

`~(~x) = x`이다. '''비트 반전'''이라고도 한다.

;AND (비트 단위 AND)

'''AND''' 연산은 두 값의 각 자릿수를 비교해, 두 값 모두에 1이 있을 때에만 1을, 나머지 경우에는 0을 계산한다.

비트 1비트 2결과
000
010
100
111



:0101

:AND 0011

:= 0001

C / C++에서는 `x = y & z;`와 같이 사용한다. 델파이에서는 `x := y and z;`와 같이 사용한다.

'''비트 AND'''는 이진 연산으로, 두 개의 동일한 길이의 이진 표현에서 각 쌍의 해당 비트에 대해 논리 AND 연산을 수행한다. 두 비트가 모두 1이면 결과 비트는 1, 그렇지 않으면 0이다.

:010'''1''' (10진수 5)

:AND 001'''1''' (10진수 3)

:= 000'''1''' (10진수 1)

이는 '''비트 마스크''' 연산으로, 특정 비트가 설정(1)되었는지 또는 지워졌는지(0) 확인하는 데 사용된다. 0 값은 관심 없는 비트를 마스크한다.

또한, 레지스터의 선택된 비트(플래그)를 지우는 데 사용되어, 여러 불리언 값을 효율적으로 저장할 수 있다. 최하위 비트 값을 확인하여 이진수의 패리티를 쉽게 확인할 수 있다.



;OR (비트 단위 OR)

'''OR''' 연산은 두 값의 각 자릿수를 비교해, 둘 중 하나라도 1이 있다면 1을, 아니면 0을 계산한다.

비트 1비트 2결과
000
011
101
111



:0101

:OR 0011

:= 0111

C / C++에서는 `x = y | z;`와 같이 사용한다. 델파이에서는 `x := y or z;`와 같이 사용한다.

'''비트 단위 OR'''은 두 개의 같은 길이의 비트 패턴을 입력으로 받아, 같은 위치의 비트마다 논리적 OR을 수행하여 같은 길이의 비트 패턴을 출력하는 연산이다. 각 비트 위치에서 입력된 두 비트 중 하나라도 1이면, 출력 비트는 1이 된다.

:0101

:OR 0011

:= 0111

비트 단위 OR은 비트열이 플래그 열로 취급될 때 자주 사용된다. 즉, 각 비트가 개별적으로 부울 값을 나타내는 경우이다. 어떤 이진수 값과 하나 이상의 1을 포함하는 비트열을 비트 단위 OR하면, 후자의 비트열에서 1이 있는 위치가 결과 비트열에서도 1이 된다.

:0010

:OR 1000

:= 1010

MIPS 아키텍처에서는 명령어 집합을 축소하기 위해 비트 단위 OR을 사용한다. 레지스터 간 로드 명령어 대신, 제로 레지스터와 다른 레지스터의 비트 단위 OR 결과를 저장하는 방식으로 레지스터 간 로드를 구현한다.

;XOR (비트 단위 XOR)

'''XOR''' 연산은 두 값의 각 자릿수를 비교해, 값이 같으면 0, 다르면 1을 계산한다.[21]

비트 1비트 2결과
000
011
101
110



:0101

:XOR 0011

:= 0110

C / C++에서는 `x = y ^ z;`와 같이 사용한다. 델파이에서는 `x := y xor z;`와 같이 사용한다.

'''비트 XOR'''은 이항 연산으로, 동일한 길이의 두 개의 비트 패턴에서 각 쌍의 해당 비트에 대해 논리 배타적 OR 연산을 수행한다. 두 비트 중 하나만 1인 경우 1, 둘 다 0이거나 둘 다 1인 경우 0이다.

:0'''10'''1 (10진수 5)

:XOR 0'''01'''1 (10진수 3)

:= 0'''11'''0 (10진수 6)

비트 XOR은 레지스터에서 선택된 비트를 반전(토글)하는 데 사용될 수 있다.

어셈블리어 프로그래머와 최적화 컴파일러는 XOR을 사용하여 레지스터의 값을 0으로 설정하는 지름길로 사용한다. 값에 대해 XOR 연산을 수행하면 항상 0이 생성된다.[21] 같은 레지스터를 지정한 XOR 명령을 실행하여 같은 레지스터로 되돌림으로써 그 내용을 0으로 만들 수 있다.

2. 1. 1. NOT (비트 단위 NOT)

'''NOT''' 연산은 각 자릿수의 값을 반대로 바꾸는 연산이다.

NOT 0111

= 1000

C / C++

x = ~y;

델파이

x := not y;

이 연산은 어떤 값의 보수를 구할 때 효과적으로 사용할 수 있다.

'''비트 NOT''' 또는 '''비트 보수'''는 각 비트에 대해 논리 부정을 수행하여 주어진 이진 값의 1의 보수를 형성하는 단항 연산이다. 0인 비트는 1이 되고 1인 비트는 0이 된다. 예를 들어,

NOT '''0'''111 (10진수 7)

= '''1'''000 (10진수 8)

NOT 10101011 (10진수 171)

= 01010100 (10진수 84)

결과는 값의 2의 보수에서 1을 뺀 것과 같다. 2의 보수 산술을 사용하면 `NOT x = -x − 1`이 된다.

부호 없는 정수의 경우, 숫자의 비트 보수는 부호 없는 정수의 범위 중간 지점을 기준으로 숫자의 "거울 반사"이다. 예를 들어, 8비트 부호 없는 정수의 경우 `NOT x = 255 - x`이며, 이는 0에서 255까지 증가하는 범위를 255에서 0까지 감소하는 범위로 효과적으로 "뒤집는" 아래쪽 선으로 그래프에서 시각화할 수 있다. 간단하지만 설명적인 사용 예는 각 픽셀이 부호 없는 정수로 저장된 회색조 이미지를 반전하는 것이다.
'''비트 단위 NOT''' 또는 '''보수'''는 논리 부정을 각 비트에 대해 수행하는 단항 연산이다. 0은 1이 되고, 1은 0이 된다. 각 비트를 반전시키므로 '''비트 반전'''이라고도 한다.

NOT 0111

= 1000

C 언어나 C++에서는, NOT 연산자는 "~" (틸다)이다.

x = ~y;

이 예에서, ''x''에 "NOT ''y''"의 결과를 저장한다. 이는 C 및 C++의 논리 "부정" 연산자 "!" (느낌표)와는 다르다. 이쪽은 주어진 수치 전체를 하나의 부울로 취급한다.

x = !y;

이 예에서는, ''x''에 ''y''가 "false"라면 "true"를 나타내는 부울 값을 저장하고, ''y''가 "true"라면 "false"를 저장한다. C나 C++에서는, 수치는 0이 아닐 때 "true"를 나타낸다고 한다. 논리 "부정"은 비트 레벨의 연산이 아니므로, 일반적으로 비트 연산으로 생각하지 않는다.

비트 단위 NOT은 이진수 1의 보수를 만드는 데 사용할 수 있다. 그리고 2의 보수를 만들 때 중간 단계로도 사용된다.

2. 1. 2. AND (비트 단위 AND)

'''AND''' 연산은 두 값의 각 자릿수를 비교해, 두 값 모두에 1이 있을 때에만 1을, 나머지 경우에는 0을 계산한다.

비트 1비트 2결과
000
010
100
111



0101

AND 0011

= 0001

C / C++

: x = y & z;

델파이

: x := y and z;

'''비트 AND'''는 두 개의 동일한 길이의 이진 표현을 받아 각 쌍의 해당 비트에 대해 논리 AND 연산을 수행하는 이진 연산이다. 따라서 비교된 위치의 두 비트가 모두 1이면 결과 이진 표현의 비트는 1(1 × 1 = 1)이고, 그렇지 않으면 결과는 0(1 × 0 = 0 및 0 × 0 = 0)이다. 예를 들어:

:010'''1''' (10진수 5)

:AND 001'''1''' (10진수 3)

:= 000'''1''' (10진수 1)

이 연산은 특정 비트가 '설정'(1)되었는지 또는 '지워졌는지'(0)를 확인하는 데 사용할 수 있다. 예를 들어, 비트 패턴 0011 (10진수 3)이 주어졌을 때, 두 번째 비트가 설정되었는지 확인하려면 두 번째 비트에만 1이 포함된 비트 패턴으로 비트 AND를 사용한다.

:00'''1'''1 (10진수 3)

:AND 00'''1'''0 (10진수 2)

:= 00'''1'''0 (10진수 2)

결과 0010이 0이 아니므로 원래 패턴의 두 번째 비트가 설정되었음을 알 수 있다. 이를 종종 '비트 마스킹'이라고 한다. (유사하게 마스킹 테이프를 사용하여 변경하면 안 되는 부분이나 관심 없는 부분을 덮거나 '마스크'한다. 이 경우 0 값은 관심 없는 비트를 마스크한다.)

비트 AND는 각 비트가 개별 불리언 상태를 나타내는 레지스터의 선택된 비트(또는 플래그)를 지우는 데 사용할 수 있다. 이 기술은 가능한 적은 메모리를 사용하여 여러 불리언 값을 저장하는 효율적인 방법이다.

예를 들어, 0110 (10진수 6)은 오른쪽에서 왼쪽으로 번호가 매겨진 네 개의 플래그 집합으로 간주할 수 있으며, 여기서 첫 번째 및 네 번째 플래그는 지워지고(0), 두 번째 및 세 번째 플래그는 설정된다(1). 세 번째 비트에만 0이 있는 패턴으로 비트 AND를 사용하여 세 번째 플래그를 지울 수 있다.

:0'''1'''10 (10진수 6)

:AND 1'''0'''11 (10진수 11)

:= 0'''0'''10 (10진수 2)

이러한 속성 때문에 최하위 비트의 값을 확인하여 이진수의 패리티를 쉽게 확인할 수 있다. 위의 예를 사용하면:

:0110 (10진수 6)

:AND 0001 (10진수 1)

:= 0000 (10진수 0)

6 AND 1이 0이므로 6은 2로 나누어지며 짝수이다.


'''비트 단위 AND'''는 두 개의 같은 길이의 비트 패턴을 입력으로 받아, 같은 위치의 비트마다 논리적인 AND를 수행하여 같은 길이의 비트 패턴을 출력하는 연산이다. 각 비트 위치에서 입력되는 두 비트가 모두 1이면, 출력 비트는 1이 된다.

:0101

:AND 0011

:= 0001

C/C++에서는, 비트 단위 AND 연산자는 "&" (앰퍼샌드)로 나타낸다.

:x = y & z;

이 예에서, "''y'' AND ''z''"의 결과를 ''x''에 저장한다. 이는, C/C++의 논리 "곱" 연산자 "&&" (두 개의 앰퍼샌드)와는 다르다. 이쪽은 피연산자를 불리언 값으로 취급하고, 결과를 "true" 또는 "false"로 한다.

비트 단위 AND는 '''비트 마스크''' 연산으로 사용되기도 한다. 이는, 비트 열의 일부를 추출하는 데 사용되거나, 특정 비트가 1인지 0인지를 조사하는 데에도 사용된다.

; 비트열의 일부를 추출하는 예

:11001011

이 예에서, 꼬리 4비트 분량의 데이터를 추출하려면 추출하고 싶은 비트 위치만 1로 한 비트 패턴을 입력한다.

:11001011

:AND 1111

:= 1011

; 특정 비트 확인 예

:0101

이 예에서, 두 번째 비트가 1인지 확인하려면 비트 단위 AND에 대해, 조사하고 싶은 비트 위치만 1로 한 비트 패턴을 입력한다.

:0101

:AND 0010

:= 0000

이 결과가 0이므로, 두 번째 비트는 0이었음을 알 수 있다. 이러한 비트 단위 AND의 사용법은 비트 마스크라고 불린다. 이 때, 관심 없는 비트 위치는 0으로 한다.

2. 1. 3. OR (비트 단위 OR)

'''OR''' 연산은 두 값의 각 자릿수를 비교해, 둘 중 하나라도 1이 있다면 1을, 아니면 0을 계산한다.

비트 1비트 2결과
000
011
101
111



```

0101

OR 0011

= 0111

```

C / C++

```

x = y | z;

```

델파이

```

x := y or z;

```

'''비트 단위 OR'''은 두 개의 같은 길이의 비트 패턴을 입력으로 받아, 같은 위치의 비트마다 논리적 OR을 수행하여 같은 길이의 비트 패턴을 출력하는 연산이다. 각 비트 위치에서 입력된 두 비트 중 하나라도 1이면, 출력 비트는 1이 된다.

```

0101

OR 0011

= 0111

```

C/C++에서는 비트 단위 OR 연산자는 "|" (세로 막대)로 표기한다.

```

x = y | z;

```

이 예시에서는 "''y'' OR ''z''"의 결과를 ''x''에 저장한다. 이는 C/C++의 논리 '합' 연산자 "||" (두 개의 세로 막대)와 다르다. 이 연산자는 피연산자를 논리값으로 취급하고, 결과를 "true" 또는 "false"로 한다.

비트 단위 OR은 비트열이 플래그 열로 취급될 때 자주 사용된다. 즉, 각 비트가 개별적으로 부울 값을 나타내는 경우이다. 어떤 이진수 값과 하나 이상의 1을 포함하는 비트열을 비트 단위 OR하면, 후자의 비트열에서 1이 있는 위치가 결과 비트열에서도 1이 된다.

```

0010

```

이 비트열은 4개의 플래그를 나타내는 것으로 간주한다. 첫 번째, 두 번째, 네 번째는 (0)으로 설정되어 있고, 세 번째는 (1)로 설정되어 있다. 첫 번째 플래그를 설정하려면, 이 비트열에 비트 단위 OR을 수행하면 된다. 이때 다른 비트열은 첫 번째 비트만 1로 설정한다.

```

0010

OR 1000

= 1010

```

이 기술은 메모리가 적은 환경의 프로그램에서 자주 사용된다. 하나의 비트 패턴으로 다양한 상태를 한 번에 표현할 수 있기 때문이다.

또한 MIPS 아키텍처에서는, 명령어 집합을 축소하기 위해 이를 사용한다. MIPS에는 레지스터 간 로드(레지스터에서 레지스터로의 값 복사) 명령어가 없다. 그 대신, 내용이 항상 0이고, 무엇을 써도 값이 변하지 않는 제로 레지스터가 있다. 따라서, 레지스터 간 로드는 비트 단위 OR 명령어를 사용하여, 제로 레지스터와 어떤 레지스터의 비트 단위 OR 결과를 다른 레지스터에 저장함으로써 구현된다.

2. 1. 4. XOR (비트 단위 XOR)

'''XOR''' 연산은 두 값의 각 자릿수를 비교해, 값이 같으면 0, 다르면 1을 계산한다.[21]

비트 1비트 2결과
000
011
101
110



0101

XOR 0011

= 0110

C / C++

x = y ^ z;

델파이

x := y xor z;

'''비트 XOR'''은 동일한 길이의 두 개의 비트 패턴을 취하여 각 쌍의 해당 비트에 대해 논리 배타적 OR 연산을 수행하는 이항 연산이다. 각 위치의 결과는 두 비트 중 하나만 1인 경우 1이고, 둘 다 0이거나 둘 다 1인 경우 0이다. 여기서 두 비트를 비교하여 두 비트가 다르면 1이고 같으면 0이 된다. 예를 들어,

0'''10'''1 (10진수 5)

XOR 0'''01'''1 (10진수 3)

= 0'''11'''0 (10진수 6)

비트 XOR은 레지스터에서 선택된 비트를 반전(토글 또는 플립이라고도 함)하는 데 사용될 수 있다. 1과 XOR 연산을 수행하여 모든 비트를 토글할 수 있다. 예를 들어, 비트 패턴 0010 (10진수 2)가 주어지면 두 번째 및 네 번째 비트는 두 번째 및 네 번째 위치에 1을 포함하는 비트 패턴과의 비트 XOR을 통해 토글될 수 있다.

'''0'''0'''1'''0 (10진수 2)

XOR '''1'''0'''1'''0 (10진수 10)

= '''1'''0'''0'''0 (10진수 8)

이 기술은 부울 상태 집합을 나타내는 비트 패턴을 조작하는 데 사용될 수 있다.

어셈블리어 프로그래머와 최적화 컴파일러는 때때로 XOR을 사용하여 레지스터의 값을 0으로 설정하는 지름길로 사용한다. 값에 대해 XOR 연산을 수행하면 항상 0이 생성되며, 많은 아키텍처에서 이 연산은 0 값을 로드하여 레지스터에 저장하는 것보다 더 적은 클럭 사이클과 메모리를 필요로 한다.[21]

'''비트 단위 XOR'''은 두 개의 같은 길이의 비트 패턴을 입력으로 받아, 같은 위치의 비트마다 논리적 XOR을 수행하여 같은 길이의 비트 패턴을 출력하는 연산이다. 각 비트 위치에서 입력하는 두 비트가 서로 다른 값이면, 출력 비트는 1이 된다.

0101

XOR 0011

= 0110

C/C++에서는 비트 단위 XOR 연산자는 "^" (캐럿)으로 나타낸다.

x = y ^ z;

이 예제에서는 "''y'' XOR ''z''"의 결과를 ''x''에 저장한다.

어셈블리 언어 프로그래머는 레지스터의 내용을 0으로 만들고 싶을 때 XOR 연산을 수행한다. 같은 값을 비트 단위 XOR의 두 입력으로 사용하면, 출력은 항상 0이 된다. 즉, 같은 레지스터를 지정한 XOR 명령을 실행하여 같은 레지스터로 되돌림으로써 그 내용을 0으로 만들 수 있다.[21]

비트 단위 XOR은 플래그의 값을 변경할 때도 사용된다.

0010

이 비트 패턴에서 1번째 비트와 3번째 비트를 동시에 변경하고 싶을 경우, 다른 비트 패턴으로 그 바꾸고 싶은 위치에 1을 놓아둔다.

0010

XOR 1010

= 1000

이 기술은 비트 패턴을 부울 변수의 열로 취급할 때 사용될 것이다.

2. 2. 시프트 연산

'''비트 시프트'''는 값을 수치량보다는 일련의 비트로 취급하기 때문에, 때때로 비트 연산으로 간주된다. 이러한 연산에서 숫자는 왼쪽 또는 오른쪽으로 이동하거나 "시프트"된다. 컴퓨터 프로세서의 레지스터는 고정된 너비를 가지므로, 일부 비트는 한쪽 끝에서 레지스터 밖으로 "시프트 아웃"되고, 같은 수의 비트가 다른 쪽 끝에서 "시프트 인"된다. 비트 시프트 연산자 간의 차이점은 시프트 인된 비트의 값을 결정하는 방식에 있다.[17]

비트 시프트는 크게 시프트 연산(한 방향으로 단순하게 이동시키는 조작)과 로테이트 연산(비트 열의 선두와 꼬리를 이은 것처럼 순환시키는 조작(「순환 시프트」, 「환상 시프트」, 「비트 회전」이라고도 함)으로 나뉜다[17]

전 비트를 일률적으로 이동하는 조작을 "논리 시프트"(logical shift)라고 한다. 한편, 오른쪽 시프트 시 최상위 비트만 움직이지 않고 저장하는 시프트 조작을 "산술 시프트"(arithmetic shift)라고 하며, 이는 최상위 비트를 부호 비트로 하는 "부호 있는 정수"를 처리하는 데 적합하다[17]

컴퓨터 프로세서 내 레지스터의 비트 수(자릿수)는 유한하므로 이에 대한 시프트 연산(한 방향으로 단순하게 이동시키는 조작)은 몇몇 비트가 레지스터에서 튀어나온다. 밖에서 들어오는 비트와 튀어나오는 비트를 어떻게 처리하느냐에 따라 여러 종류가 있다.

== 산술 시프트 ==

'''산술 시프트'''에서 양쪽 끝에서 시프트된 비트는 버려진다. 왼쪽 산술 시프트에서는 0이 오른쪽에 시프트되어 들어오고, 오른쪽 산술 시프트에서는 부호 비트(2의 보수에서 MSB)가 왼쪽에 시프트되어 들어와 피연산자의 부호를 유지한다.[22]

다음은 8비트 레지스터를 2의 보수로 해석한 예이다.

:00010111 (10진수 +23) 왼쪽 시프트

:= 0010111'''0''' (10진수 +46)

:10010111 (10진수 −105) 오른쪽 시프트

:= '''1'''1001011 (10진수 −53)

첫 번째 경우, 가장 왼쪽 숫자가 레지스터의 끝을 지나 시프트되었고, 새로운 0이 가장 오른쪽 위치로 시프트되었다. 두 번째 경우, 가장 오른쪽 1이 시프트되어 나갔고 (아마도 캐리 플래그로), 새로운 1이 가장 왼쪽 위치로 복사되어 숫자의 부호를 유지했다. 여러 번의 시프트는 때때로 특정 자릿수만큼 한 번의 시프트로 단축된다. 예를 들어:

:00010111 (10진수 +23) 왼쪽 2자리 시프트

:= 010111'''00''' (10진수 +92)

''n''만큼의 왼쪽 산술 시프트는 2''n''을 곱하는 것과 동일하며 (산술 오버플로가 발생하지 않는 경우), 2의 보수 값의 ''n''만큼의 오른쪽 산술 시프트는 2''n''으로 나눈 값의 바닥을 취하는 것과 동일하다.

'''산술 시프트'''는 오른쪽 시프트에서 최상위 비트(2의 보수 표현이라면 부호 비트)가 보존된다. 왼쪽 시프트는 (일부 예외를 제외하고) 후술하는 논리 시프트와 같으며, 비어있는 비트 위치에는 0이 들어간다. 이 시프트에서는 넘치는 비트는 단순히 사라진다(프로세서의 구현에 따라 플래그에 들어가는 경우도 있다). 아래의 예는 4비트 레지스터의 경우이다.

:0111 LEFT-SHIFT

:= 1110

:1011 RIGHT-SHIFT

:= 1101

전자의 예는, 왼쪽 끝의 0은 넘쳐서 사라지고, 새로운 0이 오른쪽 끝에 들어간다. 후자의 예는, 오른쪽 끝의 1은 넘쳐서 사라지고, 부호 비트 1이 왼쪽 끝에 복사된다. 넘쳐난 비트는, 많은 경우 캐리 플래그에 설정된다. 멀티플 시프트는, 싱글 시프트를 반복한 것과 같은 결과가 된다.

:0111 LEFT-SHIFT-BY-TWO

:= 1100

C/C++에서는, 왼쪽 시프트와 오른쪽 시프트는 "<<"와 ">>"로 표시된다. 시프트할 너비는 오른쪽 피연산자에 의해 지정할 수 있다.

:x = y << 2;

이 예에서는, ''y''를 2자리 왼쪽으로 산술 시프트한 결과를 ''x''에 저장한다.

1비트의 왼쪽 산술 시프트는 2배하는 것과 같다. 1비트의 오른쪽 산술 시프트는, '''값이 음수가 아니면''' 2로 나누고 나머지를 버리는 것과 같다.

음의 값을 오른쪽으로 산술 시프트한 경우에는, 시프트해서 넘쳐난 비트가 1이라면(복수 시프트의 경우에는, 넘쳐난 비트 안에 1이 있는 경우에는), 결과에 1을 더하면, 2 또는 2의 거듭제곱으로 나누고 나머지를 버리는 것과 같아진다.

== 논리 시프트 ==

'''논리적 시프트'''에서는 버려진 비트를 대체하기 위해 0이 삽입된다. 따라서 논리적 좌측 시프트와 산술적 좌측 시프트는 정확히 동일하다.

그러나 논리적 우측 시프트는 부호 비트를 복사하는 대신 최상위 비트에 0 비트 값을 삽입하므로 부호 없는 이진수에 이상적이며, 산술적 우측 시프트는 부호 있는 2의 보수 이진수에 이상적이다.

논리 시프트에서는 오른쪽 시프트 시 빈 비트를 0으로 채운다. 나머지는 산술 시프트와 같다. 따라서 논리 시프트는 부호 없는 이진수를 다루는 데 적합하며, 산술 시프트는 2의 보수 표현의 부호 있는 이진수를 다루는 데 적합하다.

== 순환 시프트 (비트 회전) ==

또 다른 형태의 시프트는 ''순환 시프트'', ''비트 단위 회전'' 또는 ''비트 회전''이다. 이 연산은 때때로 ''캐리 없음 회전''이라고도 하며, 비트가 레지스터의 왼쪽과 오른쪽 끝이 연결된 것처럼 "회전"된다.

왼쪽 시프트 동안 오른쪽에 시프트되는 값은 왼쪽에서 시프트된 값이고, 오른쪽 시프트 연산의 경우 그 반대이다. 이는 기존의 모든 비트를 유지해야 할 필요가 있을 때 유용하며, 디지털 암호학에서 자주 사용된다.

'''순환 시프트'''는 '''비트 로테이션'''이라고도 한다. 이는 비트 열의 좌우 끝이 연결된 것처럼 취급하여 시프트하는 것이다. 시프트 방향의 끝에서 넘치는 비트는 반대쪽 끝에 배치된다. 이는 존재하는 비트를 보존해야 할 때 비트의 위치를 변경하는 데 사용된다.

2. 2. 1. 산술 시프트



'''산술 시프트'''에서 양쪽 끝에서 시프트된 비트는 버려진다. 왼쪽 산술 시프트에서는 0이 오른쪽에 시프트되어 들어오고, 오른쪽 산술 시프트에서는 부호 비트(2의 보수에서 MSB)가 왼쪽에 시프트되어 들어와 피연산자의 부호를 유지한다.[22]

다음은 8비트 레지스터를 2의 보수로 해석한 예이다.

:00010111 (10진수 +23) 왼쪽 시프트

:= 0010111'''0''' (10진수 +46)

:10010111 (10진수 −105) 오른쪽 시프트

:= '''1'''1001011 (10진수 −53)

첫 번째 경우, 가장 왼쪽 숫자가 레지스터의 끝을 지나 시프트되었고, 새로운 0이 가장 오른쪽 위치로 시프트되었다. 두 번째 경우, 가장 오른쪽 1이 시프트되어 나갔고 (아마도 캐리 플래그로), 새로운 1이 가장 왼쪽 위치로 복사되어 숫자의 부호를 유지했다. 여러 번의 시프트는 때때로 특정 자릿수만큼 한 번의 시프트로 단축된다. 예를 들어:

:00010111 (10진수 +23) 왼쪽 2자리 시프트

:= 010111'''00''' (10진수 +92)

''n''만큼의 왼쪽 산술 시프트는 2''n''을 곱하는 것과 동일하며 (산술 오버플로가 발생하지 않는 경우), 2의 보수 값의 ''n''만큼의 오른쪽 산술 시프트는 2''n''으로 나눈 값의 바닥을 취하는 것과 동일하다. 이진수가 1의 보수로 처리되는 경우, 동일한 오른쪽 시프트 연산은 2''n''으로 나누어 0에 가깝게 반올림하는 결과를 낳는다.

'''산술 시프트'''는 오른쪽 시프트에서 최상위 비트(2의 보수 표현이라면 부호 비트)가 보존된다. 왼쪽 시프트는 (일부 예외를 제외하고) 후술하는 논리 시프트와 같으며, 비어있는 비트 위치에는 0이 들어간다. 이 시프트에서는 넘치는 비트는 단순히 사라진다(프로세서의 구현에 따라 플래그에 들어가는 경우도 있다). 아래의 예는 4비트 레지스터의 경우이다.

:0111 LEFT-SHIFT

:= 1110

:1011 RIGHT-SHIFT

:= 1101

전자의 예는, 왼쪽 끝의 0은 넘쳐서 사라지고, 새로운 0이 오른쪽 끝에 들어간다. 후자의 예는, 오른쪽 끝의 1은 넘쳐서 사라지고, 부호 비트 1이 왼쪽 끝에 복사된다. 넘쳐난 비트는, 많은 경우 캐리 플래그에 설정된다. 멀티플 시프트는, 싱글 시프트를 반복한 것과 같은 결과가 된다.

:0111 LEFT-SHIFT-BY-TWO

:= 1100

C/C++에서는, 왼쪽 시프트와 오른쪽 시프트는 "<<"와 ">>"로 표시된다. 시프트할 너비는 오른쪽 피연산자에 의해 지정할 수 있다. #주의사항도 참조.

:x = y << 2;

이 예에서는, ''y''를 2자리 왼쪽으로 산술 시프트한 결과를 ''x''에 저장한다.

1비트의 왼쪽 산술 시프트는 2배하는 것과 같다. 1비트의 오른쪽 산술 시프트는, '''값이 음수가 아니면''' 2로 나누고 나머지를 버리는 것과 같다.

음의 값을 오른쪽으로 산술 시프트한 경우에는, 시프트해서 넘쳐난 비트가 1이라면(복수 시프트의 경우에는, 넘쳐난 비트 안에 1이 있는 경우에는), 결과에 1을 더하면, 2 또는 2의 거듭제곱으로 나누고 나머지를 버리는 것과 같아진다.

2. 2. 2. 논리 시프트



'''논리적 시프트'''에서는 버려진 비트를 대체하기 위해 0이 삽입된다. 따라서 논리적 좌측 시프트와 산술적 좌측 시프트는 정확히 동일하다.

그러나 논리적 우측 시프트는 부호 비트를 복사하는 대신 최상위 비트에 0 비트 값을 삽입하므로 부호 없는 이진수에 이상적이며, 산술적 우측 시프트는 부호 있는 2의 보수 이진수에 이상적이다.

논리 시프트에서는 오른쪽 시프트 시 빈 비트를 0으로 채운다. 나머지는 산술 시프트와 같다. 따라서 논리 시프트는 부호 없는 이진수를 다루는 데 적합하며, 산술 시프트는 2의 보수 표현의 부호 있는 이진수를 다루는 데 적합하다.

2. 2. 3. 순환 시프트 (비트 회전)

또 다른 형태의 시프트는 ''순환 시프트'', ''비트 단위 회전'' 또는 ''비트 회전''이다. 이 연산은 때때로 ''캐리 없음 회전''이라고도 하며, 비트가 레지스터의 왼쪽과 오른쪽 끝이 연결된 것처럼 "회전"된다.

왼쪽 시프트 동안 오른쪽에 시프트되는 값은 왼쪽에서 시프트된 값이고, 오른쪽 시프트 연산의 경우 그 반대이다. 이는 기존의 모든 비트를 유지해야 할 필요가 있을 때 유용하며, 디지털 암호학에서 자주 사용된다.

'''순환 시프트'''는 '''비트 로테이션'''이라고도 한다. 이는 비트 열의 좌우 끝이 연결된 것처럼 취급하여 시프트하는 것이다. 시프트 방향의 끝에서 넘치는 비트는 반대쪽 끝에 배치된다. 이는 존재하는 비트를 보존해야 할 때 비트의 위치를 변경하는 데 사용된다.

3. 프로그래밍 언어별 비트 연산자

wikitext

==== C/C++ ====

C/C++에서 비트 연산자는 NOT(`~`), AND(`&`), OR(`|`), XOR(`^`) 연산자와 왼쪽 시프트 연산자(`<<`), 오른쪽 시프트 연산자(`>>`)가 있다.[4][2] 시프트 연산에서 시프트할 비트 수는 연산자의 두 번째 인수로 지정된다. 예를 들어 `x = y << 2;`는 `y`를 왼쪽으로 2비트 시프트한 결과를 `x`에 할당하며, 이는 4를 곱하는 것과 같다.

시프트 연산을 할 때에는 주의가 필요한데, 비트 수가 워드 크기보다 크거나 같은 값만큼 시프트하는 경우는 C와 C++에서 정의되지 않은 동작을 유발한다.[4][2] 또한, 음수 값을 오른쪽으로 시프트하는 것은 구현 정의 동작이므로 권장되지 않으며,[3] 부호 있는 값을 왼쪽으로 시프트했을 때 결과가 해당 자료형으로 표현할 수 없는 경우에도 정의되지 않은 동작이 발생한다.[4]

==== Java ====

Java에서는 모든 정수형이 부호가 있으므로 "`,`<`,`<`,`"` 및 "`>`>`"` 연산자는 산술 시프트를 수행한다.[10] Java는 논리적 오른쪽 시프트를 수행하기 위해 "`>`>`>`"` 연산자를 추가하지만, 부호 있는 정수의 경우 논리적 및 산술적 왼쪽 시프트 연산이 동일하므로 Java에는 "`<`,`<`,`<`,`"` 연산자가 없다. "`<`,`<`,`"` (왼쪽 시프트), "`>`>`"` (부호 있는 오른쪽 시프트), "`>`>`>`"` (부호 없는 오른쪽 시프트) 연산자를 ''시프트 연산자''라고 한다.[10] 시프트 표현식의 타입은 왼쪽 피연산자의 승격된 타입이다. 예를 들어, `aByte >>> 2`는 `((int) aByte) >>> 2`와 동일하다.

왼쪽 피연산자의 승격된 타입이 `int`인 경우, 오른쪽 피연산자의 최하위 5비트만 시프트 거리로 사용된다. 이는 오른쪽 피연산자가 마스크 값 `0x1f` (0b11111)와 비트 단위 논리 AND 연산자 `&`를 수행한 것과 같다.[11] 따라서 실제로 사용되는 시프트 거리는 항상 0에서 31 사이이다. 왼쪽 피연산자의 승격된 타입이 `long`인 경우, 오른쪽 피연산자의 최하위 6비트만 시프트 거리로 사용된다. 이는 오른쪽 피연산자가 마스크 값 `0x3f` (0b111111)와 비트 단위 논리 AND 연산자 `&`를 수행한 것과 같다.[11] 따라서 실제로 사용되는 시프트 거리는 항상 0에서 63 사이이다. `n >>> s`의 값은 ''n''을 제로 확장하여 ''s'' 비트 위치만큼 오른쪽으로 시프트한 것이다.

비트 및 시프트 연산에서 `''byte''` 타입은 `''int''`로 암시적으로 변환된다. 바이트 값이 음수이면 최상위 비트가 1이므로, 1을 사용하여 `int`의 추가 바이트를 채운다. 따라서 `byte b1 = -5; int i = b1 | 0x0200;`는 `i == -5`가 된다.

==== JavaScript ====

자바스크립트는 비트 연산을 사용하여 두 개 이상의 자리수 각각을 1 또는 0으로 평가한다.[12]

==== Pascal ====

파스칼 및 모든 파생 언어(오브젝트 파스칼, 표준 파스칼 등)에서 논리적 좌측 및 우측 시프트 연산자는 각각 "shl" 및 "shr"이다. 부호 있는 정수에서도 `shr`은 논리적 시프트처럼 동작하며 부호 비트를 복사하지 않는다. 시프트할 자릿수는 두 번째 인수로 제공된다. 예를 들어 `x := y shl 2;`는 ''y''를 왼쪽으로 두 비트 시프트한 결과를 ''x''에 할당한다.

3. 1. C/C++

C/C++에서 비트 연산자는 NOT(`~`), AND(`&`), OR(`|`), XOR(`^`) 연산자와 왼쪽 시프트 연산자(`<<`), 오른쪽 시프트 연산자(`>>`)가 있다.[4][2] 시프트 연산에서 시프트할 비트 수는 연산자의 두 번째 인수로 지정된다. 예를 들어 `x = y << 2;`는 `y`를 왼쪽으로 2비트 시프트한 결과를 `x`에 할당하며, 이는 4를 곱하는 것과 같다.

시프트 연산을 할 때에는 주의가 필요한데, 비트 수가 워드 크기보다 크거나 같은 값만큼 시프트하는 경우는 C와 C++에서 정의되지 않은 동작을 유발한다.[4][2] 또한, 음수 값을 오른쪽으로 시프트하는 것은 구현 정의 동작이므로 권장되지 않으며,[3] 부호 있는 값을 왼쪽으로 시프트했을 때 결과가 해당 자료형으로 표현할 수 없는 경우에도 정의되지 않은 동작이 발생한다.[4]

3. 2. Java

Java에서는 모든 정수형이 부호가 있으므로 "`,`<`,`<`,`"` 및 "`>`>`"` 연산자는 산술 시프트를 수행한다.[10] Java는 논리적 오른쪽 시프트를 수행하기 위해 "`>`>`>`"` 연산자를 추가하지만, 부호 있는 정수의 경우 논리적 및 산술적 왼쪽 시프트 연산이 동일하므로 Java에는 "`<`,`<`,`<`,`"` 연산자가 없다. "`<`,`<`,`"` (왼쪽 시프트), "`>`>`"` (부호 있는 오른쪽 시프트), "`>`>`>`"` (부호 없는 오른쪽 시프트) 연산자를 ''시프트 연산자''라고 한다.[10] 시프트 표현식의 타입은 왼쪽 피연산자의 승격된 타입이다. 예를 들어, `aByte >>> 2`는 `((int) aByte) >>> 2`와 동일하다.

왼쪽 피연산자의 승격된 타입이 `int`인 경우, 오른쪽 피연산자의 최하위 5비트만 시프트 거리로 사용된다. 이는 오른쪽 피연산자가 마스크 값 `0x1f` (0b11111)와 비트 단위 논리 AND 연산자 `&`를 수행한 것과 같다.[11] 따라서 실제로 사용되는 시프트 거리는 항상 0에서 31 사이이다. 왼쪽 피연산자의 승격된 타입이 `long`인 경우, 오른쪽 피연산자의 최하위 6비트만 시프트 거리로 사용된다. 이는 오른쪽 피연산자가 마스크 값 `0x3f` (0b111111)와 비트 단위 논리 AND 연산자 `&`를 수행한 것과 같다.[11] 따라서 실제로 사용되는 시프트 거리는 항상 0에서 63 사이이다. `n >>> s`의 값은 ''n''을 제로 확장하여 ''s'' 비트 위치만큼 오른쪽으로 시프트한 것이다.

비트 및 시프트 연산에서 `''byte''` 타입은 `''int''`로 암시적으로 변환된다. 바이트 값이 음수이면 최상위 비트가 1이므로, 1을 사용하여 `int`의 추가 바이트를 채운다. 따라서 `byte b1 = -5; int i = b1 | 0x0200;`는 `i == -5`가 된다.

3. 3. JavaScript

자바스크립트는 비트 연산을 사용하여 두 개 이상의 자리수 각각을 1 또는 0으로 평가한다.[12]

3. 4. Pascal

파스칼 및 모든 파생 언어(오브젝트 파스칼, 표준 파스칼 등)에서 논리적 좌측 및 우측 시프트 연산자는 각각 "shl" 및 "shr"이다. 부호 있는 정수에서도 `shr`은 논리적 시프트처럼 동작하며 부호 비트를 복사하지 않는다. 시프트할 자릿수는 두 번째 인수로 제공된다. 예를 들어 `x := y shl 2;`는 ''y''를 왼쪽으로 두 비트 시프트한 결과를 ''x''에 할당한다.

4. 비트 연산의 활용

비트 연산은 장치 드라이버, 저수준 그래픽, 통신 프로토콜 패킷 조립 및 디코딩과 같은 저수준 프로그래밍에 필수적이다.[13]

머신은 산술 및 논리 연산을 수행하기 위한 효율적인 내장 명령어를 종종 가지고 있지만, 이러한 모든 연산은 비트 연산자와 제로 테스트를 다양한 방식으로 결합하여 수행할 수 있다.[13] 예를 들어, 다음은 비트 시프트와 덧셈만 사용하여 두 임의의 정수 `a`와 `b`(`a`가 `b`보다 큼)를 곱하는 방법을 보여주는 의사 코드로 구현된 고대 이집트 곱셈의 예시이다.

```c

c ← 0

while b ≠ 0

if (b and 1) ≠ 0

c ← c + a

left shift a by 1

right shift b by 1

return c

```

또 다른 예는 비트 연산자와 제로 테스트를 사용하여 두 정수 `a`와 `b`의 합을 계산하는 방법을 보여주는 덧셈의 의사 코드 구현이다.

```c

while a ≠ 0

c ← b and a

b ← b xor a

left shift c by 1

a ← c

return b

```

기계는 산술 연산과 논리 연산을 수행하기에 충분한 명령을 가지고 있지만, 실제 모든 연산은 비트 연산의 조합과 어떤 종류의 제로 판정 기능만 있으면 실현할 수 있다. 예를 들어, 아래 예시는 두 개의 임의의 정수 '''a''' 와 '''b''' 의 곱셈을 비트 시프트와 덧셈으로 실현하는 의사 코드이다.

```

c := 0

'''while''' b ≠ 0

'''if''' b '''and''' 1 ≠ 0

c := c + a

a를 왼쪽으로 한 비트 시프트

b를 오른쪽으로 한 비트 시프트

'''return''' c

```

4. 1. 응용 예시

비트 연산은 다양한 분야에서 활용된다.

5. 비트 연산 관련 주의사항

비트 시프트 연산을 할 때 오른쪽 피연산자(시프트량)의 값이 음수이거나, 왼쪽 피연산자 타입의 비트 수를 초과하는 경우의 규정은 언어에 따라 다르다.[23] 자바, .NET 언어(C#, VB.NET 등), 자바스크립트 등에서는 "왼쪽 피연산자 타입의 비트 수 -1"의 비트 단위 AND 마스크를 오른쪽 피연산자에 적용하여 최소 1비트의 값을 남긴다.[23] C/C++의 ISO 사양에서는 이와 같은 경우의 결과는 미정의 동작이다.[23] GCC 및 Visual C++의 구현에서는 경고(Warning)가 나오지만, 위와 비슷한 결과를 반환한다.

참조

[1] 웹사이트 CMicrotek Low-power Design Blog http://cmicrotek.com[...] CMicrotek 2015-08-12
[2] 웹사이트 Arithmetic operators - cppreference.com http://en.cppreferen[...] 2016-07-06
[3] 웹사이트 INT13-C. Use bitwise operators only on unsigned operands https://www.secureco[...] Software Engineering Institute, Carnegie Mellon University 2015-09-07
[4] 간행물 'C programming language' http://std.dkuug.dk/[...]
[5] 웹사이트 Operator (C# Reference) http://msdn.microsof[...] Microsoft 2013-07-14
[6] 웹사이트 Near constant time rotate that does not violate the standards? https://stackoverflo[...] Stack Exchange Network 2015-08-12
[7] 웹사이트 Poor optimization of portable rotate idiom https://gcc.gnu.org/[...] GNU GCC Project 2015-08-11
[8] 웹사이트 Circular rotate that does not violate C/C++ standard? https://software.int[...] Intel Developer Forums 2015-08-12
[9] 웹사이트 Constant not propagated into inline assembly, results in "constraint 'I' expects an integer constant expression" https://llvm.org/bug[...] LLVM Project 2015-08-11
[10] 문서 15.19. Shift Operators http://docs.oracle.c[...] The Java Language Specification
[11] 웹사이트 Chapter 15. Expressions http://docs.oracle.c[...]
[12] 웹사이트 JavaScript Bitwise https://www.w3school[...]
[13] 웹사이트 Synthesizing arithmetic operations using bit-shifting tricks http://bisqwit.iki.f[...] Bisqwit.iki.fi 2014-02-15
[14] 문서 Throughout this article, 0xFFFF means that all the bits in your data type need to be set to 1. The exact number of bits depends on the width of the data type.
[15] 문서 - is negation here, not subtraction
[16] 문서 - is subtraction here, not negation
[17] 문서 IT用語辞典 e-words【ビット演算】
[18] 문서 論理的にかぞえ尽くすと16種類あるが、有用なものは以上である。
[19] 서적 ハッカーのたのしみ
[20] 문서 https://www.frontier[...]
[21] 문서 Microsoft Visual C++など、C/C++でゼロを代入するコードを記述した場合、XOR命令を使用するよう最適化するコンパイラも存在する。
[22] 문서 VHDLには論理左シフトと異なる算術左シフトslaがあり [[:en:Arithmetic_shift#cite_note-10]] によれば、空くビット位置を保存する。また [[CASL#COMET の仕様]]にあるSLA命令は、符号ビットを保存しながら左シフトする。
[23] 문서 15.19. Shift Operators - Java Language Specification http://docs.oracle.c[...]



본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.

문의하기 : help@durumis.com