Di level mesin, bilangan bulat adalah deretan bit. NumPy menyediakan ufunc bitwise untuk mengoperasikan deretan bit itu langsung per elemen, tanpa loop Python. Pemakaiannya nyata: sistem izin berkas gaya Unix yang menyimpan baca/tulis/eksekusi dalam tiga bit, pemadatan status hadir/tidak hadir menjadi satu byte, dan pembacaan pola biner dari data sensor.

Bab ini membahas empat operasi bitwise utama, pergeseran bit, np.packbits/np.unpackbits untuk memadatkan pola biner, serta np.bitwise_count milik NumPy 2.x. Semua fungsi ini berupa ufunc, sehingga bekerja elemen demi elemen dengan kecepatan C.

Empat Operasi Bitwise Utama #

np.bitwise_and, np.bitwise_or, np.bitwise_xor, dan np.bitwise_not membandingkan pasangan bit sesuai aturan logika masing-masing. Untuk memeriksa hasil dengan mata, np.binary_repr menampilkan bentuk biner sebuah bilangan:

python
import numpy as np

a = np.array([12, 10])
b = np.array([10, 3])
print(np.binary_repr(12, width=4), np.binary_repr(10, width=4), np.binary_repr(3, width=4))
print(np.bitwise_and(a, b))
print(np.bitwise_or(a, b))
print(np.bitwise_xor(a, b))

Output yang Dihasilkan:

text
1100 1010 0011
[8 2]
[14 11]
[6 9]

Baris demi baris:

  1. Baris 5 (np.binary_repr): 12 ditampilkan sebagai 1100, 10 sebagai 1010, dan 3 sebagai 0011. Padanan biner inilah acuan membaca tiga baris berikutnya.
  2. Baris 6 (np.bitwise_and): bit hasil bernilai 1 hanya bila kedua bit sumber bernilai 1: 1100 & 1010 = 1000 (8) dan 1010 & 0011 = 0010 (2), sehingga tercetak [8 2].
  3. Baris 7 (np.bitwise_or): bit hasil bernilai 1 bila salah satu bit bernilai 1: 1100 | 1010 = 1110 (14) dan 1010 | 0011 = 1011 (11).
  4. Baris 8 (np.bitwise_xor): bit hasil bernilai 1 bila kedua bit berbeda: 1100 ^ 1010 = 0110 (6) dan 1010 ^ 0011 = 1001 (9).

Studi Kasus Flag Izin Berkas #

Izin berkas gaya Unix memakai tiga bit; satu bilangan menyimpan ketiganya sekaligus sebagai jumlah:

FlagNilaiBinerMakna
BACA4100berkas boleh dibaca
TULIS2010berkas boleh ditulis
EKSEKUSI1001berkas boleh dieksekusi

Nilai 7 (111) berarti baca+tulis+eksekusi, 6 (110) berarti baca+tulis tanpa eksekusi, dan 4 (100) berarti hanya baca. Tiga pola yang paling sering dipakai: memeriksa flag lewat bitwise_and, menambah flag lewat bitwise_or, dan mencabut flag lewat bitwise_and terhadap kebalikan bit dari bitwise_not:

python
import numpy as np

BACA, TULIS, EKSEKUSI = 4, 2, 1
izin = np.array([7, 6, 4, 5])
print(np.bitwise_and(izin, BACA) != 0)
print(np.bitwise_and(izin, EKSEKUSI) != 0)
print(np.bitwise_or(izin, TULIS))
print(np.bitwise_and(izin, np.bitwise_not(EKSEKUSI)))

Output yang Dihasilkan:

text
[ True  True  True  True]
[ True False False  True]
[7 6 6 7]
[6 6 4 4]

Baris demi baris:

  1. Baris 5: np.bitwise_and(izin, BACA) != 0 bernilai True persis bila bit baca menyala; keempat nilai (7, 6, 4, 5) semuanya memuat bit 4.
  2. Baris 6: bit eksekusi hanya menyala pada 7 (111) dan 5 (101); nilai 6 (110) dan 4 (100) tidak memuatnya.
  3. Baris 7: bitwise_or dengan TULIS menyalakan bit tulis tanpa menyentuh bit lain: 4 (100) menjadi 6 (110) dan 5 (101) menjadi 7 (111).
  4. Baris 8: np.bitwise_not(EKSEKUSI) membalik semua bit sehingga hanya bit eksekusi yang padam; bitwise_and dengan mask itu mencabut izin eksekusi: 7 menjadi 6, 6 tetap 6, 4 tetap 4, dan 5 menjadi 4.

