Forum: Ders Arası RSS
Çift yollu otoban! (.sizeof, size_t, vs.)
64 bit derleme...
Sayfa:  1  2  sonraki 
Avatar
Salih Dinçer #1
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Konu adı: Çift yollu otoban!
Merhaba,

Bugün ilk defa size_t'yi denedim ve 64 bit sistemde bir fark meydana gelir mi diye merak ettim. Bir sorunla karşılaştım ama bunun size_t ile de alakası olmayabilir. Hala öğrenecek ve deneyecek çok şey var...:)

Denediğim ise aşağıdaki kodu 64 bit sistemde derlediğimde 15 değerini almam gerekirken kuramsal açıdan iki katı olan 31 değerini alıyorum. Sonra -m32 ile derlediğimde bu sorun kalmıyor. Demek ki işin sırrı olinde, iki kere rafine... :nuts:

Özele; şaka bir yana bunun anlamı ne?
Salih Dinçer:
import core.stdc.stdio: printf;
 
int bitBul(size_t arananBitler, ref ubyte[] veri) {
    int uzunluk = cast(int)arananBitler;
    size_t kafa, maske = 1;
 
    for(int i = 1; i <= 64; i++) {
        maske |= maske << 1;
        uzunluk >>= 1;
        if(uzunluk == 0) {
            maske >>= 1;
            uzunluk = i;
            break;
        } // MSB bitleri 0 olana kadar devam et, önceki duruma dön ve çık
    } // maske'yi doldur ve uzunluk'tan bir bit çıkar
 
    for(ubyte b = 0; b < (veri.length * veri.sizeof); b++) {
        kafa <<= 1;
        if((veri[b / veri.sizeof] & (128 >> b % veri.sizeof))!=0) kafa |= 1;
        kafa &= maske;
        if (kafa == arananBitler) return b - uzunluk;
    }
    return -1;
}
 
int main() {
    // bit >>           8  16  24   32   40   48   56   64 <--ulong    
    ubyte[] veriler = [ 1, 1, 137, 137, 137, 137, 137, 137, 9, 1 ];
    size_t xKelime = 0b1000_1001; // decimal 137
    int xKonum = bitBul(xKelime, veriler);
 
    printf("%lu verisi arandı ", xKelime);
 
    if(xKonum == -1) {
        printf("ama bulunamadı!");
    } else {
        printf("ve %d numaralı bitden sonra başladığı tespit edildi...:)", xKonum);
    }
    printf("\n\nHoşça kalın...\n");
 
    return 1;
}
Teşekkürler...
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
Avatar
Salih Dinçer #2
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Herhalde 64 bit'de değişkenler tıpkı UTF8'de olduğu gibi iki kat olarak ifade edildiği için böyle diyeceğim ama emin olamıyorum. Bu arada aşağıdaki gibi de denedim; ne size_t ile ne de printf kullanmamla alakası var...
    import std.stdio;
 
    int main() {
        // bit >>           8  16  24   32   40   48   56   64 <--ulong    
        ubyte[] veriler = [ 1, 1, 137, 137, 137, 137, 137, 137, 9, 1 ];
        ulong xKelime = 0b1000_1001; // decimal 137
        int xKonum = bitBul(xKelime, veriler);
     
        writef("%d verisi arandı ", xKelime);
     
        if(xKonum == -1) {
            write("ama bulunamadı!");
        } else {
            writefln("ve %d numaralı bitden sonra başladığı tespit edildi...:)", xKonum);
        }
        writeln("\nHoşça kalın...");
     
        return 1;
    }
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
acehreli (Moderatör) #3
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj #1
Salih Dinçer:
    int uzunluk = cast(int)arananBitler;

Aranan bitlerle uzunluğun ilgisi var mı? 0b1000_1001 aranırken uzunluk 8 olmamalı mı?

Ali
acehreli (Moderatör) #4
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj #1
uzunluk konusunda yanılmışım. Uzunluk anlamında kullanılmıyormuş. ;) (İsimler çok önemlidir.)

Salih Dinçer:
        if((veri[b / veri.sizeof] & (128 >> b % veri.sizeof))!=0) kafa |= 1;

Sanırım .sizeof değil de .length olacak.

