İçeriğe geç
academia.sh

Ders 03 / 16

İşaretli Tam Sayılar ve İkiye Tümleyen

Negatif sayıların bit örüntüsü içinde kodlanması, ikiye tümleyen gösterim ve taşma davranışı.

İçindekiler

Önceki iki ders sayıları negatif olmayan kabul etti. Oysa donanımda eksi işaretini tutacak fazladan bir yer yoktur: 32 bitlik bir yazmaçta yalnızca 32 bit vardır. İşaret de değerin kendisiyle aynı örüntünün içinde kodlanmak zorundadır.

Bu dersin sorusu, bu kodlamanın nasıl yapılacağıdır. Birden çok yanıt mümkündür; ancak donanım neredeyse tek bir yanıtta birleşmiştir ve bunun nedeni, o yöntemin toplama devresini hiç değiştirmemesidir.

İki Sezgisel Yaklaşım ve Sorunları

İşaret-büyüklük (sign-magnitude) gösteriminde en soldaki bit işareti, kalan bitler büyüklüğü taşır. Sekiz bitte +5+5 için 0000 0101, 5-5 için 1000 0101 yazılır. Bu gösterim insan sezgisine yakındır ve iki sorunu vardır.

Birincisi, sıfırın iki gösterimi olur: 0000 0000 ve 1000 0000. İki örüntü aynı değeri taşıdığında, eşitlik karşılaştırması bit karşılaştırmasından ibaret olmaktan çıkar.

İkincisi ve daha ağırı: toplama artık düz toplama değildir. 5+(5)5 + (-5) hesabı bit düzeyinde yapıldığında 0000 0101 + 1000 0101 = 1000 1010 çıkar; bu örüntü işaret- büyüklük yorumunda 10-10 demektir, oysa sonuç sıfır olmalıydı. Donanımın işaretleri ayıklayıp büyüklükleri karşılaştırması ve çıkarma yapması gerekir.

Bire tümleyen (one’s complement) gösteriminde negatif sayı, pozitifin tüm bitleri ters çevrilerek elde edilir: 5-5 için 1111 1010. Toplama düz toplamaya yaklaşır ancak elde biti yeniden başa eklenmelidir; ayrıca sıfır yine iki gösterimlidir (0000 0000 ve 1111 1111).

İkiye Tümleyen

İkiye tümleyen (two’s complement) gösterimi bu iki sorunu da ortadan kaldırır. Tanımı tek cümleyle verilebilir: en soldaki bitin konum değeri negatiftir. nn bitlik bir örüntünün değeri şudur:

dn1×2n1+i=0n2di×2i-d_{n-1} \times 2^{n-1} + \sum_{i=0}^{n-2} d_i \times 2^{i}

Sekiz bit için en soldaki bitin ağırlığı 128-128, diğerlerininki alışıldık biçimde +64,+32,,+1+64, +32, \dots, +1’dir. Örnekler:

Örüntü Hesap Değer
0000 0101 4+14 + 1 55
1111 1011 128+64+32+16+8+2+1-128 + 64 + 32 + 16 + 8 + 2 + 1 5-5
1111 1111 128+127-128 + 127 1-1
1000 0000 128-128 128-128
0111 1111 127127 127127

Sıfırın tek gösterimi vardır: 0000 0000. En soldaki bit hâlâ işareti ele verir — 11 ise sayı negatiftir — ama bu bit ayrı bir işaret alanı değil, değerin bir parçasıdır.

nn bitlik ikiye tümleyen aralığı şudur:

[2n1, 2n11][-2^{n-1},\ 2^{n-1} - 1]

Aralık bakışımlı değildir: sekiz bitte 128-128 temsil edilir, +128+128 edilemez. Negatif tarafta bir değer fazladır, çünkü sıfır pozitif tarafın bir örüntüsünü harcar.

Negatifi Üretmek

Bir sayının negatifini bulmak için iki adım yeterlidir: tüm bitleri ters çevir, sonuca bir ekle.