Pergeseran Bit dengan left_shift dan right_shift #

np.left_shift(x, n) menggeser bit ke kiri sebanyak n posisi, setara dengan mengalikan dua pangkat n; np.right_shift menggeser ke kanan, setara pembagian bulat dua pangkat n. Pergeseran lazim dipakai untuk membangun nilai flag dari posisi bitnya:

python
import numpy as np

print(np.left_shift(np.array([1, 3, 5]), 2))
print(np.right_shift(np.array([16, 20, 7]), 2))
print(np.binary_repr(np.left_shift(3, 4), width=8))

Output yang Dihasilkan:

text
[ 4 12 20]
[4 5 1]
00110000

Baris demi baris:

  1. Baris 3: 1, 3, dan 5 digeser dua bit ke kiri: 1 menjadi 100 (4), 3 (11) menjadi 1100 (12), dan 5 (101) menjadi 10100 (20).
  2. Baris 4: 16, 20, dan 7 digeser dua bit ke kanan: 16 (10000) menjadi 4, 20 (10100) menjadi 5, dan 7 (111) menjadi 1 karena pembagian bulat membulatkan ke bawah.
  3. Baris 5: 3 digeser kiri empat bit menjadi 48; binary_repr lebar 8 menampilkannya sebagai 00110000.

Memadatkan Pola Biner dengan packbits dan unpackbits #

Delapan status 0/1 yang disimpan sebagai array int memakan delapan byte. np.packbits memadatkan deretan 0/1 menjadi bit di dalam byte, dan np.unpackbits membongkarnya kembali bit demi bit. Untuk array 2-D, parameter axis=1 memadatkan per baris:

python
import numpy as np

pola = np.array([1, 1, 0, 0, 1, 0, 1, 0])
terkemas = np.packbits(pola)
print(terkemas)
print(np.unpackbits(terkemas))
status = np.array([[1, 1, 0], [0, 1, 1]])
print(np.packbits(status, axis=1))

Output yang Dihasilkan:

text
[202]
[1 1 0 0 1 0 1 0]
[[192]
 [ 96]]

Baris demi baris:

  1. Baris 4: deretan 11001010 dibaca sebagai bilangan biner, menghasilkan satu byte bernilai 202.
  2. Baris 6: np.unpackbits mengembalikan delapan bit byte itu dalam urutan semula, [1 1 0 0 1 0 1 0].
  3. Baris 8-9 (axis=1): tiap baris 3 bit dilengkapi lima bit 0 di kanan sebelum dipadatkan: 110 menjadi 11000000 (192) dan 011 menjadi 01100000 (96).

Menghitung Bit Satu dengan np.bitwise_count #

NumPy 2.x menambahkan np.bitwise_count, yang menghitung banyaknya bit bernilai satu pada tiap elemen — operasi yang lazim disebut popcount. Salah satu pemakaian cepatnya adalah menguji paritas:

python
import numpy as np

nilai = np.array([5, 6, 7, 8])
bit_satu = np.bitwise_count(nilai)
print(bit_satu)
print(bit_satu % 2 == 0)

Output yang Dihasilkan:

text
[2 2 3 1]
[ True  True False False]

Baris 4 menjelaskan segalanya: 5 (101) memuat dua bit satu, 6 (110) dua bit, 7 (111) tiga bit, dan 8 (1000) satu bit. Baris 6 lalu menguji paritas genap lewat sisa bagi 2; hasilnya [True True False False].

Satu pembeda penting dibanding bab tetangga: np.logical_and dan kawan-kawan pada Chapter Operasi Boolean menilai kebenaran tiap elemen secara utuh — nol dianggap salah — sedangkan operasi di bab ini menilai tiap bit di dalam elemen. Semua fungsi bab ini adalah ufunc yang menerima array seganda bentuk berkat broadcasting; mekanisme ufunc dibedah tuntas pada Chapter Fungsi Universal (ufunc).