Ali
Avatar
Salih Dinçer #5
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Aslında bu kodda uzunluk, keywordLength demek. Sizeof'u kullanma sebebim ise veri türünün daha büyük değişkenlerde olması durumunda 8 değil de 16, 32, 64 gibi devingen (dynamic) değişkenleri göndermesi. Aslında oraya 128 sabitinde yaptığım gibi durağan (static) bir şekilde 8 koyabilirdik.

Artistik olsun işte...:)
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
acehreli (Moderatör) #6
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Salih Dinçer:
Sizeof'u kullanma sebebim ise veri türünün daha büyük değişkenlerde olması durumunda

Dilimin eleman türünden bahsediyorsun o zaman. Ama veri.sizeof dediğin zaman dilim denen referans nesnesinin büyüklüğünü alıyorsun. O her zaman için bir gösterge ve bir uzunluk üyesinden oluşur. Yani her dilim 32 bitlik sistemlerde 8 bayt, 64 bitlik sistemlerde de 16 bayt olur.

Ali
Avatar
Salih Dinçer #7
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
O zaman sorunun cevabını bulduk, teşekkürler...:)
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
Avatar
Salih Dinçer #8
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Sanırım, immutable ve foreach() ile daha iyi oldu! Hiç bir sihirli sayı yok ama büyü devam ediyor...:)
import std.c.stdio: printf;/*
import std.stdio;//*/
 
    // bit >>           8  16  24   32   40   48   56   64 <--ulong    
    uint[] veriler = [ 1, 1, 137, 137, 137, 137, 137, 137, 3, 128 ];
                                                  //   _0011 1000_
    immutable sf = veriler[0].sizeof * 8;   // size of
    immutable sm = 2^^(sf - 1);             // sub mask
    immutable mx = ulong.sizeof * 8;        // data max
 
    int bitBul(size_t arananBitler, ref size_t[] veri) {
        int uzunluk = cast(int)arananBitler;
        size_t kafa, maske = 1;
 
        for(int i = 1; i <= mx; i++) {
            maske |= maske << 1;
            uzunluk >>= 1;
            if(uzunluk == 0) {
                maske >>= 1;
                uzunluk = i;
                break;
            } // MSB bitleri 0 olana kadar devam et, önceki duruma dön ve çık
        } // maske'yi doldur ve uzunluk'tan bir bit çıkar
 
        foreach(bs; 0 .. (veri.length * sf)) {
            kafa <<= 1;
            if((veri[bs / sf] & (sm >> bs % sf)) != 0) kafa |= 1;
            kafa &= maske;
            if (kafa == arananBitler) return bs - uzunluk;
        }
        return -1;
}
 
int main() {
    //size_t xKelime = 0b1001_0000; // decimal 144
    size_t xKelime = 0b0111; // decimal 7
    int xKonum = bitBul(xKelime, veriler);
 
    printf("%lu verisi arandı ", xKelime);
    if (xKonum == -1) {
        printf("ama bulunamadı!");
    } else {
        printf("ve %d numaralı bitden sonra başladığı tespit edildi.", xKonum);
    }
    printf("\n\tVeri türü: %lu bits", sf);
    printf("\n\tVeri genişliği: %lu", sm * 2 - 1);
    printf("\n\tToplam taranan: %lu bits\n", veriler.length * sf);
    printf("\nHoşça kalın...\n");
 
    return 1;
}
Çıktısı:
salih@DB-N150-N210-N220:~/d.ders$ ./bitDerle
7 verisi arandı ama bulunamadı!
    Veri türü: 32 bits
    Veri genişliği: 4294967295
    Toplama taranan: 320 bits

Hoşça kalın...


Deneme imkanınız varsa, bulup bulmadığını görmek için veriler'i, ubyte'a çevirmeniz yeterlidir...
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
Bu mesaj Salih Dinçer tarafından değiştirildi; zaman: 2012-03-16, 04:01.
acehreli (Moderatör) #9
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Notlar:

1) Değişken isimleri sf gibi kısa seçilip açıklama satırıyla açıklanmak yerine, baştan açık olarak seçilebilir.

2) .sizeof'un zaten "bayt adedi" gibi bir anlamı var. Bit adedi için de size of demek yanıltıcı olur.

