출시·고도화 중
비트 연산 안내서 · 6/6
비트 연산은 알고리즘 문제에만 나오지 않습니다. 운영 체제의 파일 권한, 네트워크 주소, 해시 테이블, 데이터베이스 인덱스, 게임 엔진까지 성능과 메모리가 중요한 곳이라면 어디에나 있습니다. 이 장에서는 실제 사례와 언어별 함정, 더 읽을거리를 정리합니다.
여러 개의 켜짐/꺼짐 옵션을 정수 하나에 담는 것이 가장 흔한 쓰임입니다. Unix 파일 권한 755는 8진수로 쓴 9개의 비트(소유자·그룹·기타 사용자 각각 rwx)입니다. Python의 enum.Flag, C#의 [Flags] 열거형, Java의 EnumSet도 내부적으로 비트를 씁니다.
import stat
from enum import Flag, auto
mode = 0o754 # rwxr-xr--
print(bool(mode & stat.S_IXUSR)) # True: 소유자 실행 가능
print(bool(mode & stat.S_IWGRP)) # False: 그룹 쓰기 불가
print(stat.filemode(stat.S_IFREG | mode)) # -rwxr-xr--
class Perm(Flag):
READ = auto()
WRITE = auto()
EXECUTE = auto()
user = Perm.READ | Perm.WRITE
print(Perm.WRITE in user, Perm.EXECUTE in user) # True False
user &= ~Perm.WRITE
print(user) # Perm.READIPv4 주소는 32비트 정수이고, 서브넷 마스크와 AND 하면 네트워크 주소가 나옵니다. 라우터와 방화벽이 패킷마다 하는 일이 바로 이 연산입니다.
import ipaddress
ip = int(ipaddress.IPv4Address("192.168.10.77"))
prefix = 24
mask = (0xFFFFFFFF << (32 - prefix)) & 0xFFFFFFFF
print(ipaddress.IPv4Address(ip & mask)) # 192.168.10.0
print(ipaddress.ip_interface("192.168.10.77/24").network) # 192.168.10.0/24HashMap은 테이블 크기를 2의 거듭제곱으로 맞추고 (n - 1) & hash로 칸을 고릅니다. 나머지 연산보다 싸기 때문입니다.SETBIT, GETBIT, BITCOUNT로 일별 접속 여부 같은 대량의 불리언 값을 적은 메모리로 저장합니다.i & -i로 다음 구간으로 이동합니다.==가 &보다 먼저 계산되어 x & 1 == 0이 x & (1 == 0)으로 읽힙니다. 비트 연산에는 항상 괄호를 칩니다.1 << 31은 음수이고, C++의 1 << 40은 int 범위를 넘습니다. 넓은 마스크는 1L << i(Java), 1ULL << i(C++), 1n << 40n(JavaScript BigInt)로 만듭니다.1 << 32가 1입니다. C++에서는 정의되지 않은 동작입니다.>>는 부호를 유지하고 >>>는 0을 채웁니다. C++는 부호 없는 타입에서 논리 시프트를 하며, 부호 있는 음수의 오른쪽 시프트는 C++20부터 산술 시프트로 정해졌습니다.bin(-5)는 -0b101입니다. 32비트 결과를 흉내 내려면 & 0xFFFFFFFF로 자릅니다.def to_int32(x: int) -> int:
x &= 0xFFFFFFFF
return x - (1 << 32) if x & 0x80000000 else x
print(to_int32(1 << 31)) # -2147483648: Java·JS의 1 << 31과 같음
print(-1 & 0xFFFFFFFF) # 4294967295: JS의 -1 >>> 0과 같음
print(to_int32(0xDEADBEEF)) # -559038737XOR 교환(a ^= b; b ^= a; a ^= b)은 요즘 컴파일러에서 더 빠르지도 않고, 같은 변수를 가리키면 값이 0이 되므로 쓰지 않는 편이 낫습니다. 비트 트릭은 이름 있는 상수와 작은 함수로 감싸 읽는 사람을 배려하세요.
비트 연산은 플래그, 권한, 네트워크 주소, 해시 테이블, 비트맵 인덱스처럼 많은 불리언 값을 빠르고 작게 다뤄야 하는 곳에 쓰입니다. 우선순위와 정수 폭, 시프트 규칙이 언어마다 다르다는 점만 조심하면, 짧고 빠른 코드를 안전하게 쓸 수 있습니다.
댓글 0개
로그인 · 로그인하면 댓글을 남길 수 있습니다.
첫 댓글을 남겨 보세요.