İçeriğe geç
academia.sh

Ders 05 / 16

Bit Düzeyi İşlemler

VE, VEYA, XOR, DEĞİL işleçleri, kaydırmalar ve maskeleme ile alan ayıklama.

İçindekiler

Önceki dersler bit örüntülerini hep bir bütün olarak yorumladı: otuz iki bit birlikte bir tam sayı ya da bir gerçel sayı oluşturuyordu. Programlar ise sık sık örüntünün parçalarıyla çalışır — tek bir baytı ayıklamak, bir bayrağı açmak, bir alanı sıfırlamak gibi.

Bu dersin konusu, bu parça işlemlerini yapan işleçlerdir. Bunlar donanımın en ucuz işlemleri arasındadır ve düşük seviyeli kodun büyük bölümü bunlarla yazılır.

Mantıksal İşleçler

Dört temel işleç, bitler üzerinde tanımlı doğruluk tablolarıyla verilir. İşleçler bit bit uygulanır: sonucun ii’nci biti, girdilerin yalnızca ii’nci bitlerine bağlıdır.

aa bb a&ba \mathbin{\&} b (VE) aba \mid b (VEYA) aba \oplus b (XOR)
0 0 0 0 0
0 1 0 1 1
1 0 0 1 1
1 1 1 1 0

DEĞİL işleci tek girdilidir ve her biti ters çevirir: ¬0=1\lnot 0 = 1, ¬1=0\lnot 1 = 0.

Sekiz bitlik iki örüntü üzerinde:

  1100 1010        1100 1010        1100 1010
& 1010 0110      | 1010 0110      ^ 1010 0110
-----------      -----------      -----------
  1000 0010        1110 1110        0110 1100

Her işlecin ayırt edici bir kullanımı vardır:

  • VE, istenmeyen bitleri sıfırlar: karşısında 00 olan her bit silinir.
  • VEYA, istenen bitleri açar: karşısında 11 olan her bit kurulur.
  • XOR, seçili bitleri ters çevirir; ayrıca “farklı mı?” sorusunun bit karşılığıdır. Bir sayının kendisiyle XOR’u sıfırdır, bu da aynı değerle iki kez XOR yapmanın başlangıç değerine döndüğü anlamına gelir.

Bu işleçlerin mantıksal ve/veya işleçleriyle karıştırılmaması gerekir. Mantıksal işleçler tüm değeri doğru/yanlış olarak ele alır ve çoğu dilde kısa devre yapar; bit düzeyi işleçler her biti bağımsız işler ve kısa devre yapmaz.

Kaydırma

Sola kaydırma (<<) tüm bitleri sola taşır, sağdan sıfır doldurur. Her kaydırma, konum değerlerini iki katına çıkardığı için sayıyı ikiyle çarpar:

0000 01012=0001 0100(5×4=20)\texttt{0000 0101} \ll 2 = \texttt{0001 0100} \qquad (5 \times 4 = 20)

Sağa kaydırma (>>) bitleri sağa taşır ve sayıyı ikiye böler; kesirli kısım atılır. Soldan hangi bitin dolduğu, değerin yorumuna bağlıdır:

  • Mantıksal kaydırma soldan sıfır doldurur; işaretsiz değerler için doğrudur.
  • Aritmetik kaydırma soldan işaret bitinin kopyasını doldurur; işaretli değerlerin işaretini korur.

Bu ayrım, önceki dersteki işaret genişletme kuralının aynısıdır. Python’da tam sayılar işaretlidir ve >> aritmetik davranır: -8 >> 1 sonucu -4, -5 >> 1 sonucu -3’tür (sonuç sıfıra değil, aşağı yuvarlanır).

Sabit genişlikli dillerde kaydırma sayısının veri genişliğine eşit veya daha büyük olması tanımsız davranıştır; 32 bitlik bir değeri 32 kez kaydırmak taşınabilir bir sonuç vermez. Bu, sessizce yanlış çalışan kodun bilinen kaynaklarından biridir.

Maskeleme

Maske, hangi bitlerle ilgilenildiğini belirten sabit bir örüntüdür. Dört temel işlem maskeyle yapılır:

Amaç İşlem Açıklama
Bit sınama deger & maske Sonuç sıfır değilse ilgili bit kuruludur
Bit kurma deger | maske Maskede 11 olan bitler açılır
Bit silme deger & ~maske Maskede 11 olan bitler sıfırlanır
Bit ters çevirme deger ^ maske Maskede 11 olan bitler ters çevrilir

Bir alanı ayıklamak iki adımdır: alanı en sağa kaydır, sonra fazlasını maskele. Kursun ortak örneğinden ikinci baytı almak için:

(0x4142434416) & 0xFF=0x42(\texttt{0x41424344} \gg 16)\ \&\ \texttt{0xFF} = \texttt{0x42}

Kaydırma miktarı, alanın sağdan kaç bit uzakta başladığını; maske ise alanın kaç bit genişliğinde olduğunu söyler. 0xFF sekiz bitlik, 0x0F dört bitlik, 0x01 tek bitlik bir alan seçer.

