- Yalnızca 3 CPU komutu ile artık yılı belirleyen bir fonksiyon uygulanıyor
- Bu yöntem, geleneksel dallanma olmadan bit işlemleri ve çarpma kullanarak çalışıyor
- Bu yaklaşım 0~102499 yıl aralığında doğru sonuç veriyor
- Benchmark sonuçlarına göre mevcut yönteme kıyasla yaklaşık 3,8 kat daha hızlı performans sunuyor
Genel bakış ve problemin tanımı
- 0 ile 102499 arasındaki yıllar için, yalnızca 3 CPU komutu kullanarak artık yılı belirleyen bir fonksiyon
- Kullanılan gerçek fonksiyonun yapısı
((y * 1073750999) & 3221352463) <= 126976 şeklinde
- Bu bit-twiddling tekniğinin mantığı, çalışma biçimi ve pratik faydası açıklanıyor
Geleneksel artık yıl belirleme yöntemi
- Genelde artık yıl kontrolü bölme(modulo) ve koşullu dallanma ile uygulanır
Standart yaklaşımın optimizasyonu
(y % 100) kontrolü (y % 25) ile, (y % 400) kontrolü ise (y % 16) ile değiştirilebilir
- Bunun nedeni, daha önce zaten 4'e bölme kontrolünün yapılmış olması ve bunun 25 ile 16 çarpan ilişkisine dönüştürülebilmesi
(y % 25) işlemini bölme kullanmadan çarpma ve karşılaştırmaya dönüştüren sihirli bir sabit
- Örnek:
x * 3264175145 > 171798691 biçimine dönüştürülebilir
- Bir bit maskesi eklenerek
(y & 3) ya da (y & 15) ile 4 veya 16'ya bölünebilirlik kontrolü yapılabilir
- Derleyiciler bu dönüşümleri otomatikleştirebilir, ancak başka dillerde doğrudan da kullanılabilir
Dallanmasız(branchless) uygulama yöntemi
Sihirli sabitleri bulmak: bit-twiddling yaklaşımı
- Artık yıl denklemini daha da basitleştirmek için kombinatoryal arama ve SMT Solver olan Z3 kullanılıyor
- Biçim:
((y * f) & m) <= t
- Koşulları sağlayan f, m, t sabitleri Z3 ile aranıyor
- 0~102499 aralığında doğru sonuç verebilen değerler bulunuyor
- Nihai sonuç
(y * 1073750999) & 3221352463 <= 126976 oluyor
Fonksiyonun mantığı ve iç yapısının açıklaması
- Sabitler ikili düzeyde analiz edilerek üç ana bit bölgesine, A, B, C, ayrılıyor
- Her bölgedeki bit durumu, artık yıl belirlemenin 3 koşulunu kapsıyor
- Fonksiyonun mantıksal ayrıştırması:
- A bölgesi:
(y % 4) != 0 olup olmadığını da içerecek şekilde 4'ün katı olma koşulunu kontrol ediyor
- B bölgesi:
(y % 100) != 0 durumunu farklı desenlerle (ör. son iki hanesi 14, 57, 71 vb.) filtreliyor
- C bölgesi:
(y % 16) == 0, yani 16'nın katı olma durumunu kontrol ediyor
- Çarpmanın, aslında kalan hesabı yapmadan çeşitli koşulları birleştirmeyi nasıl başardığı açıklanıyor
- Sihirli sabitle çarpıldığında 100'ün katları gibi değerlerde ayırt edici bit desenleri oluşuyor
- Buna ek olarak, çarpma hatası ve çok basamaklı sayı desenlerinin ortaya çıktığı matematiksel iç yapı da inceleniyor
Ek aralıklar ve bit genişliğini artırma olasılığı
- 64 bit'e genişletildiğinde uygun sihirli sabit kombinasyonlarını arama yöntemi de sunuluyor
f, m, t değerleri değiştirilerek en geniş aralık bulunabilir
- StackExchange üzerinde de en iyi kombinasyonlar ve Z3 ile ispat örnekleri yer alıyor
Benchmark ve gerçek performans karşılaştırması
- Benchmark sonuçları:
- 2025 gibi öngörülebilir değerlerde 0.65~0.69ns ile neredeyse fark yok
- Rastgele girdilerde
is_leap_year_fast yaklaşık 3,8 kat daha hızlı performans gösteriyor
- Girdi desenine bağlı olarak dallanma(branching) yaklaşımı öngörülemez olduğunda ciddi avantaj sağlıyor
Sonuç ve pratikte uygulanabilirlik
- Gerçek uygulamalarda değerler öngörülebilirse kazanç sınırlı, ancak büyük miktarda rastgele veri durumunda çok yararlı
- Python veya C# gibi dillerde standart kütüphaneyi değiştirmek için gerçekçi bütün program benchmark'ı gerekli
- Fikir ve uygulama yöntemi başlı başına ilgi çekici ve bazı durumlarda performans açısından cazip bir çözüm
2 yorum
Fast inverse sqrt'ı hatırlatan bir yazı
Hacker News görüşleri
is_leap_year1gibi bir kodunis_leap_year2gibi otomatik optimize edilmesine şaşırdım; bu yüzden C kaynak kodu aşamasında elle optimizasyon yapmaya çok gerek olmadığı hissi var, ama diğer diller için hâlâ faydalı olabilir, özellikle decalprogramının güncel sürüm kaynak kodunda leap year kontrolünün çok basit ele alınması etkileyici((y * 1073750999) & 3221352463) <= 126976kodunun nasıl çalıştığına dair açıklamanın karmaşık olmasına hiç şaşırmadım, hatta bu gayet doğalCMP(X, Y)makrosu,signumfonksiyonu optimizasyon örnekleri, Motorola 68000 için assembly kodu örnekleri, OpenSolaris kökenli bit makroları derlemesi gibi farklı optimizasyon tekniklerine linkler verildi; Open Solaris blogunun artık olmamasına dair üzüntü de belirtildi, kod optimizasyonuna ilgi duyanlara tavsiye edildisupercompilationtekniğine bakma önerisi