3) size_t adet gibi, indeks gibi, vs. sayılabilen kavramlara uygundur. Oysa arananBitler ne adet gibi ne de indeks gibi bir kavram. Bence arananBitler için işaretsiz bir tür seçilebilr. Herhalde en uzun olsun diye ulong diyebiliriz.

Veya istersen uint de olur. Buna işlevin karar vermesi gerek. Aslında en iyisi işlevi şablon yapmak ve bu seçimi kullanıcıya bırakmaktır.

Altını çizmek istiyorum: size_t'nin belirli bir ortamda perde arkasında ulong'un takma ismi olması ulong yerine size_t yazma anlamına gelmemeli. Kural şöyle olsun: eğer adet veya indeks gibi bir kavram ise size_t kullanalım.

Buna göre, bitBul'un aslında size_t döndürmesi gerekir. Yoksa şu satırda derleme hatası alıyorum (32 bitlik ortamlarda derleniyordur):

            if (kafa == arananBitler) return bs - uzunluk;

Çünkü ne anlama geldiğini tahmin edemediğim bs size_t türündedir. size_t benim ortamımda ulong'un eşdeğeri olduğundan int'e otomatik olarak dönüşemiyor.

4) Aynı biçimde veri parametresi de size_t dilimi olmamalı. (Bu konuda da derleme hatası alıyorum.)

5) Bir önceki değişikliği yaptığımızı kabul ederek, parametreyi 'ref ulong[]' olarak işaretliyorsun. Daha önce söylediğimi tekrarlayacağım: bitBul() gibi bir işlev, aldığı dilimde değişiklik yapmamalıdır çünkü tek amacı bulmaktır. Ayrıca immutable dilimlerle de çağrılabilmelidir. O yüzden parametrenin 'const ulong[]' olması uygundur.

Dilimleri 'ref' olarak işaretlemek ancak asıl dilimde yapısal değişiklikler gerektiği zaman uygundur: eleman eklemek, çıkartmak, vs. Bit bulan bir işlev zaten böyle değişiklikler yapmamalıdır. bulDeğiştir() diye bir işlev olsa tamam.

Ali
Avatar
Salih Dinçer #10
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Teşekkürler Ali Hocam,

Yazdıklarını bir tek şey dışında anlamadım; o da size_t ile ilgili olanlar. Öncelikle kısaca bu veri türünden ne anladığımı yazmalıyım...

size_t: "Derleyicinin, sistem kaynaklarına ve kodun işleyişine göre karar verdiği (tanımladığı) bir veri türüdür."

Kullanma sebebim ise; aranan veri ile verinin kendisinin değişebilirliliği. Yani veriler[] dizi en küçük ubyte olabilir ama dilediğimizde sınıf veya işlevde değişikliğe gitmeden diğer veri türleri de kullanılmalıdır. İşte bu yüzden yan anlam olarak da şunu zannediyorum:

"...işlevde kullanılırken bağlandığı veri türü ubyte ise temsil eden size_t de ubyte olur" mu?

Ayrıca aranılan veri türü üç bit de olabileceği gibi 64 bit de olabilir. O yüzden size_t kullanmıştım. Yine yukarıdaki gibi aynı mantıkla, xKelime değişkenini ulong olarak tanımlarsam derleyici de size_t'li işlevleri de ulong yapıyor olabilir mi?

Eğer yukarıda şüphelendiğim gibi yanılgı içindeysem size_t'leri tam anlamıyla öğrenene kadar kullanmamalıyım...:)

Sevgiler, saygılar...
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
zafer #11
Üye Tem 2009 tarihinden beri · 700 mesaj · Konum: Ankara
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Sanırım projeye bu konu altından devam ediyorsunuz. Bu konularda çok acemi olduğumu belirtmiştim ama Salih'in yazdıklarını okuduktan sonra dayanamadım ve elimden geldiğince katkı sağlamaya karar verdim. Neticede amaç öğrenmek :)

Bende Ali'nin önceki mesajlarında maskeleme hakkında yaptığı tesbite katılıyorum ve MaskeYap() veya MaskeHazirla() isimli bir metoda ihtiyaç olduğunu düşünüyorum. Böylece bitBul() metodu hem daha sade hale gelecek hemde direk görevine odaklanacaktır. Ayrıca bunun ileride yazılacak unittest bloklarını hazırlarkende daha uygun olacağını düşünüyorum.