Aynı yöntem tersinden de çalışır: bir alana değer yazmak için önce alan silinir, sonra yeni değer kaydırılıp VEYA ile yerleştirilir.

Bayrak Kümeleri

Birbirinden bağımsız açık/kapalı seçeneklerin her biri bir bite atanabilir. Bu düzen, tek bir tam sayıda çok sayıda seçeneği taşır ve seçeneklerin birleştirilmesini, sınanmasını ucuz kılar.

OKUMA   = 0b100      # 4
YAZMA   = 0b010      # 2
CALISMA = 0b001      # 1

izin = OKUMA | YAZMA              # 0b110 = 6

print(bool(izin & YAZMA))         # True   — yazma izni var mı?
print(bool(izin & CALISMA))       # False

izin |= CALISMA                   # çalışma iznini ekle   -> 0b111
izin &= ~YAZMA                    # yazma iznini kaldır   -> 0b101
print(f"{izin:03b}")              # 101

Bu örnekteki üç bit, ikinci derste sekizlik gösterimle yazılan dosya izinlerinin ta kendisidir: 0b101 örüntüsü 5, yani r-x iznidir. Sekizlik gösterimin o alanda tercih edilmesinin nedeni, üçlü bit gruplarının doğrudan tek rakama karşılık gelmesiydi.

Yaygın Deyimler

Bit işleçleriyle kurulan birkaç kalıp, kaynak kodda sık görülür:

  • x & (x - 1) — en sağdaki kurulu biti siler. Sonuç sıfırsa xx ikinin kuvvetidir (yalnız bir biti kuruluydu). Aynı ifade döngüde kullanılarak kurulu bitler sayılır.
  • x & -x — yalnızca en sağdaki kurulu biti bırakır. İkiye tümleyende negatif alma işleminin tanımından çıkar.
  • x << k ve x >> k — ikinin kuvvetleriyle çarpma ve bölme. Derleyiciler bu dönüşümü zaten yapar; kaynakta kaydırma yazmak okunabilirliği düşürür ve başarım kazandırmaz.
  • x ^ maske — seçili bitleri ters çevirme; x ^ x her zaman sıfırdır.

Aşağıdaki program, bu deyimlerin ikisini ve alan ayıklamayı bir arada gösterir:

def ikinin_kuvveti_mi(x: int) -> bool:
    """Pozitif x, tam olarak bir bit kuruluysa ikinin kuvvetidir."""
    return x > 0 and (x & (x - 1)) == 0


def kurulu_bit_sayisi(x: int) -> int:
    """Her adımda en sağdaki kurulu biti silerek sayar."""
    sayac = 0
    while x:
        x &= x - 1
        sayac += 1
    return sayac


deger = 0x41424344
baytlar = [(deger >> k) & 0xFF for k in (24, 16, 8, 0)]

print([hex(b) for b in baytlar])        # ['0x41', '0x42', '0x43', '0x44']
print(ikinin_kuvveti_mi(64))            # True
print(ikinin_kuvveti_mi(48))            # False
print(kurulu_bit_sayisi(deger))         # 9
print(bin(deger).count("1"))            # 9  — aynı sonuç, farklı yol

kurulu_bit_sayisi işlevinin döngüsü, kurulu bit sayısı kadar döner; bit genişliği kadar değil. 0x41424344 örüntüsünde dokuz bit kuruludur (0x41 ve 0x42 ikişer, 0x43 üç, 0x44 iki), dolayısıyla döngü otuz iki değil dokuz kez çalışır.

Özet

  • Bit düzeyi işleçler her biti bağımsız işler; mantıksal işleçlerden farklı olarak değerin tamamını doğru/yanlış olarak ele almazlar.
  • VE bit siler, VEYA bit kurar, XOR bit ters çevirir; bir değerin kendisiyle XOR’u sıfırdır.
  • Sola kaydırma ikiyle çarpar; sağa kaydırma ikiye böler ve soldan doldurma kuralı değerin işaretli yorumlanıp yorumlanmadığına bağlıdır.
  • Alan ayıklama iki adımdır: alanı sağa kaydır, ardından genişliği kadar maske uygula.
  • Bağımsız seçenekler tek bir tam sayıda bayrak bitleri olarak taşınabilir; birleştirme VEYA, sınama VE ile yapılır.
  • x & (x - 1) en sağdaki kurulu biti siler; ikinin kuvveti sınaması ve bit sayımı bu deyime dayanır.

Sonraki Adım

Sayılar için temsil kuralları tamamlandı. Metin ise farklı bir sorun çıkarır: harfler doğal olarak sayı değildir; her karakterin bir sayıya eşlenmesi gerekir ve bu eşleme üzerinde dünya çapında anlaşmak gerekir. Sonraki ders, bu anlaşmanın nasıl kurulduğunu ve kod noktası ile bayt dizisi arasındaki farkın neden önemli olduğunu ele alacak.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat