Pages

12 Şubat 2012 Pazar

Matlab'de hafıza

Merhabalar

Hız ve Hafıza. Bir programcının herzaman dert ettiği iki unsur. Bu yazıda matlabde hafıza kontrolünden bahsedeceğim. öncelikle hızlandırma konusunda matrislerin ilk başta tanımlanmasının hız dışında hafıza için ne gibi yararı var onu düşünelim. 
Matlabde değişken tanımlaması birçok programlama diline farklılık göstermektedir. Öyle ki matlabde bir matris (dizi - array) tanımlarsanız bunun için ram'de kesinlikle sıralı boş hafıza bulunması gerekmektedir. Çeşitli nedenlerden dolayı ram'de herzaman ihtiyaç olunan kadar sıralı boş,uygun hafıza mevcut değildir.
Bunu sayısal olarak açıklayalım. Örneğin 50 kutucuklu ram olsun.
a = 1 (ramin 10.)
b = 2 (ramin 25)
c = 3 (ramin 40)
değişkenleri tanımladığımız zaman program tarafından ramden rasgele hafızadan yer alınıyor. Burada 10 , 25 ve 40.cı adresler alınmış olsun. Böylece 50 kutucuk içinden alabileceğimiz sıralı maximum hafıza 14tür. Yani m = zeros(20,1) tanımlarsak hata alırız. Ama c 26.cı kutuya yerleşmiş olsaydı ozaman sorun olmayacaktı. Demek ki işimiz şansa kalmış. Ya da yapmamız gereken şey matrisi önceden tanımlamaktır. Ozaman sorun kalkar.
Matrisin olası boyutunu bilmiyorsanız kendiniz için çok büyük geçici bir matris oluşturun, program akışında ihtiyacınız olduğunda o alanı kullanırsınız.
gecici_m = zeros(1000,1)
program_run.......
clearvars gecici_m
yeni_m1 = zeros(300,1)
yeni_m2 = zeros(300,1)
gibi kullanabilirsiniz.

Clearvars komutunu görmüşken yapabileceğiniz diğer şieyler program akışı sırasında hafıza yetmiyorsa kullanmadığıınız değişkenleri clearvars komutuyla silin ve yeni değişkenlerinizi tanımlayın.
Mecburiyetten ileride kullanacağınız silemeyeceğiniz değişken var ise o değişkenleri harddiske kaydedin, işlem bittiği zaman geri alırsınız. örneğin
save degiskenim1, degiskenim2
işlemlerim...
load degiskenim1,degiskenim2
Bu işlemin kodu yavaşlatacağını unutmayın,çünkü harddiske erişim var.
Fonksiyonla işin içinden çıkılabilir mi, hayır. Çünkü bi yerden fonksiyon çağırdığınız zaman oraya kadar ki hafıza hala ram'dedir, fonksiyondaki değişkenler de onlara eklenecektir. Fonksiyonlardaki değişkenler ancak global değişken olarak tanımlanmamışsa fonksiyon bitiminde ölür ve rami boşaltırlar.

Bunların dışında yapabileceğiniz şeyler ise açık tüm programları kapatmaktır. msn,skype,explorer,bilgisayarım vs... Görünen ne varsa. Bi de görünmeyenler vardır. Bilgisayara kurulu bazı programların hizmetler kısmında otomatik olarak bazı kısımlarının çalışması ve arka fonda çalışan diğer exeleri. Bunları kontrol etmek biraz riskli,yanlış program açılış için engellenirse bilgisayarın açılmamasına sebeğ olabilir. Bununla ilgili daha sonra yazarım. 

Kolay gelsin...

5 Şubat 2012 Pazar

Fork nedir ?

Merhabalar.

İşletim sistemi denildiği zaman windows, linux, ubuntu, pardus ve daha nice bilmediğimiz 100lercesini düşünebiliriz. Hepsinin sistem call dediğimiz öntanımlı fonksiyonları vardır. Bunlardan biri de fork'tur. İşletim sistemi çalıştığı zaman sürekli çalışan processler vardır. Sadece işletim sistemi değil bilgisayarımıza kurduğumuz programlar da processler ile çalışmaktadır. Ve her process kendine özgü alt processler oluşturur. Bu fork sayesinde mümkün olmaktadır. Kodun herhangi bir yerinde fork() komutu çalıştırdığımız zaman yeni bir process oluşmuş demektir.
fork() komutu çalıştırıldığı anda çocuk (child), ve onu oluşturan process ise veli (parent) adını almaktadır. Çocuk yaratıldığı anda velinin hangi değişkeni var ise onun hepsinin kopyasını alır. VE. bulunduğu konumdan itibaren çalışır.
Cümleler ile bu işi anlamak zor olabilir. En iyisi kodu incelerken cümlelerdekini düşünmek gerekir. Bunun için googleda fork yazdığınızda ilk bulacağınız koddan başlayalım.

#include <stdio.h>
#include <sys/types>
#include <unistd.h>
#include <stdlib.h>

int main()
{
    pid_t pid;
        pid = fork();
        if(pid == 0)
        {
            printf("Ben cocugum, numaram \n");
            sleep(1);
            exit(0);
        }
        else
        {
            printf("Ben veliyim, numaram \n");
            sleep(1);

            exit(0);
        }
return 0;
}


pid = fork() satırından sonra yeni cocuk oluşuyor ve pid değerine -1 veya 0 gelir. -1 gelmiş ise cocuk oluşturulamamıştır, 0 gelmiş ise sorun yoktur ve cocuk oluşmuştur. Demek ki output olarak "ben cocugum" ve "ben veliyim" yazıları gelecek. Ama sırası nedir. Kimse bilemez. Çünkü bilgisayarın çalışma mantıgında genellikle biraz o iş biraz öteki işi yapayım mantığı vardır. Bununla ilgili yazımı daha sonra yazarım.
Not: sleep(1) - 1 sn bekle, exit(0) bulunduğu procesi sonlandır.
Fork!u daha iyi anlamanın yolu dene yanıl yine dene mantığından geçtiğini düşündüğüm için bu koda biraz farklılıklar uygulayarak çalışma prensibini daha iyi kavrarız diye düşünüyorum. Gelin bir döngü kuralım,deneyelim.

int dongusayisi = 1;
for(i = 0; i < dongusayisi; i++)
{
    pid = fork();
    if(pid == 0)
    {
        printf("%d Ben cocugum, numaram = %d %d\n",i,getpid(),getppid());
        sleep(1);
    }
    else
    {
        printf("%d Ben veliyim, numaram = %d\n",i,getpid());
        sleep(1);
    }
}

exit(0)

(kodun üst ve alt taraflarını tekrar yapıştırmadım) dongusayisi = 1 iken ilk verdiğim koddan farkı olmayacaktır. dongusayisi = 2 yapin. ve çıkan sonucu inceleyin. Göreceksiniz ki cocuk bi anda veli olmuş:). Bu kısmı anlatmak zor, kodu takip edin. adım adım ise şöyle olur:
i = 0 iken - fork çalıştı (1.ci cocuk) -şimdi 1.ci cocuktaki i degeri i = 1. yani for(i = 1; i < 2; i++)
i = 0 iken - veli çalıştı  
i = 1 iken - (1.ci cocuk) fork çalıştı (1.cocuğun cocugu) şimdi i = 2
i = 1 iken - (1.ci cocuk) veli çalıştı
i = 1 iken - veli çalıştı
bilgisayarın çalışma prensibine göre sonuçlar farklı sıralarda gelebilirler.  not edelim: getpid() öntanımlı metodu bulunduğu procesin "process ID" sini verir. bu bir int değeridir. getppid() ise "parent process ID"dir. Yani velinin id'sidir.
Buradan görüldüğü gibi böyle birşey yapmak belki programcının işine yarayabilir ama genellikle başağrısıdır. Bir de şu şekilde denersek:

    for(i = 0; i < dongusayisi; i++)
    {
        pid = fork();
        if(pid == 0)
        {
            printf("%d Ben cocugum, numaram = %d %d\n",i,getpid(),getppid());
            sleep(1);

            exit(0); // değişiklik burada!!!
        }
        else
        {
            printf("%d Ben veliyim, numaram = %d\n",i,getpid());
            sleep(1);
        }
    }

exit(0)

Eğer çocuk procesi içinde exit(0) koyarsak 1 cocuk nested cocuklar üretmeden ömrünü tamamlayacaktır. Bu daha çok tercih edilebilir. 
Peki fork yapmak ne işimize yarar, işkence gibi birşey? Mantık yürütmek gerekir ya da google'a bakmak.
Peki bu çoluk çocuk oluşturuldu kendi başlarına, ne olacak bunların sonu, birbirlerinden haberleri olacak mı? - tabi ki. çoluk cocuk veli kendi aralarında pipe (boru,hortum)vasıtasıyla işkence usulü anlaşırlar. Pipeler ile ilgili daha sonra yazacağım.

Kolay gelsin :)

1 Şubat 2012 Çarşamba

CPP'de büyük sayıların çarpımı

Merhabalar.

Bildiğiniz gibi derleyiciler belli bytelarda sayıları tutabilmekte ve buna bağlı olarak sayılar çarpıldığında da bu byte sınır kadar izin vermektedirler. Örneğin çarpmak istediğimiz ve compilere input olarak girebileceğimiz 2 int sayısının çarpımı oldukça büyük olacağından derleyici bize muhtemelen çöp dönecektir. Bu yine de yapılamayacak bir durum değildir. Yine derleyicinin bize sağlamış olduğu dizilerle kolay olmasa da çok da güzel bir şekilde bu işi gerçekleştirebiliriz.

Paylaşacağım kodda tüm değişkenleri "long long int" olarak tanımladım. Nereye kadar çalıştığını görmek istedim. Ubuntuda g++ version 4.4.3'da denemelerimi gerçekleştirdim. Vektör ve dinamik bellek ayırmalar olduğu için windowsta ne tepkiler verir şuan için tahmin edemiyorum. Ama sanırım problem olmaz,zira ortada sistem call tarzı çalışması garip processler bulunmamaktadır:).

Daha önce C'de yazmıştım. Hem dağınık yazmışım hem de yeterince test etmedim, %100 doğru çalıştığından emin değilim. Bu sefer C++'da yazdım. Hem okunaklı hem açık. Özellikle vektörlerin Arraylere nazaran kolay kullanılabilirliğini farkedeceksiniz. Ekran görüntüsü ise böyledir.


Kod ise aşağıdaki gibidir. Hata durumları ve hız konusunda öneriler bekliyorum. Ayrıca çarpmadan sonra bölme işlemi nasıl olur, veya floating point çarpımları nasıl olur. Hatta bunu sadece input girilebilen bir sistem haline nasıl getirmek mümkün olur, hepsi soru işareti ?