Ben bir şeyler yapmaya çalıştım ama tam olarak anlayamadığım için bir neticeye ulaşamadım.

...
immutable mx = ulong.sizeof * 8;        // data max
...
int uzunluk = cast(int)arananBitler;
size_t kafa, maske = 1;
 
for(int i = 1; i <= mx; i++)
    {
        maske |= maske << 1;
        uzunluk >>= 1;
        if(uzunluk == 0)
        {
            writefln("uzunluk  : %s", uzunluk);
            writefln("i  : %s", i);
 
            maske >>= 1;
            uzunluk = i;
            break;
        } // MSB bitleri 0 olana kadar devam et, önceki duruma dön ve çık
    } // maske'yi doldur ve uzunluk'tan bir bit çıkar
 
...

Bu kod yani for döngüsünü içini kastediyorum, tam olarak ne iş yapıyor. Satır satir anlatabilir misiniz?
https://github.com/zafer06 - depo
acehreli (Moderatör) #12
Kullanıcı başlığı: Ali Çehreli
Üye Haz 2009 tarihinden beri · 4527 mesaj
Grup üyelikleri: Genel Moderatörler, Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj #10
Evet, size_t'de bir yanlış anlama var.

Salih Dinçer:
size_t: "Derleyicinin, sistem kaynaklarına ve kodun işleyişine göre karar verdiği (tanımladığı) bir veri türüdür."

Sistem kaynakları deyince bellek miktarı gibi bir kavram anlaşılabiliyor. size_t'nin sistemle öyle bir ilgisi yoktur.

Kodun işleyişi derken de çalışma zamanı ile ilgili bir kavramdan bahsediyorsan o da olamaz. Hatırlarsak, D derlemeli bir dil olduğundan bütün türler derleme sonunda bellidir. (Aslında kod işlemeye başladığında tür diye bir kavram kalmamıştır; ama konuyu dağıtıyorum.)

size_t'nin ne olduğunu sana bir soru sorarak anlatayım. Dizi gibi işleyen bir yapı tasarlıyorsun:

struct Dizi
{
    /* ... */
 
    BuTürNedir uzunluk()
    {
        /* ... */
    }
}

uzunluk() işlevinin dönüş türü nedir? Nasıl karar verirsin? Öyle bir tür olmalı ki bu sistemdeki bütün adet kavramlarını temsil edebilmeli.

Veya derleyici tarafından yanıtlayalım: Derleyici şu döngüde i'nin türünü ne seçmelidir?

    foreach (i; 0 .. 10) {
        /* ... */
    }

10 yerine int.max yazsam? uint.max yazsam? Bunlara göre farklı tür mü seçmelidir? Ama öyle yapsa döngü içinde benim kodlarım farklı işleyebilir. Programcı olarak orada bir garanti beklerim.

Sonuçta şöyle karar verilmiş: programın derlendiği sisteme uygun bir tür seçelim ve onun adına size_t diyelim. Program adet ve indeks gibi kavramları temsil ederken hep size_t yazarsa hiçbir yerde sorun kalmaz.

Ayrıca bu türün işaretsiz bir tür olduğunu da garantileyelim. Yoksa programcı örneğin 64 bitlik bir sistemde belleğin uzunluğunu bile söyleyemez. 64 bitlik sistemde 2 üzeri 64 adet adres bulunabildiğine göre size_t'yi long seçsek yalnızca yarısını söyleyebiliriz.

size_t, programın derlendiği anda belirlidir ve uygun bir işaretsiz bir türdür. Her ne kadar "uygun bir türdür" diye fazla serbest konuşuyorsam da 32 bitlik sistemlerde uint'in, 64 bitlik sistemlerde de ulong'un eşdeğeri olduğu neredeyse kesindir.

Neyin takma ismi olduğunu /usr/include/d/dmd/druntime/import/object.di dosyasında görüyorum:

alias typeof(int.sizeof)                    size_t;

Demek ki aslında karar daha derinlerden geliyor: derleyici o sistemde .sizeof'un türü olarak neyi seçmiş ise ona size_t diyoruz.

Programcının yapması gereken son derece basit: size_t, adet veya indeks gibi kavramların türüdür. .length, .sizeof, öğrenciAdedi(), çekirdekAdedi(), vs. hep size_t türünde seçilmelidir. O tarafı bu kadar basit.