55 için: 0000 0101 \rightarrow ters çevir 1111 1010 \rightarrow bir ekle 1111 1011. Sonuç, tablodaki 5-5 örüntüsüdür.

Aynı işlem 5-5’e uygulanınca 55’e dönülür: 1111 1011 \rightarrow 0000 0100 \rightarrow 0000 0101. İşlem kendi tersidir.

Kuralın neden çalıştığı şöyle görülür: bir örüntü ile tersinin toplamı, tüm bitleri 11 olan örüntüdür, yani 2n12^n - 1. Buna bir eklenirse 2n2^n elde edilir; nn bitlik bir yazmaçta 2n2^n değeri sıfıra karşılık gelir. Dolayısıyla xx ile “ters çevir ve bir ekle” sonucu toplandığında sıfır çıkar — negatifin tanımı budur.

Tek istisna en küçük değerdir: 128-128 üzerinde işlem uygulandığında yine 1000 0000 elde edilir. +128+128 aralığın dışında olduğundan, bu değerin negatifi sekiz bitte yoktur.

Toplama Neden Tek Devre

İkiye tümleyenin donanım açısından belirleyici üstünlüğü şudur: işaretli toplama, işaretsiz toplamayla aynı işlemdir. Bitler toplanır, taşan elde biti atılır.

5+(3)5 + (-3) hesabı sekiz bitte:

  0000 0101      (5)
+ 1111 1101      (-3)
-------------
1 0000 0010      (elde biti atılır)
  0000 0010      (2)

Sonuç doğrudur ve bunun için işaretlere bakılmamıştır. Çıkarma da ayrı bir devre gerektirmez: aba - b hesabı, bb’nin negatifi üretilip toplanarak yapılır. Karşılaştırma işlemleri de aynı toplayıcı üzerine kurulur.

Bu, gösterim seçiminin donanım karmaşıklığını doğrudan azalttığı somut bir örnektir. Sezgiye en yakın gösterim (işaret-büyüklük) en pahalı devreyi, sezgiye en uzak gösterim (ikiye tümleyen) en ucuz devreyi verir.

Taşma

Sabit genişlik, aralığın dışına çıkan sonuçların temsil edilememesi anlamına gelir. Sonuç kaybolmaz; aralığın öbür ucundan geri döner.

İşaretsiz yorumda sekiz bitte 255+1255 + 1 hesabı 1111 1111 + 0000 0001 = 1 0000 0000 verir; elde atıldığında geriye 0000 0000, yani 00 kalır. Sayı büyümemiş, başa sarmıştır.

İşaretli yorumda 127+1127 + 1 hesabı 0111 1111 + 0000 0001 = 1000 0000 verir; bu örüntü 128-128 demektir. İki pozitif sayının toplamı negatif çıkmıştır.

İki durum arasındaki fark, aynı bit işleminin farklı yorumlanmasından ibarettir. Donanım her iki taşmayı da ayrı bayraklarla bildirir; hangisinin anlamlı olduğuna, değerin işaretli mi işaretsiz mi yorumlandığını bilen program karar verir.

Taşmanın pratikteki sonucu, sayısal kodun sessizce yanlış sonuç üretebilmesidir. İki büyük pozitif sayının toplamının negatif çıkması, döngü sayaçlarının başa sarması ve dizi indekslerinin beklenmedik yerlere işaret etmesi bu sınıftandır. Bu davranışın güvenlik boyutu, siber güvenlik müfredatında ayrıca ele alınır.

Genişletme

Bir değer daha geniş bir tipe taşınırken boş kalan sol bitler doldurulmalıdır. Değerin korunması için doldurma kuralı yoruma bağlıdır:

  • İşaretsiz değerlerde sol bitler sıfırla doldurulur (sıfır genişletme).
  • İşaretli değerlerde sol bitler işaret bitinin kopyasıyla doldurulur (işaret genişletme). Sekiz bitlik 1111 1011 (5-5), on altı bitte 1111 1111 1111 1011 olur ve değeri korunur.