/* Multiplication of large numbers */
#include <iostream>
#include <vector>
using namespace std;
int main()
{
    long long int sizex = 0, sizey = 0, sizetotal;
    long long int x, y, tmp;
    long long int n, m, tmpx, tmpy;
    vector < vector <long long int> > v;
    vector < long long int > tmpvx;
    vector < long long int > tmpvy;
    long long int birler, onlar, k = 0;
    x = 1223372036854775808;
    y = 1223372036854775808;
    cout <<"Compiler destekleyen byte: " << sizeof(long long int) << endl;
    tmp = x;
    while( tmp )
    {// x sayısı kaç basamaklıdır
        sizex++;
        tmp /= 10;
    }
    tmp = y;
    while( tmp )
    {// y sayısı kaç basamaklıdır
        sizey++;
        tmp /= 10;
    }// toplam basamak + 1 olası carry bit
    sizetotal = sizex + sizey + 1;
    v.resize(sizey + 1); // vektör malloc/realloc
    for(int i = 0; i < v.size(); i++)
    {
        v[i].resize(sizetotal + 1); // 2D vektör yap
        for(int j = 0; j < sizetotal + 1; j++)
            v[i][j] = 0; // içini sıfırla
    }
    n = 10;
    m = 1;
    for(int i = 0; i < sizetotal + 1; i++)
    {
        if(m < x && i < sizex)
        {// x sayısını basamaklarına ayır vektöre yedekle
            tmpx = x%n;
            tmpx = tmpx/m;
            tmpvx.resize(tmpvx.size() + 1);
            tmpvx[i] = tmpx;
        }
        if(m < y && i < sizey)
        {// y sayısını basamaklarına ayır vektöre yedekle
            tmpy = y%n;
            tmpy = tmpy/m;
            tmpvy.resize(tmpvy.size() + 1);
            tmpvy[i] = tmpy;
        }
        m = n;
        n *= 10;
    }
    k = 0;
    for(int i = 0; i < tmpvy.size(); i++)
    {
        for(int j = 0; j < tmpvx.size(); j++)
        {// y sayısının sondan itibaren rakamlarını x'in rakamları ile çarpıyoruz
            tmp = tmpvx[j] * tmpvy[i];
            onlar = tmp / 10;
            birler = tmp % 10;
            v[i][j + k] += birler;
            v[i][j + k + 1] += onlar;
        }
        for(int j = 0; j < sizetotal; j++)
        {// sonucu baştan tarayıp rakam olmayanları 10'a bölüp carry olarak sağa atıyoruz
            if(v[i][j] > 9)
            {
                tmp = v[i][j];
                v[i][j] = tmp % 10;
                v[i][j + 1] += tmp / 10;
            }
        }
        k++;
    }
    cout<<"vektor:"<<endl;
    // son işleme girmeden önceki hali - çalıştırmaya gerek yok
    /*
    for(int i = 0; i < sizey + 1; i++)
    {
        for(int j = 0; j < sizetotal + 1; j++)
            cout << v[i][j] << " ";
            cout << endl;
    }*/
    tmp = 0;
    for(int i = 0; i < sizetotal + 1; i++)
    {// toplama sonucunda taşmalar olabilir, Carry kontrolü yapılıyor
        for(int j = 0; j < sizey; j++)
            tmp += v[j][i];
        v[sizey][i] = tmp % 10;
        v[sizey][i + 1] += tmp / 10;
        tmp = v[sizey][i + 1];
    }
   
    for(int i = 0; i < sizey + 1; i++)
    {// vektörü bir bütün olarak yaz
        for(int j = 0; j < sizetotal + 1; j++)
            cout << v[i][j] << " ";
            cout << endl;
    }
        cout << "Carpim Sonucu: "<<endl;
    int flag = 0;
    for(int i = sizetotal; i>=0; i--)   
    {// sonucu yaz. Baştaki gereksiz sıfırlardan arınılıyor. vektörün son satırına dikkat
        if(v[sizey][i] != 0 || flag)
        {
            flag = 1;
            cout << v[sizey][i];
        }
    }
    cout << endl;

    return 0;
}

30 Ocak 2012 Pazartesi

Matlabde olasılık problemleri için ipucu

Merhabalar

Bazı problemlerde olasılık kullanmak durumundayız. Bazen kesin yüzdeler veririz ve bunun gerçekleşmesini isteriz. Örneğin bir a değişkeninin değeri %80 olasılıkla 1, %20 olasılıkla 0 olmasını istersek demek ki 10 adımda 8 kez a = 1 ve 2 kez de a = 0 dır.
Matlab için hep kullandığımız rand fonksiyonu işimizi görür aslında. Alttaki fonksiyonu birkaç kez çalıştırıp j ve k değerlerini görebilirsiniz

j = 0;
k = 0;
for i = 1:10
   if rand <= 0.8
       j = j + 1;
   else
       k = k + 1;
   end
end
j
k



ve alttaki kod ise kesin  %80e %20 lik çalıştırmakta. döngü sayınız 10 ise durum aşağıdaki gibi


j = 0; k = 0;
r = randperm(10)
for i = 1:10
   if(r(i) <= 8)
       j = j + 1;
   else
       k = k + 1;
   end
end

k

Peki döngü sayısı 10un katı ise 1000 gibi ? Bu durumda yapılacak değişiklik 10 yerine 1000, 8 yerine de 800 konulur.
10'un katı değil ise. Dongu sayısını 10'a göre mod alıp kalan kadar rand yaparsınız olur biter. Birazcık hata kaçınılmaz.
not: randperm fonksiyonu rand gibi bu ve buna benzer problemler için oldukça kullanışlıdır, tavsiye ederim

Kolay gelsin