Öte yandan size_t, bu programdaki veri için hiç uygun değildir. Çünkü verimiz adet değil, indeks değil. Bitleri ile ilgilendiğimiz değişkenlerle ilgileniyoruz.

Yan not: size_t'nin işaretsiz bir tür olmasının getirdiği bir sakınca vardır. Eksi değer taşıyamadığından çıkarma işleminde kullanıldığında yanlış sonuç verebilir: i-j dendiğinde j daha büyük değer ise i ile j arasındaki uzaklığı elde etmemiş oluruz. Çıkarma işleminde kullanmaya uygun tür sizediff_t'dir çünkü o işaretli bir türdür.


Kullanma sebebim ise; aranan veri ile verinin kendisinin değişebilirliliği. Yani veriler[] dizi en küçük ubyte olabilir ama dilediğimizde sınıf veya işlevde değişikliğe gitmeden diğer veri türleri de kullanılmalıdır.

"İşlevde değişikliğe gitmeden" derken derleyicinin değişiklik yapmamasından bahsediyorsan bu olanaksızdır. Sonuçta işleyen makine kodu tam da o türe uygun yazmaçlarla vs. derlenmiştir. Türe karar verilmiştir.

Eğer programcının değişiklik yapmamasından bahsediyorsan o zaman ya işlev yükleme (overloading) olanağından yararlanarak her tür için farklı işlev yazmak zorundasın, ya da bunun güçlüğünü farkettiğinde şablon yazmalısın.

Başka bir seçeneğin de verinin türünü örneğin ulong seçmek ve olayı bitirmektir. D'nin tamsayı türlerinin bit sayılarının belirli olması yararlı. ulong'un her zaman 64 bit olduğunu biliyoruz. Ek olarak şunlar da var:

  http://dlang.org/phobos/std_stdint.html

O türler sanıyorum C'ye sonradan eklenen tür isimlerinin aynıları.

İşte bu yüzden yan anlam olarak da şunu zannediyorum:

"...işlevde kullanılırken bağlandığı veri türü ubyte ise temsil eden size_t de ubyte olur" mu?

Bu noktaya kadar anlaşılmıştır ama, hayır ubyte olmaz. Kullanılırken bağlandığı tür istiyorsan şablon yazman gerek. D şablon kolaylığı konusunda inanılmayacak kadar kolay.

Ayrıca aranılan veri türü üç bit de olabileceği gibi 64 bit de olabilir. O yüzden size_t kullanmıştım.

İşte o zaman ya ulong kullanmalısın veya yukarıdaki sayfadaki ismi daha açık olan uint64_t'yi. Belki de en büyük tamsayı türü anlamına gelen uintmax_t'yi. Onun tanımı da şurada:

  /usr/include/d/dmd/druntime/import/core/stdc/stdint.di

Görüldüğü gibi o da zaten ulong:

    alias ulong uintmax_t;

Eğer ucent sonunda gerçekleştirilirse belki de ucent olur. (?)

Yine yukarıdaki gibi aynı mantıkla, xKelime değişkenini ulong olarak tanımlarsam derleyici de size_t'li işlevleri de ulong yapıyor olabilir mi?

Senin ilacın şablon! ;)

Eğer yukarıda şüphelendiğim gibi yanılgı içindeysem size_t'leri tam anlamıyla öğrenene kadar kullanmamalıyım...:)

Bence adet ve indeks kavramları için size_t kullan. Çıkarma işleminde sonucun çok büyük çıkabileceğini de aklında tut.

Şimdi sana bit işlemleri ile ilgilenen küçük bir şablon yazayım. İşine yarayıp yaramayacağına veya zor olup olmadığına sen karar ver:

import std.stdio;
 
/**
 * Verinin en üst ve en alt dört biti dışındaki bitlerinin
 * sıfırlanmışını döndürür.
 */
T ortasıSıfırlı(T)(T veri)
{
    /* Not: Aşağıdaki üç değişkenin başına enum yazmak daha
     * uygun olur. Örneği bulandırmamak için öyle yazmadım. */
    size_t toplamBit = veri.sizeof * 8;
    T altBitlerMaskesi = 0b1111;
    T üstBitlerMaskesi = cast(T)(altBitlerMaskesi << (toplamBit - 4));
    /* Yukarıdaki cast'e neden gerek olduğunu yazı içinde
     * anlatıyorum. */
 
    return veri & (altBitlerMaskesi | üstBitlerMaskesi);
}
 
