Ders 07 / 21
Büyük Tam Sayılar
Güvenli tam sayı aralığının aşıldığı durumlar, keyfi büyüklükte tam sayı tipi, işleç davranışı, tip karıştırma yasağı ve dizileştirme sınırı.
İçindekiler
Önceki ders, sayı tipinin tamamının IEEE 754 çift duyarlıklı gösterim olduğunu ve bu gösterimin tam sayılar için değerinde bir sınır taşıdığını gösterdi. Sınırın üstünde iki farklı tam sayı aynı bit örüntüsüne yuvarlanır ve eşit çıkar.
Bu ders o sınırın gerçekten aşıldığı durumları ve dilin buna verdiği yanıtı ele alır: keyfi büyüklükte tam sayı taşıyan ayrı bir ilkel tip. Tipin kendisi kadar, sayı tipiyle arasına konan kesin sınır da önemlidir.
Sınır Nerede Aşılır
Güvenli aralık yaklaşık dokuz katrilyondur. Günlük hesaplarda uzak görünen bu değer, belirli veri türlerinde tek bir okumayla geçilir:
- Nanosaniye çözünürlüklü zaman damgaları. Bir başlangıç anından itibaren geçen nanosaniye sayısı, milisaniyeye göre bir milyon kat büyüktür ve aralığın dışına çıkar.
- Başka sistemlerden gelen 64 bitlik tam sayı kimlikleri. Kimlik üzerinde aritmetik yapılmasa bile, değeri kaybetmeden okuyup geri yazmak gerekir.
- Uzun süre biriken sayaçlar. Yüksek örnekleme hızlı bir ölçüm ağında toplam örnek sayısı bu aralığa ulaşabilir.
Üçünde de ortak nokta, hassasiyetin son basamağa kadar korunması gerektiğidir. Sayı tipiyle çalışıldığında kayıp sessizdir; hata verilmez, yalnızca yanlış değer taşınır.
Ayrı Bir İlkel Tip
Büyük tam sayı (BigInt), keyfi basamak sayısında tam sayı taşıyan ilkel tiptir. İki
biçimde yazılır: sayı yazımının sonuna n eklenerek veya bir dönüştürme çağrısıyla.
const a = 9007199254740993n; const b = BigInt("9007199254740993"); console.log(a === b); console.log(typeof a); console.log(a + 1n);
true bigint 9007199254740994n
Önceki derste bu değer sayı tipiyle temsil edilemiyordu; burada tam olarak korunuyor.
Çıktıdaki n soneki değerin parçası değildir, çalışma zamanının inceleme biçimidir.
Değer metne çevrildiğinde sonek görünmez:
console.log(String(10n)); console.log(10n.toString()); console.log(10n);
10 10 10n
İlk iki satır dilin metne çevirme kuralının sonucudur ve her ortamda aynıdır. Üçüncü satırdaki gösterim ortamın inceleme biçimidir. Kod Çalıştırma Yolları dersinde kurulan ayrım burada tekrar karşımıza çıkıyor.
İşleç Davranışı
Aritmetik işleçler tam sayı anlambilimiyle çalışır. En belirgin fark bölmededir:
console.log(7n / 2n); console.log(7n % 2n); console.log(2n ** 64n);
3n 1n 18446744073709551616n
Bölme kesir üretmez; sonuç sıfıra doğru kırpılır. Programlama Temelleri kursundaki Temel Veri Tipleri dersinde iki bölme işleminin ayrımı kurulmuştu — burada büyük tam sayı tipinde yalnızca tam bölme vardır. Kırpma yönü sıfıra doğrudur, aşağı doğru değil; negatif işlenenlerde bu ayrım sonuç değiştirir.
Üstel işlem, sayı tipinde temsil edilemeyecek büyüklükleri tam olarak verir. değeri yirmi basamaklıdır ve son basamağına kadar doğrudur.
Tipler Karıştırılamaz
İki sayı tipi aritmetik işleçlerde bir araya gelemez:
try { console.log(1n + 1); } catch (hata) { console.log(hata.name + ": " + hata.message); }
TypeError: Cannot mix BigInt and other types, use explicit conversions
Bu yasak bir eksiklik değil, bilinçli bir tasarım kararıdır. İki tipin anlambilimi uyuşmaz: sayı tipinde bölme kesir üretir, büyük tam sayıda üretmez; sayı tipinde büyük değerler yuvarlanır, büyük tam sayıda yuvarlanmaz. Karışık bir ifadenin hangi kuralla değerlendirileceği tek biçimde seçilemez. Dil, seçimi program yazarına bırakır ve açık dönüşüm ister.
Karşılaştırma işleçleri farklı davranır. Değer karşılaştırması yapan işleçler iki tipi birlikte ele alabilir; tip de karşılaştıran işleç ayırır:
console.log(1n == 1); console.log(1n === 1); console.log(2n > 1);
true false true
İlk ve üçüncü satırlar matematiksel değeri karşılaştırır. İkinci satır ise tipleri de karşılaştırdığı için yanlış verir. Bu üç işlecin kuralları Eşitlik Karşılaştırmaları dersinde adım adım tanımlanacak.
Dönüşümün Bedeli
İki tip arasında dönüşüm açıkça yazılabilir, ama her yön güvenli değildir.
Büyük tam sayıdan sayıya dönüşüm, aralık dışındaki değerlerde duyarlık kaybeder:
const zamanNs = 1700000000123456789n; console.log(Number(zamanNs)); console.log(BigInt(Number(zamanNs)));
1700000000123456800 1700000000123456768n
İki satır birlikte okunmalıdır. Birinci satır, dönüşümden çıkan sayının metne çevrilmiş
halidir; metne çevirme, aynı bit örüntüsüne geri dönen en kısa onluk gösterimi seçer, bu
yüzden yuvarlak görünür. İkinci satır aynı değeri kayıpsız bir tiple yazar ve gerçek
değeri gösterir: ...768. Yani hem özgün değer kaybolmuştur hem de kaybın miktarı ilk
bakışta göründüğünden farklıdır.
Sayıdan büyük tam sayıya dönüşüm ise kesirli değerleri reddeder:
try { console.log(BigInt(1.5)); } catch (hata) { console.log(hata.name + ": " + hata.message); }
RangeError: The number 1.5 cannot be converted to a BigInt because it is not an integer
Sayı tipiyle çalışan yerleşik yöntemler de büyük tam sayı kabul etmez:
try { console.log(Math.max(1n, 2n)); } catch (hata) { console.log(hata.name + ": " + hata.message); }
TypeError: Cannot convert a BigInt value to a number
Math nesnesinin tamamı kayan noktalı sayılar için tanımlıdır. Büyük tam sayılarla
karşılaştırma yapmak gerekiyorsa karşılaştırma işleçleri kullanılır.
Ölçüm Betiğine Uygulama
Ölçüm kayıtlarına nanosaniye çözünürlüklü zaman damgası eklendiğinde, iki tip aynı kayıtta yan yana bulunur:
const okumalar = [ { istasyon: "A1", zamanNs: 1700000000123456789n, sicaklik: 21.5 }, { istasyon: "A1", zamanNs: 1700000000923456789n, sicaklik: 21.7 }, ]; const fark = okumalar[1].zamanNs - okumalar[0].zamanNs; console.log("fark (ns):", fark.toString()); console.log("fark (ms):", (fark / 1000000n).toString());
fark (ns): 800000000 fark (ms): 800
Zaman farkı nanosaniye duyarlığında hesaplandı, sonra milisaniyeye çevrildi. Çevrimde kesir atıldı — tam bölme kırpma yapar. Kesirli bir sonuç gerekiyorsa, bölme sayı tipine geçilerek yapılır ve bu noktada duyarlık kaybı bilinçli olarak kabul edilir.
Sıcaklık alanı sayı tipinde kaldı; kayan noktalı bir büyüklük için doğru seçim odur. İki tipin aynı kayıtta bulunması sorun değildir — sorun, ikisini aynı ifadede karıştırmaktır.
Dizileştirme Sınırı
Büyük tam sayılar, verinin JSON biçiminde yazılmasını engeller:
try { console.log(JSON.stringify({ sayac: 10n })); } catch (hata) { console.log(hata.name + ": " + hata.message); } console.log(JSON.stringify({ sayac: String(10n) }));
TypeError: Do not know how to serialize a BigInt
{"sayac":"10"}
Neden bir eksiklik değil, biçimin tanımıdır: JSON’un sayı gösteriminin duyarlık garantisi yoktur ve okuyan taraf değeri sayı tipine çevirebilir. Değeri kayıpsız aktarmak için metin olarak yazmak, biçimin sınırını kabul eden çözümdür. JSON’un sınırları ayrı bir dersin konusudur.
Özet
- Güvenli tam sayı aralığı nanosaniye zaman damgaları, 64 bitlik dış kimlikler ve uzun süre biriken sayaçlarda aşılır; kayıp sessizdir.
- Büyük tam sayı ayrı bir ilkel tiptir;
nsonekiyle veya açık dönüşümle yazılır ve keyfi basamak sayısı taşır. - Bölme kesir üretmez, sıfıra doğru kırpar;
Mathyöntemleri bu tiple çalışmaz. - Aritmetik işleçlerde iki sayı tipi karıştırılamaz; karşılaştırma işleçleri değer karşılaştırmasında birlikte çalışır, tip karşılaştıran işleç ayırır.
- Büyük tam sayıdan sayıya dönüşüm aralık dışında duyarlık kaybettirir; JSON’a doğrudan yazılamaz, metin olarak aktarılır.
Sonraki Adım
Bu ders, iki tip arasındaki dönüşümün açıkça yazılmasını gerektiren tek durumu gösterdi.
Dilin geri kalanında durum tersidir: tipler çoğu işleçte kendiliğinden dönüştürülür ve
sonuç, dönüşümün hangi sırayla yapıldığına bağlıdır. Sonraki ders bu örtük zorlamanın
adımlarını tanımlayacak; [] + {} gibi ifadelerin sonucu ezber değil, izlenebilir bir
yordamın çıktısı olarak okunacak.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.