Yanlış kural uygulanırsa değer sessizce değişir: sekiz bitlik 5-5 örüntüsü sıfır genişletmeyle on altı bitte 0000 0000 1111 1011, yani 251251 olur. Ters yönde, on altı bitlik 5-5 örüntüsü işaretsiz yorumlanırsa 65.53165.531 okunur. Bu, farklı genişlikteki tipler arasında dönüşüm yapan kodun tipik hata kaynaklarından biridir.

Ortak Örneğin İşaretli Yorumu

Kursun ortak örneği 0x41424344 örüntüsünün en soldaki biti 00’dır — ilk onaltılık rakam 4, yani 0100. Bu nedenle örüntü, 32 bitlik işaretli yorumda da işaretsiz yorumdakiyle aynı değeri taşır: 1.094.861.6361.094.861.636.

Örüntünün ilk rakamı 8 olsaydı — yani 0x81424344 — en soldaki bit 11 olur ve aynı işlemler bambaşka bir değer verirdi:

2.168.603.460232=2.126.363.8362.168.603.460 - 2^{32} = -2.126.363.836

Bit dizisi ile onun anlamı arasındaki mesafeyi bundan iyi gösteren bir örnek yoktur: tek bir bitin değişmesi, değeri iki milyarın üzerinde kaydırır.

Uygulamada Görmek

Python’un tam sayıları sabit genişlikte değildir; taşma olmaz, sayı büyür. Sabit genişlikli donanım davranışını gözlemlemek için maskeleme kullanılır:

def sabit_genislik(deger: int, bit: int = 8) -> int:
    """Değeri `bit` genişliğinde ikiye tümleyen yorumuna indirger."""
    maske = (1 << bit) - 1          # 8 bit için 0xFF
    deger &= maske                  # fazla bitleri at
    isaret_biti = 1 << (bit - 1)    # 8 bit için 0x80
    if deger & isaret_biti:
        deger -= 1 << bit           # en soldaki bitin ağırlığı negatiftir
    return deger


print(sabit_genislik(0b11111011))     # -5
print(sabit_genislik(127 + 1))        # -128   (işaretli taşma)
print(sabit_genislik(-1))             # -1
print((255 + 1) & 0xFF)               # 0      (işaretsiz başa sarma)

print(sabit_genislik(0x41424344, 32)) # 1094861636
print(sabit_genislik(0x81424344, 32)) # -2126363836

sabit_genislik işlevinin gövdesi, bu dersin tanımının doğrudan çevirisidir: önce genişliğe sığmayan bitler atılır, sonra en soldaki bit için negatif ağırlık uygulanır.

Özet

  • Sabit genişlikli bir gösterimde işaret, ayrı bir alanda değil, örüntünün içinde kodlanır.
  • İkiye tümleyen gösterimde en soldaki bitin konum değeri negatiftir; nn bitin aralığı [2n1,2n11][-2^{n-1}, 2^{n-1}-1]’dir ve sıfırın tek gösterimi vardır.
  • Bir sayının negatifi, tüm bitler ters çevrilip bir eklenerek üretilir; en küçük değer bu işlemin istisnasıdır.
  • İşaretli toplama, işaretsiz toplamayla aynı devrede yapılır; ikiye tümleyenin tercih nedeni budur.
  • Aralık aşıldığında sonuç kaybolmaz, öbür uçtan geri döner: işaretsizde 255+1=0255 + 1 = 0, işaretlide 127+1=128127 + 1 = -128.
  • Genişletmede doldurma kuralı yoruma bağlıdır; işaretli değerlerde işaret biti kopyalanır.

Sonraki Adım

Tam sayılar, temsil edebildikleri aralık içinde kesindir: her değer ya vardır ya yoktur. Kesirli sayılarda durum başkadır — sonsuz sayıda gerçel değeri sonlu sayıda örüntüye sığdırmak gerekir. Sonraki ders, bunun nasıl yapıldığını ve 0,1+0,20{,}1 + 0{,}2 toplamının neden tam olarak 0,30{,}3 etmediğini 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