/*
 * 101010... deseninde belirtilen türde değer döndürür.
 */
T birSıfır(T)()
{
    return cast(T)(0xaaaa_aaaa_aaaa_aaaa);
}
 
void main()
{
    ubyte  b = birSıfır!ubyte();
    ushort s = birSıfır!ushort();
    uint   i = birSıfır!uint();
    ulong  l = birSıfır!ulong();
 
    writefln("%b => %b", b, ortasıSıfırlı(b));
    writefln("%b => %b", s, ortasıSıfırlı(s));
    writefln("%b => %b", i, ortasıSıfırlı(i));
    writefln("%b => %b", l, ortasıSıfırlı(l));
}

Çıktısı:

10101010 => 10101010
1010101010101010 => 1010000000001010
10101010101010101010101010101010 => 10100000000000000000000000001010
1010101010101010101010101010101010101010101010101010101010101010 => 1010000000000000000000000000000000000000000000000000000000001010


Şablonun karışıklıkları şunlar:

  • İşlev şablonunun iki parantezi oluyor. Birinci parantez, T'nin bir tür olduğunu ve programdaki kullanıma göre derleyici tarafından seçileceğini bildiriyor. (Çalışma zamanından çok önce.)

  • İşlevin geri kalanında o tür ne ise onun yerine T yazıyoruz.

ortasıSıfırlı() işlevinde cast kullanmak zorunda kaldım. Bu, "integer promotions" (bazen "integral promotions" da diyorlar) yüzündendi. Şurada "Integer promotions" başlığında:

  http://dlang.org/type.html

C'ye dayanan kurallara göre << gibi işlemler ya int ya da uint türü ile yapılırlar. Yani T ubyte bile olsa << işleminin kendi türü int oluyor. int'i de üstBitlerMaskesi değişkenine cast'siz atayamıyoruz.

Çok önemli bir hatırlatma daha: şablonların sihiri de derleme zamanındadır. Derleyici, programda kullandık diye tam dört tane ortasıSıfırlı() işlevi oluşturur. Bunların makine kodları kullandığımız dört türe göredir.

Ali
Avatar
Salih Dinçer #13
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Hocam, yazdıklarını az önce okudum; asıl cevabımı vermeden önce ve yeni yanlış anlamalara dallanmadan evvel, oku_ve_Anla() işlevini bir döngü içinde (sayısı belirsiz, size_t diyelim!) bir kaç defa işletmeliyim...:)

Ancak çok çok yararlı olduğunu da belirtmeliyim, teşekkürler...

Zafer Çelenk:
...
0.    immutable mx = ulong.sizeof * 8;        // data max
...
1.    int uzunluk = cast(int)arananBitler;
2.    size_t kafa, maske = 1;
 
3.    for(int i = 1; i <= mx; i++) {
4.            maske |= maske << 1;
5.            uzunluk >>= 1;
6.            if(uzunluk == 0) {
7.                maske >>= 1;
8.                uzunluk = i;
9.                break;
        } // MSB bitleri 0 olana kadar devam et, önceki duruma dön ve çık
    } // maske'yi doldur ve uzunluk'tan bir bit çıkar
...
Bu kod yani for döngüsünü içini kastediyorum, tam olarak ne iş yapıyor. Satır satir anlatabilir misiniz?
Zafer'in sorduğu koda gelince; yanlarına satır numaraları verdim ve elimden geldiğince ifade etmeye çalışacağım inşaallah:

0. satır: Aslında bir yanlış anlamalar zincirinin bir ürünü. Ancak sabit (const) değişmeyen bir sayı ürettiğini ve bunun değerinin 64 olduğunu belirtmeliyim. Özetle ulong kaç bytlık bir sayı olduğunu soruyoruz ve 8 ile çarparak içine alabileceği (maskeleme yapabileceğimiz) en fazla değeri öğreniyoruz.

1. satır:İşlevin dönüş değer int olduğu için bu türe yerleştiriyoruz. Belki işaretli bir değer olduğu için yanlış yapıyor olabilirim. Ancak ihtiyacım olan bir kopyasını almaktı çünkü onu ilerleyen satılarda değiştirip (her seferinde ikiye bölüp) etkin bir şekilde kullanacağız.

2. satır:İse bizim diğer çok çok etkin değişkenlerimiz. Özellike maske'yi 1'e eşitledim ki her defasında sola kaydırdığımızda maskenin sınırı belli olsun. Yoksa bu değişkene 0 olsaydı 4. satırdaki işlemde maskemiz her seferinde 0 olmaya mahkum olacaktı.

3. satır:Bizim bir taşla (döngüyle) iki kuş vurduğumuz bir bölümün başlangıcı. Yaptığı ise 1'den 64'e kadar saymak.

4. satır:Aslında iki satır ve benim her şeyi sıkıştırma alışkanlığımın bir ürünü. Yani derleyici imkan verdiği ölçüde ben bunu hep yapıyorum, n'apayım can çıkarmış huy çıkmazmış...:)

Açılımı ise şu:
maske = maske << 1; //Tüm bitleri sola kaydır, ilk durumda: 1 [0001] idi, 2 [0010] oldu...
maske = maske | 1; //Başına bir ekle, ilk durumda: 1 [0001] idi, 3 [0011] oldu... 
Gerçi tam karşılığı sayılmaz çünkü yukarıda iki adet 1 değeri var. Ancak şöyle de izah edilebilir, kendisinin bir kopyasını sola kaydır ve sonra kendisiyle OR'la. Bu ROT (rotate) komutunun bir benzeri ama CF (carry flag) değili (invert). Yani CPU'da bu tür işlemler yapılırken 8 bit dışında bazı bitler (register'lar) vardır. Bunlardan biri STATUS ise (aslında o da bir değişken) içinde bir bayrağın ismi CF. O halde bu kaydırma işlemi yapılırken dışarıdan 1 değerini adeta açığa çıkarıyoruz.

Görsel olarak ise şöyle:

[.... 0001]1 <-dışarıdaki CF bayrağı gibi düşünülebilir...
[...0 0011]1 <-dışarıdaki içeriye girdi ama hala CF bayrağı değişmedi...


-devam edecek-
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
Avatar
Salih Dinçer #14
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
5. satır:Tam olarak ikiye bölmekte ve yine artizlik olsun diye :) kaydırma işlemini uyguladık. Yani ikiye de bölebilirdik çünkü değişken float veya double olmadığı için bize tam sayı verecektir. Madem bit üzerinde işlemler yapıyoruz, yakıştığı da bir gerçek! Zaten alt satırda sorguladığımız amaç ile doğru orantılı...

6. satır:İse en basit manasında 0 olup olmadığı kontrol ediyoruz. Ama gerçekte sağa kaydırma işlemi sırasında değişkende artık 1 kalıp kalmadığını sorguluyoruz. Böylece kaç adetlik maske yapmam gerektiğini, işleve ayrı bir parametre göndermeden tespit ediyoruz.

7. satır:Aslında bu satıra da gerek yok hani. Yani sorguyu yukarı alıp maske üzerinde yaptığımız işlemi de aşağıya alırsa alın size bir satır (belki de 2 satır) daha kazanmış olduk. Küme bitim parantezinin yanındaki açıklamada belirttiğim gibi, önceki duruma dönüyoruz, yani fazladan kaydırdığımızı geri alıyoruz.

8. satır:Hatırlarsan bir taşla iki kuş vurduğumuzdan bahsetmiştik. Maskeyi oluştururken uzunluk değerini de elde ettiğimiz için döngü adeti bize işlem yapılacak verinin uzunluğunu veriyor. İşte bu satırda artık önemi kalmamış (0 olmuş) değişkeni ileride kullanmak için atama yapıyoruz. Belki daha akıllı bir kodlama ile bu satırı bile kaldırabiliriz...:)

9. satır:Belki bu satırı açıklamaya gerek yok ama burada belirtmek uygun olacak. Döngü en fazla 64 defa devam edebilir. Aslında şimdi aklıma geldi, biz buraya sonsuz döngü koyabiliriz de! Çünkü farz edelim ilerde 128 bitlik işlemciler çıktı ve bit işleme değeri arttı. Zaten gelen verinin uzunluğuna göre bir sınırlama (sorgula ve çık) yaptığımıza göre 64 bit değerini immutable yapıp oraya aktarmak son derece gereksizmiş...

Özetle, yine Zafer sayesinde bir gerçeğin daha farkına vardım. Tabi Ali hocamın bahsettikleri ile kod daha kararlı olacağına eminim. Belki biz Türkler'in yaptığı ve tüm dünyada kullanılabilecek bit işleme sınıfının temellerini atıyoruz. Tabi şu ana kadar yaptıklarımız sanki beyin fırtınası gibi. Sanırm birlikte daha çok kod yazıp daha iyi bir düzene otursak farklı dillere de çevirip hoş bir ürün ortaya çıkarabiliriz. Özellikle söylüyorum altında bir Türk imzası olması önemli. Çünkü çevremiz hep bütün dünyadan karıncaların (karınca gibi çalışan yabancıların) yaptığı ürünler ile dolu; çok çalışkan olmalıyız!

Dip Not: Bu vesile ile araya bir görüşümü sıkıştırmak istiyorum. Gelecekte Türkiye, dünyanın yazılım sektörünün kalbi haline gelebilir. Tamam, Hindistan'da ben doğmadan evvel başlayan ve şu an doruk noktasında olan bir sektör var ama peki ya kalite? İnanıyorum ki Türkiye'de daha kaliteli kodlar üretecek bir nesil yetişiyor. Bence bizim hızlı çalışan kodlara ihtiyacımız var, süper hızlı bilgisayarlara değil!

Başarılar...
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
Avatar
Salih Dinçer #15
Üye Ock 2012 tarihinden beri · 1912 mesaj · Konum: İstanbul
Grup üyelikleri: Üyeler
Profili göster · Bu konuya bağlantı
Yanıtlanan mesaj #12
Artık size_t'yi tıpkı sizeof'u anladığım gibi daha iyi anlamaya başladım; Ali hocam sayesinde...

Ancak henüz esnek bir yapı için çözüm bulmuş değilim...:)
acehreli on 2012-03-17, 06:23:
Evet, size_t'de bir yanlış anlama var.

Salih Dinçer:
size_t: "Derleyicinin, sistem kaynaklarına ve kodun işleyişine göre karar verdiği (tanımladığı) bir veri türüdür."

Sistem kaynakları deyince bellek miktarı gibi bir kavram anlaşılabiliyor. size_t'nin sistemle öyle bir ilgisi yoktur.

Kodun işleyişi derken de çalışma zamanı ile ilgili bir kavramdan bahsediyorsan o da olamaz. Hatırlarsak, D derlemeli bir dil olduğundan bütün türler derleme sonunda bellidir. (Aslında kod işlemeye başladığında tür diye bir kavram kalmamıştır; ama konuyu dağıtıyorum.)
Benim asıl bahsetmek istediğim tıpkı işlevleri "overload" yapmamız gibi derleme anında kodun işleyişi neyi ön görüyorsa o işlevi kullanmaya karar verdiğiydi. Gerçi artık size_t üzerine böyle bir görev yüklenemediğini öğrenmiş olduk. Ama ne iyi olmaz mıydı; "overload" olayının değişkenler üzerinde de uygulanabilmesi. Tabi şablon olayları ile çözebiliriz ki hocam bunu belirtmiş.

Şimdi çözüm üzerine çalışıyorum...
(bir yandan oku_ve_Anla() işlevi arkaplanda çalışıyor ama)
Bilgi paylaştıkça bir bakmışız; kar topu olmuş ve çığ gibi üzerimize geliyor...:)
Doğrulama Kodu: VeriCode Lütfen resimde gördüğünüz doğrulama kodunu girin:
İfadeler: :-) ;-) :-D :-p :blush: :cool: :rolleyes: :huh: :-/ <_< :-( :'( :#: :scared: 8-( :nuts: :-O
Özel Karakterler:
Sayfa:  1  2  sonraki 
Forum: Ders Arası RSS
Bağlı değilsiniz. · Şifremi unuttum · ÜYELİK
This board is powered by the Unclassified NewsBoard software, 20100516-dev, © 2003-10 by Yves Goergen
Şu an: 2017-11-18, 07:20:08 (UTC -08:00)