Bircogunuz başlığa bakınca convert constructor mı o da ne diyordur herhalde, aslında convert constructor C++ da bildiğimiz içerisine parametre alan constructor a denmektedir. Peki sizce neden böyle bir ad konulma gereği duyulmuş bu parametre alan constructor tipine? sadece constructor denseydi parametre almayan constructordan nasıl ayrılacaktı... peki böyle bir ayrıma ihtiyaç var mı? peki copy constructor var bide o ne? etrafta bu kadar constructor dolanırken neden bir tanecik destructor var:) Bu soruların cevabını merak ediyorsanız bu yazımı okuyabilirsiniz, merak etmiyorsanız bir aşağıdaki yazıya alalım sizi:)
Şimdi siz aşağıda ki kodu bir inceleyin ve bu kodun çalışıp çalışmayacağını kendinize söyleyin ( Bu şekilde sorduğuma göre kodun çalışmasını bekliyorsunuzdur herhalde :) )
#include<iostream>
using namespace std;
class Test{
int var;
public:
Test( int v = 0 ) : var( v ) {}
int getVar() const { return this->var; }
};
void function( Test t1 ){
cout << t1.getVar()<< endl;
}
int main(){
function( 50 );
return 0;
}
Evet gelelim cevaba. Bu kodun çalışacağını söyleyenler malasef kaybeden tarafta yer almıycaklar:) evet çalışır bu kod. Peki;
gördüğünüz üzere function fonksyonunun giriş parametresi class Test tipinden tanımlanmıştır. Ozaman demek ki bizim function fonksiyonuna Test nesnesi vermemiz gerekir. Oysa biz napıyoruz açıkça bir int parametre veriyoruz...
İşte burada convert constructor dediğimiz olay devreye giriyor! 50 sayısı Test için yazdığımız constructora yada birden fazla varsa sırayla, verilerek Test nesnesine cast edilmeye yani 50 sayısı ile bir giriş parametresi oluşturulmaya çalışılıyor...
Burada argümanlar bire bir uyuştuğu için, Test sınıfının constructor ı bir tane int parametre alır, bu casting işi başarılı oluyor ve Yığında bir adet Test nesnesi oluşturuluyor. Bu yüzden bu constructorlar convert constructor olarak adlandırılmıştır.
Peki gelelim bu durumu engellemek için yapılabileceklere. Bazen böyle bir durumun gerçekleşmesini istemeyebiliriz. Fonksiyonun sadece bir nesneyi direk olarak vererek çalışmasını istediğimiz zamanlar olabilir. Bunu engellemek için ben 3 tane yol önerecem sizin aklına gelirse commentleyin lütfen:)
1) Fonksyionun giriş parametresini referance yapalım. Yani:
void function( Test& t1 ); şeklinde tanımlarsak, yığında nesne oluşturmak işe yaramayacaktır. Çünkü t1 nesnesi direk nesnenin kendisi olmalıdır ( kopyası değil! ) Bu yüzden bu şekilde bir fonksyon için function( 50 ); çağrısı hata verecektir.
2) Hiç convert constructor yazmayalım.. Bu mümkün bir çözüm olmasına rağmen akıldan uzaktır. 3. yöntem e bakın siz:)
3) explicit anahtar sözcüğünü kullanırsak derleyiciye function( 50 ); çağrısının mümkün olamayacağını söylemiş oluruz.
Peki nedir bu explicit? eğer bir convert constructor ı explicit olarak yazarsak, bu constructorın dışarıdan dolaylı olarak nesne üretmesini engellemiş oluruz. Yani function( 50 ); çağrısında ki 50 değeri bu constructor a giremez.
explicit Test( int v=0 ) : var( v ) {}
Evet işte convert constructlar hakkında kısaca söyleceğim şeyler bunlardı. convert constructorlardan başka bir de copy contructorlar var. copy constructor lar ise, bir nesneden bir nesne üretilceği zaman çalıştırılır. örneğin
Test t1;
Test t2 = t1; //copy constructor çalışır.
eğer sınıfınızın üyeleri arasında dinamik bellek ile ayrılmış değişkenler yoksa ( işaretçiler), sizin açıkça bir copy constructor yazmanız çoğu zaman gereksizdir ( gerekli olduğu durumlar da vardır uygulamanıza göre ). Çünkü derleyici otomatik olarak size bir adet constructor ve copy constructor sağlayacaktır. derleyicinin sağladığı copy constructor basitçe değişkenlerin değerlerini kopyalanandan kopyalayana atar. Eğer siz bir copy constructor ve constructor yazarsanız sınıfınıza, derleyici size default olarak bu fonksiyonları artık sağlamaz ve sizin yazdıklarınız geçerli olur. O yüzden eğer bilmeyerek constructor ı private alana koyarsanız, niye nesne oluşturamıyorum diye şaşırmayın:) her zaman nesne oluşturmak istiyorsanız constructorlarınız public alanda olmalı ki dışarıdan çağrılabilsin.
Constructorlarda ki bu çeşitliliğe karşılık destructor her zaman 1 tanedir. Bunun sebebi burada yapılacak işlemelerin genelde kaynakları geri iade etmek ve giriş çıkış işlemlerini tamamlamak gibi giriş parametresine bağlı olmayan değerlerdir. ve nesne yok edilirken kendiliğinden otomatik olarak çağrılmasıdır.
Bu yazımda sizlere convert constructorların bir özelliğinden bahsetmeye ve diğer constructorlar hakkında kısaca bilgi vermeye çalıştım. Bir sonraki yazımda görüşmek üzere...
Tuesday, January 16, 2007
Monday, January 15, 2007
Sabitler de artık değişmeye başladı...
yarın finale gireceğim için bu gece karışık bişeyler yazmamaya karar verdim, ve kısaca size C de programlamanın ne kadar çok programcıya bırakıldığını göstermeye kadar verdim. Güzel bir trick yaparak const tanımlanan değişkenleri değiştirelim ne derseniz....
Derleyici const olarak tanımlanmış bir değişkene direk olarak bir atama yaptığınız da şöyle bir hata verecektir:
#include<iostream>
using namespace std;
int main(){
const int thisIsConstant = 10;
thisIsConstant = 9;
cout << thisIsConstant << endl ;
return 0;
}
error C2166: l-value specifies const object
gördüğünüz gibi l-value ( left value ) bir const nesneye işaret ediyor dedi derleyicim. Bunun anlamı sen atama yapamazsın çünkü sol da bir const değişken var, nereye atama yapıon sen filan diyor :)
ama derleyiciye sezdirmeden bu const değişkeni değiştirebiliriz... Değiştirdikten sonra bir soru sorucam bilene benden bi çikolata:)
işte değiştiriyoruz const değişkeni:
#include<iostream>
using namespace std;
int main(){
int* ptr;
const int thisIsConstant = 10;
ptr = ( int* ) &thisIsConstant; //cast ediyoruz
*ptr = 9; //degistirdikkkk
cout << thisIsConstant << endl;
return 0;
}
Evet thisIsConstant değişkenin bellek gözünde 9 mu yazıyor dersiniz??? Benim sistemimde ekran çıktısı:
10
Press any key to continue
10 yazıyor! Bunun sebebi, derleyicinin object kodunu oluştururken thisIsConstant değişkeni gördüğü yerleri değeriyle değiştirmesidir, derleyici kodda bu değişkenin değerinin 10 olduğunu ve const tanımlandığını görünce nasolsa bu const değişken değişemez diyip değerini object koda gömdü. ( Systems programming ders1 : studying assembly language provides; deeper understanding how the compiler works! )
Bu arada merak ediyosanız, debug yaparak değişkenin içeriğine baktığınız da ( ben baktım :) ) içerisinde 9 yazdığını göreceksiniz. Ama object kodda değişkenin kullanıldığı yerde değişkenin adresi değil derlendiği anda ki içeriği yani 10 değeri olduğu için aslında
cout << thisIsConstant << endl; satırı
cout << 10 << endl;
satırı ile yer değiştirmiştir ;) Derleyicim VS 6.0, başka derleyiciler de derlediğiniz zaman bu optimize yapılmıyorsa ekran da 9 sayısını görürsünüz. Mesala ben bu denemeden sonra, cpp uzantılı dosyayı c olarak değiştirdim, tabi iostream i de stdio ile
#include<stdio.h>
int main(){
int a = 5;
int* ptr;
const int thisIsConstant = 10;
ptr = ( int* ) &thisIsConstant; //cast ediyoruz
*ptr = 9; //degistirdikkkk
printf("%d\n",thisIsConstant);
return 0;
}
işte ekran çıktısı:
9
Press any key to continue
Demek ki neymiş efendim, vs 6.0 da C ve C++ derlenirken kodun optimize edilişi farklıymış.
Aynı kodları, ssh ile itu ye bağlanip gcc ile derledim.
Sonuçlar:
C kodu için ekrana 9 değeri bastı,
C++ kodu için ekrana 10 değeri bastı.
Buradan genelleme yaparsak, C++ derleyicileri kodu optimize ederken, const değişkenlerin değerlerini object koda direk gömerler. C derleyicileri değişkenlerin adresilerini kullanmaya devam ederler. ( En azından VS 6.0 ve Gcc/G++ öle yapıo ).
Const değişkenler ve pointerlar hakkında söylenecek bayağı bir şey var aslında,
mesala;
const int* ptr ile int* const ptr nin farklı şeyler olduğunu biliyor muydunuz?
const int* ptr ; ile işaretçinin içeriğini değiştirebilirsiniz ama işaret ettiği verinin içeriği değişemez.
int x, y;
const int* ptr = &x ; //işaretçi oluşturulurken değer atanıyor OK
*ptr = 111; //işaretçinin gösterdiği yerdeki veri değişemez, HATA
ptr = &y; //işaretçi farklı bir değişkene işaret ettirildi, OK
int* const ptr; de ise işaretçinin işaret ettiği adres değişemez, ama içerdiği veri değişebilir:
int x,y;
int* const ptr = &x ; //işaretçi oluşturulurken değeri atandı, OK
*ptr = 111; //işaretçinin verisi değiştirilebilir OK
ptr = &y; //işaretçi const tanımlanmıştı, başka bir yere işaret edemez, HATA
Son olarakta const int* const ptr; ile tanımlanmış bir işaretçinin ne içerdiği veri, ne de gösterdiği yer değişebilir. ( yukarıda ki iki işaretçinin birleşimi gibi )
Bu yazımda da sizlerle birlikte const değişkenleri/işaretçileri tartışmış olduk.
Bir sonra ki yazımda C++ da convert constructor larla ilgili ilginç bir konuya değinmek istiyorum inşallah:) Görüşmek üzere...
Derleyici const olarak tanımlanmış bir değişkene direk olarak bir atama yaptığınız da şöyle bir hata verecektir:
#include<iostream>
using namespace std;
int main(){
const int thisIsConstant = 10;
thisIsConstant = 9;
cout << thisIsConstant << endl ;
return 0;
}
error C2166: l-value specifies const object
gördüğünüz gibi l-value ( left value ) bir const nesneye işaret ediyor dedi derleyicim. Bunun anlamı sen atama yapamazsın çünkü sol da bir const değişken var, nereye atama yapıon sen filan diyor :)
ama derleyiciye sezdirmeden bu const değişkeni değiştirebiliriz... Değiştirdikten sonra bir soru sorucam bilene benden bi çikolata:)
işte değiştiriyoruz const değişkeni:
#include<iostream>
using namespace std;
int main(){
int* ptr;
const int thisIsConstant = 10;
ptr = ( int* ) &thisIsConstant; //cast ediyoruz
*ptr = 9; //degistirdikkkk
cout << thisIsConstant << endl;
return 0;
}
Evet thisIsConstant değişkenin bellek gözünde 9 mu yazıyor dersiniz??? Benim sistemimde ekran çıktısı:
10
Press any key to continue
10 yazıyor! Bunun sebebi, derleyicinin object kodunu oluştururken thisIsConstant değişkeni gördüğü yerleri değeriyle değiştirmesidir, derleyici kodda bu değişkenin değerinin 10 olduğunu ve const tanımlandığını görünce nasolsa bu const değişken değişemez diyip değerini object koda gömdü. ( Systems programming ders1 : studying assembly language provides; deeper understanding how the compiler works! )
Bu arada merak ediyosanız, debug yaparak değişkenin içeriğine baktığınız da ( ben baktım :) ) içerisinde 9 yazdığını göreceksiniz. Ama object kodda değişkenin kullanıldığı yerde değişkenin adresi değil derlendiği anda ki içeriği yani 10 değeri olduğu için aslında
cout << thisIsConstant << endl; satırı
cout << 10 << endl;
satırı ile yer değiştirmiştir ;) Derleyicim VS 6.0, başka derleyiciler de derlediğiniz zaman bu optimize yapılmıyorsa ekran da 9 sayısını görürsünüz. Mesala ben bu denemeden sonra, cpp uzantılı dosyayı c olarak değiştirdim, tabi iostream i de stdio ile
#include<stdio.h>
int main(){
int a = 5;
int* ptr;
const int thisIsConstant = 10;
ptr = ( int* ) &thisIsConstant; //cast ediyoruz
*ptr = 9; //degistirdikkkk
printf("%d\n",thisIsConstant);
return 0;
}
işte ekran çıktısı:
9
Press any key to continue
Demek ki neymiş efendim, vs 6.0 da C ve C++ derlenirken kodun optimize edilişi farklıymış.
Aynı kodları, ssh ile itu ye bağlanip gcc ile derledim.
Sonuçlar:
C kodu için ekrana 9 değeri bastı,
C++ kodu için ekrana 10 değeri bastı.
Buradan genelleme yaparsak, C++ derleyicileri kodu optimize ederken, const değişkenlerin değerlerini object koda direk gömerler. C derleyicileri değişkenlerin adresilerini kullanmaya devam ederler. ( En azından VS 6.0 ve Gcc/G++ öle yapıo ).
Const değişkenler ve pointerlar hakkında söylenecek bayağı bir şey var aslında,
mesala;
const int* ptr ile int* const ptr nin farklı şeyler olduğunu biliyor muydunuz?
const int* ptr ; ile işaretçinin içeriğini değiştirebilirsiniz ama işaret ettiği verinin içeriği değişemez.
int x, y;
const int* ptr = &x ; //işaretçi oluşturulurken değer atanıyor OK
*ptr = 111; //işaretçinin gösterdiği yerdeki veri değişemez, HATA
ptr = &y; //işaretçi farklı bir değişkene işaret ettirildi, OK
int* const ptr; de ise işaretçinin işaret ettiği adres değişemez, ama içerdiği veri değişebilir:
int x,y;
int* const ptr = &x ; //işaretçi oluşturulurken değeri atandı, OK
*ptr = 111; //işaretçinin verisi değiştirilebilir OK
ptr = &y; //işaretçi const tanımlanmıştı, başka bir yere işaret edemez, HATA
Son olarakta const int* const ptr; ile tanımlanmış bir işaretçinin ne içerdiği veri, ne de gösterdiği yer değişebilir. ( yukarıda ki iki işaretçinin birleşimi gibi )
Bu yazımda da sizlerle birlikte const değişkenleri/işaretçileri tartışmış olduk.
Bir sonra ki yazımda C++ da convert constructor larla ilgili ilginç bir konuya değinmek istiyorum inşallah:) Görüşmek üzere...
Sunday, January 14, 2007
Struct ve Union da ne ola ki...
Neredeyse yazdığım programların hiç birinde union kullanmadım, hatta bu cümleyi okurken bazılarımız union da ne ola ki diyebilir.
struct C de yaygin olarak kullanilan, C++ da ise class olarak bilinen bir veri tipidir. C++ da ki class ile C de ki struct in farklari tabi ki vardır, orneğin default olarak class yapısında değişkenler private tanımlanır. yani;
class emreknlkCokClass{ //:))
int var;
};
emreknlkCokClass sınıfının içerisinde tanımlanmış var değişkeni private dır ve dışarıdan erişelemez. struct da ise varsayılan erişim tipi public olup dışardan değişkenlere erişilebilir.
Neyse benim bu akşam canım sıkıldı. O yüzden struct ve union ı kendime oyuncak seçtim, hadi biraz oynayalım ;)
1) Makineniz little endian mı big endian mı öğrenmek istermisiniz...
Little endian ve big endian kavramları nedir bilmeyenler için özetleyim: Verilerinizin bellekte nasıl saklandığına yönelik kavramlardır. Big endian kısmında verinin en yüksek anlamlı kısmı düşük adreste, düşük anlamlı kısmı yüksek adreste saklanır. Bu insanların da rahatça anlayabileceği bir yöntemdir. Mesala $4579 verisini 1000 no lu bellek gözüne yazmak isterseniz, 1000 nolu bellek gözünün içeriği 45 , 1001 no lu bellek gözünün içeriği 79 olacaktır.
Little endian da tahmin edeceğiniz üzere bunun tam tersi, 1000 nolu bellek gözünde 79, 1001 nolu bellek gözünde 45 yazacak...
işte union yapısı ile:
#include<stdio.h>
union WhichEndian{
int number; //4 byte
char byte; //1 byte
};
int main(){
union WhichEndian find;
int i;
char* ptr;
find.number = 0x12345678;
ptr = &find.byte;
for(i = 0; i < sizeof( int ) ; i++)
printf("Memory address: %p\tData: %x\n",ptr, (int)*(ptr++));
return 0;
}
ve benim makinemde işte size ekran çıktısı:
Memory address: 0012FF7C Data: 78
Memory address: 0012FF7D Data: 56
Memory address: 0012FF7E Data: 34
Memory address: 0012FF7F Data: 12
Press any key to continue
Gördüğünüz gibi little endian çıktı benim toşibam :))
Gelelim kodaa, union ne yapar, ne işe yarar kısaca bir özet geçeyim: union içerisinde ki bütün değişkenleri bellekte aynı offset değerinden başlayarak yerleştirir. Kodda bir integer ve bir char kullandık, bunların ikisininde başlangıç adresleri aynıdır. aslında bu kodda char byte değişkenine gerek yoktu, aslında yukardaki sonucu elde etmek için union kullanmak bile gereksizdi, ama burada dikkatinizi çekmek istediğim nokta:
ptr = &find.byte;
satırıdır. Burada ptr adresi byte değişkenin adresini içeriyorsa da aslında number değişkeni ile byte değişkeni aynı bellek gözünden başlayarak tanımlandıkları için, for döngüsü içerisinde number değişkeninin içeriğini sıra ile düzgün bastırabildik.
Eğer burada union değil de struct kullanacak olsaydık bu kod çalışmayacaktı. Çünkü byte değişkeni number ın bittiği yerden başlayacaktı...
2) Struct ile bit show
Diyelim ki elimiz de 8 tane led var. Bu ledlerin durumunu ( on/off ) kontrol etmek istiyoruz. Her bir led için 1 integer değer tutarsak 8*sizeof(int) kadar bellek bosuna gitmis olacak. Ben diyorum ki gelin her led için 1 bit kullanalım ve toplam 1 byte yer ayırarak bu işi bitirelim...
işte gerekli struct yapısı ve program kodu
#include<stdio.h>
#define OFF 0
#define ON 1
struct LedControl
{
unsigned char led1: 1;
unsigned char led2: 1;
unsigned char led3: 1;
unsigned char led4: 1;
unsigned char led5: 1;
unsigned char led6: 1;
unsigned char led7: 1;
unsigned char led8: 1;
};
int main(){
struct LedControl vecii; //LED leri vecii yaksin kapasin...
printf("Led Control %d byte yer kaplar..\n",sizeof(vecii));
vecii.led1 = OFF;
printf("1. led: %d\n",vecii.led1);
vecii.led1 = ON;
printf("1. led: %d\n",vecii.led1);
return 0;
}
Görüldüğü gibi struct içinde tanımlana led lerin her biri 1 bit yer kaplar. Bu bitlere erişim normal değişkenlere erişim gibidir. her değişken için bir bit ayırmak zorunluluğu yoktur.
Şimdi ekran çıktısını inceleyip struct için gerçekten 1 byte yer ayrıldığını görebiliriz:
Led Control 1 byte yer kaplar..
1. led: 0
1. led: 1
Press any key to continue
Peki nerelerde kullanılır bu yapı, herhalde enterprise edition lı program yazarken pek işimiz düşmez bu yapılara:) Ama sistem programlama da, driver yazmada , embeded sistemler için yazılım geliştirme de ciddi derece başvurulabilen bir metot olarak karşımıza çıkar.
Bu yazımda da size basitçe struct ve union ı tekrar hatırlatmak istedim. Basit şeyler olmasına karşın pek başvurulmadığı için zamanla fonksyonları unutulabiliyor. Diğer yazılarımda görüşmek üzere...
struct C de yaygin olarak kullanilan, C++ da ise class olarak bilinen bir veri tipidir. C++ da ki class ile C de ki struct in farklari tabi ki vardır, orneğin default olarak class yapısında değişkenler private tanımlanır. yani;
class emreknlkCokClass{ //:))
int var;
};
emreknlkCokClass sınıfının içerisinde tanımlanmış var değişkeni private dır ve dışarıdan erişelemez. struct da ise varsayılan erişim tipi public olup dışardan değişkenlere erişilebilir.
Neyse benim bu akşam canım sıkıldı. O yüzden struct ve union ı kendime oyuncak seçtim, hadi biraz oynayalım ;)
1) Makineniz little endian mı big endian mı öğrenmek istermisiniz...
Little endian ve big endian kavramları nedir bilmeyenler için özetleyim: Verilerinizin bellekte nasıl saklandığına yönelik kavramlardır. Big endian kısmında verinin en yüksek anlamlı kısmı düşük adreste, düşük anlamlı kısmı yüksek adreste saklanır. Bu insanların da rahatça anlayabileceği bir yöntemdir. Mesala $4579 verisini 1000 no lu bellek gözüne yazmak isterseniz, 1000 nolu bellek gözünün içeriği 45 , 1001 no lu bellek gözünün içeriği 79 olacaktır.
Little endian da tahmin edeceğiniz üzere bunun tam tersi, 1000 nolu bellek gözünde 79, 1001 nolu bellek gözünde 45 yazacak...
işte union yapısı ile:
#include<stdio.h>
union WhichEndian{
int number; //4 byte
char byte; //1 byte
};
int main(){
union WhichEndian find;
int i;
char* ptr;
find.number = 0x12345678;
ptr = &find.byte;
for(i = 0; i < sizeof( int ) ; i++)
printf("Memory address: %p\tData: %x\n",ptr, (int)*(ptr++));
return 0;
}
ve benim makinemde işte size ekran çıktısı:
Memory address: 0012FF7C Data: 78
Memory address: 0012FF7D Data: 56
Memory address: 0012FF7E Data: 34
Memory address: 0012FF7F Data: 12
Press any key to continue
Gördüğünüz gibi little endian çıktı benim toşibam :))
Gelelim kodaa, union ne yapar, ne işe yarar kısaca bir özet geçeyim: union içerisinde ki bütün değişkenleri bellekte aynı offset değerinden başlayarak yerleştirir. Kodda bir integer ve bir char kullandık, bunların ikisininde başlangıç adresleri aynıdır. aslında bu kodda char byte değişkenine gerek yoktu, aslında yukardaki sonucu elde etmek için union kullanmak bile gereksizdi, ama burada dikkatinizi çekmek istediğim nokta:
ptr = &find.byte;
satırıdır. Burada ptr adresi byte değişkenin adresini içeriyorsa da aslında number değişkeni ile byte değişkeni aynı bellek gözünden başlayarak tanımlandıkları için, for döngüsü içerisinde number değişkeninin içeriğini sıra ile düzgün bastırabildik.
Eğer burada union değil de struct kullanacak olsaydık bu kod çalışmayacaktı. Çünkü byte değişkeni number ın bittiği yerden başlayacaktı...
2) Struct ile bit show
Diyelim ki elimiz de 8 tane led var. Bu ledlerin durumunu ( on/off ) kontrol etmek istiyoruz. Her bir led için 1 integer değer tutarsak 8*sizeof(int) kadar bellek bosuna gitmis olacak. Ben diyorum ki gelin her led için 1 bit kullanalım ve toplam 1 byte yer ayırarak bu işi bitirelim...
işte gerekli struct yapısı ve program kodu
#include<stdio.h>
#define OFF 0
#define ON 1
struct LedControl
{
unsigned char led1: 1;
unsigned char led2: 1;
unsigned char led3: 1;
unsigned char led4: 1;
unsigned char led5: 1;
unsigned char led6: 1;
unsigned char led7: 1;
unsigned char led8: 1;
};
int main(){
struct LedControl vecii; //LED leri vecii yaksin kapasin...
printf("Led Control %d byte yer kaplar..\n",sizeof(vecii));
vecii.led1 = OFF;
printf("1. led: %d\n",vecii.led1);
vecii.led1 = ON;
printf("1. led: %d\n",vecii.led1);
return 0;
}
Görüldüğü gibi struct içinde tanımlana led lerin her biri 1 bit yer kaplar. Bu bitlere erişim normal değişkenlere erişim gibidir. her değişken için bir bit ayırmak zorunluluğu yoktur.
Şimdi ekran çıktısını inceleyip struct için gerçekten 1 byte yer ayrıldığını görebiliriz:
Led Control 1 byte yer kaplar..
1. led: 0
1. led: 1
Press any key to continue
Peki nerelerde kullanılır bu yapı, herhalde enterprise edition lı program yazarken pek işimiz düşmez bu yapılara:) Ama sistem programlama da, driver yazmada , embeded sistemler için yazılım geliştirme de ciddi derece başvurulabilen bir metot olarak karşımıza çıkar.
Bu yazımda da size basitçe struct ve union ı tekrar hatırlatmak istedim. Basit şeyler olmasına karşın pek başvurulmadığı için zamanla fonksyonları unutulabiliyor. Diğer yazılarımda görüşmek üzere...
Saturday, January 13, 2007
Template C++
Bu postumda size belki biraz sıradışı ama ilginizi çekecek bir konuyu tanıtacağım. Yazıyı okumadan önce C++ ve template bilginizi tazeleyin derim, basit tutucam örneği ama yine de anlamayabilirsiniz:)
Bildiğiniz gibi template kavramı c++ nın güçlü ve önemli bir yanıdır. generic dediğimiz fonksyonlar sınıflar veritipleri oluşturmak için kullanırız genelde. örneğin bir absolute fonksyonu yazacaksak template kullandığımız zaman bütün veri tipleri için ( int float double ... ) ayrı ayrı yazmamıza gerek kalmaz. programcı bir kere yazar bu fonksyonu derleyici sağolsun çevirir....
Benim burada bahsetmek istediğim şey ise daha uçuk bişi:)
Önce gelin template i unutalım ve normal babadan kalma yöntemle bir fibonacci serisinin 20. terimini sadece 50 kere hesaplatalım ve ne kadar zaman alıo ölçelim:
#include < iostream >
using namespace std;
class Fibbooo{
public:
static int FindNth( int n ){
if( n == 0 )
return 0;
if( n == 1 )
return 1;
else
return FindNth( n - 1 ) + FindNth( n - 2);
}
};
int main(){
int result,i;
for( i = 0; i < 50; i++ )
result = Fibbooo::FindNth( 20 );
cout << result;
return 0;
}
Kodun çıktısında 20.terim: 6765 ve en önemlisi toplam süre:
Program Statistics ------------------
Command line at 2007 Jan 14 01:56:
"D:\ITU\c++\fib\Debug\fib"
Total time: 482,825 millisecond
Time outside of functions: 17,381 millisecond
Call depth: 21
Total functions: 1088
Total hits: 1095805
Function coverage: 26,2%
Overhead Calculated 3
Overhead Average 3
Module Statistics for fib.exe
-----------------------------
Time in module: 465,444 millisecond
Percent of time in module: 100,0%
Functions in module: 1088
Hits in module: 1095805
Module function coverage: 26,2%
Görüldüğü gibi modülün yürütülmesi 465,4 milisaniye, tüm program da 482 milisaniye de bitti.
Şimdi gelelim Template Meta Programming e, kodu daha sonra açıklayacağım. önce heycanlanmanız için kodu ve sonucu veriyim. işte kod:
#include <iostream>
template<n>
struct fibonacci
{
enum { result = fibonacci < n-1 >::result + fibonacci < n - 2 >::result};
};
template <>
struct fibonacci<0>
{
enum { result = 0 };
};
template <>
struct fibonacci<1>
{
enum { result = 1 };
};
int main() {
int result,i;
for( i = 0; i < 50; i++)
result = fibonacci<20>::result;
std::cout << result;
return 0;
}
ekran çıktısı bir önceki ile aynı. peki zamanlamalara göz atalım:
Program Statistics ------------------
Command line at 2007 Jan 14 01:59:
"D:\ITU\c++\fib\Debug\template"
Total time: 32,450 millisecond
Time outside of functions: 19,927 millisecond
Call depth: 15
Total functions: 1087
Total hits: 1255
Function coverage: 26,1%
Overhead Calculated 3
Overhead Average 3
Module Statistics for template.exe
----------------------------------
Time in module: 12,522 millisecond
Percent of time in module: 100,0%
Functions in module: 1087
Hits in module: 1255
Module function coverage: 26,1%
Evet, bazılarınız gözlerinize inanamamış olabilir, hatta benim bir yerlerde yannış yaptığımı da düşünebilir:) ama gördükleriniz doğru. program 32,5 milisaniyede ( ilk koda göre yaklaşık 15 kat daha hızlı) modül ise 12,5 milisaniyede ( yaklaşık 35 kat daha hızlı ) bir şekilde çalıştı.
Peki neden? Bunun sebebi aslında çok basit, siz execute tuşuna bastınız, yada exe ye çift tıkladınız, program loader programı belleğe aldı. Aslında tam bu noktada, yani loader programı belleğe yüklerken fibonacci serisinin 20. terimi hazırdı!!! evet hazırdı, program run time da hesaplamaz onu, compile ettiğiniz anda dosyayı 20.terim hesaplanır ve object kodunun içine yazılır. Nasıl mı? template ler compile aşamasında derleyici tarafından değiştirilerek yerine gelmesi gereken kod konulur. örneğin yukarıda bahsettiğim absolute fonksyonunu template ile yazıp, main içerisinde double için fonksyonu çağırırsanız, derlerken derleyici sizin bu fonksyonu double için çağırdığınızı görüp, template ifadelerini atıcak ve yerine sadece double için çalışan absolute fonk. nu yerleştirecektir.
Hal böyleyken, siz derlemeye başladığınız anda derleyici aşağıda ki ifadeyi görecek:
fibonacci<20>::result;
ve fibonacci<20>::result değerini hesaplamaya başlayacaktır. bunun için rekürsif olarak sürekli fibonacci < n > li struct ın değerini hesaplayacak, ne zaman ki n = 0 veya n = 1 olunca fibonacci<0> veya fibonacci<1> in değerlerini ( result değişkenlerini ) alabilecek, ozaman hesaplama bitmiş olacak...
Templateler ile programlama bir çok algoritmayı önemli derecede hızlandırabilmektedir. Uygulama da c++ programları bir run time da hesaplar yapan bölüm, bir de template meta programming dediğimiz bu şekilde kodlama ile yazılır ve compile time denilen yerde işlerin bir bölümü halledilmiş olunur.
Umarım bir miktar açıklayabilmişimdir TMP yi. daha fazlası için bknz google :) Sonraki yazılarımda görüşmek üzere...
Bildiğiniz gibi template kavramı c++ nın güçlü ve önemli bir yanıdır. generic dediğimiz fonksyonlar sınıflar veritipleri oluşturmak için kullanırız genelde. örneğin bir absolute fonksyonu yazacaksak template kullandığımız zaman bütün veri tipleri için ( int float double ... ) ayrı ayrı yazmamıza gerek kalmaz. programcı bir kere yazar bu fonksyonu derleyici sağolsun çevirir....
Benim burada bahsetmek istediğim şey ise daha uçuk bişi:)
Önce gelin template i unutalım ve normal babadan kalma yöntemle bir fibonacci serisinin 20. terimini sadece 50 kere hesaplatalım ve ne kadar zaman alıo ölçelim:
#include < iostream >
using namespace std;
class Fibbooo{
public:
static int FindNth( int n ){
if( n == 0 )
return 0;
if( n == 1 )
return 1;
else
return FindNth( n - 1 ) + FindNth( n - 2);
}
};
int main(){
int result,i;
for( i = 0; i < 50; i++ )
result = Fibbooo::FindNth( 20 );
cout << result;
return 0;
}
Kodun çıktısında 20.terim: 6765 ve en önemlisi toplam süre:
Program Statistics ------------------
Command line at 2007 Jan 14 01:56:
"D:\ITU\c++\fib\Debug\fib"
Total time: 482,825 millisecond
Time outside of functions: 17,381 millisecond
Call depth: 21
Total functions: 1088
Total hits: 1095805
Function coverage: 26,2%
Overhead Calculated 3
Overhead Average 3
Module Statistics for fib.exe
-----------------------------
Time in module: 465,444 millisecond
Percent of time in module: 100,0%
Functions in module: 1088
Hits in module: 1095805
Module function coverage: 26,2%
Görüldüğü gibi modülün yürütülmesi 465,4 milisaniye, tüm program da 482 milisaniye de bitti.
Şimdi gelelim Template Meta Programming e, kodu daha sonra açıklayacağım. önce heycanlanmanız için kodu ve sonucu veriyim. işte kod:
#include <iostream>
template<n>
struct fibonacci
{
enum { result = fibonacci < n-1 >::result + fibonacci < n - 2 >::result};
};
template <>
struct fibonacci<0>
{
enum { result = 0 };
};
template <>
struct fibonacci<1>
{
enum { result = 1 };
};
int main() {
int result,i;
for( i = 0; i < 50; i++)
result = fibonacci<20>::result;
std::cout << result;
return 0;
}
ekran çıktısı bir önceki ile aynı. peki zamanlamalara göz atalım:
Program Statistics ------------------
Command line at 2007 Jan 14 01:59:
"D:\ITU\c++\fib\Debug\template"
Total time: 32,450 millisecond
Time outside of functions: 19,927 millisecond
Call depth: 15
Total functions: 1087
Total hits: 1255
Function coverage: 26,1%
Overhead Calculated 3
Overhead Average 3
Module Statistics for template.exe
----------------------------------
Time in module: 12,522 millisecond
Percent of time in module: 100,0%
Functions in module: 1087
Hits in module: 1255
Module function coverage: 26,1%
Evet, bazılarınız gözlerinize inanamamış olabilir, hatta benim bir yerlerde yannış yaptığımı da düşünebilir:) ama gördükleriniz doğru. program 32,5 milisaniyede ( ilk koda göre yaklaşık 15 kat daha hızlı) modül ise 12,5 milisaniyede ( yaklaşık 35 kat daha hızlı ) bir şekilde çalıştı.
Peki neden? Bunun sebebi aslında çok basit, siz execute tuşuna bastınız, yada exe ye çift tıkladınız, program loader programı belleğe aldı. Aslında tam bu noktada, yani loader programı belleğe yüklerken fibonacci serisinin 20. terimi hazırdı!!! evet hazırdı, program run time da hesaplamaz onu, compile ettiğiniz anda dosyayı 20.terim hesaplanır ve object kodunun içine yazılır. Nasıl mı? template ler compile aşamasında derleyici tarafından değiştirilerek yerine gelmesi gereken kod konulur. örneğin yukarıda bahsettiğim absolute fonksyonunu template ile yazıp, main içerisinde double için fonksyonu çağırırsanız, derlerken derleyici sizin bu fonksyonu double için çağırdığınızı görüp, template ifadelerini atıcak ve yerine sadece double için çalışan absolute fonk. nu yerleştirecektir.
Hal böyleyken, siz derlemeye başladığınız anda derleyici aşağıda ki ifadeyi görecek:
fibonacci<20>::result;
ve fibonacci<20>::result değerini hesaplamaya başlayacaktır. bunun için rekürsif olarak sürekli fibonacci < n > li struct ın değerini hesaplayacak, ne zaman ki n = 0 veya n = 1 olunca fibonacci<0> veya fibonacci<1> in değerlerini ( result değişkenlerini ) alabilecek, ozaman hesaplama bitmiş olacak...
Templateler ile programlama bir çok algoritmayı önemli derecede hızlandırabilmektedir. Uygulama da c++ programları bir run time da hesaplar yapan bölüm, bir de template meta programming dediğimiz bu şekilde kodlama ile yazılır ve compile time denilen yerde işlerin bir bölümü halledilmiş olunur.
Umarım bir miktar açıklayabilmişimdir TMP yi. daha fazlası için bknz google :) Sonraki yazılarımda görüşmek üzere...
Analiz: Nasıl kod yazabiliriz?
Anladım ki benim yazılarım genel de yaşadığım güncel olaylar üzerine çıkıyor. Şimdi size geçenler de itü bilgisayar grubumuz da konustugumuz bir konuyu hararetli bicimde aktaricam hazir olun:) Yaziyi sonuna kadar takip etmenizi oneririm sonunda şaşırabilirsiniz...
Ozgur Macit arkadasimin deyimiyle;
Efendim gecen gun grubumuza bir mail geldi bi arkadasimiz tarafindan. Mail de herkesin bildiği bir swap islemi C/C++ dilinde farkli bir sekilde yazilmisti. Buyrun inceleyelim:
#include
int main(void)
{
int a = 3, b = 5;
a = a^b;
b = a^b;
a = a^b;
printf("%d\n", a);
printf("%d\n", b);
return 0;
}
// ^ XOR islemi bu arada :)
Alinti: Onur Dolu
Goruldugu gibi 3 tane XOR islemi yapilarak a ve b değiskenlerinin yeri değiştirimiş. Xor işlemi matematikte/programlamada çok işe yarıyor daha sonra başka örnekler yazmayı düşünüyorum da biz gelelim esas konuya: Bu kodu bilinen temp değişkeni üzerinden eski değeri saklayıp, daha sonra a ve b değişkenlerinin değerini değiştiren swap koduna tercih edilebilr mi?
Bu arada yukarıda yazılmış olan kod aşağıda ki şekilde de kısaltılabiliyor:
int a = 3, b = 5;
a ^= b ^=a ^=b;
Grupta bulunan sevdiğim bir arkadaşım bu koda doğal olarak karşı çıktı. Nedenini ise şu şekilde açıkladı:
"Okuması da oldukça zor oluyor..
Kod bir kere yazılır ama defalarca okunur..
Senden sonra programda değişlik yapması gereken bir programcı aşağıdaki satırı anlıyamıyabileceğ inden veya daha kötüsü yanlış anlıyabileceğinden saatler veya günler kaydebilir.. Proje başarızlığa uğrayabilir."...
Yukarıda aynen alıntısını aldığım yazı hakkında herhalde herkes fikir birliğine varmıştır. Bu kodu okumak matematik bilgisi çok iyi olmayan bir programcı için imkansıza yakın olduğu gibi, matematik bilgisi olan bir programci için de zaman alıcı ve can sıkıcıdır.
Bunun üzerine ne yapılabilir diye düşündüm. Kod daha efektif duruyordu. Yukardaki probleme bir çözüm üretmeden önce bunu teyid etmem gerekti ( Hazırsanız birazdan kendinizi sonu gelmeyen bir kaosun içinde bulacaksınız!! ) :
Test1 ( yeni swap )
#include //stdio gereksiz bu kodda ama printf koymustum kalmis oyle:)
int main(void)
{
int a = 3, b = 5;
int i;
for( i = 0; i < 100001; i++ ){
a ^= b ^= a ^= b;
}
return 0;
}
Bu kodun çalışması sonucunda şu değerler elde edildi:
Program Statistics
------------------
Command line at 2007 Jan 13 11:28: "D:\ITU\c++\fib\Debug\swap"
Total time: 17,024 millisecond
Time outside of functions: 15,794 millisecond
Call depth: 1
Total functions: 1
Total hits: 1
Function coverage: 100,0%
Overhead Calculated 3
Overhead Average 3
Module Statistics for swap.exe
------------------------------
Time in module: 1,231 millisecond
Percent of time in module: 100,0%
Functions in module: 1
Hits in module: 1
Module function coverage: 100,0%
Func Func+Child Hit
Time % Time % Count Function
---------------------------------------------------------
1,231 100,0 1,231 100,0 1 _main (swap.obj)
Görüldüğü gibi döngü yaklaşık 1,231 milisaniye de tamamlandı.
Şimdi ikinci swap işlemini incelemeye geldi sıra. Bildiğmiz temp değişkeni üzerinden elde edilen swap....
Test1 ( klasik swap )
#include
int main(void)
{
int a = 3, b = 5;
int i, temp;
for( i = 0; i < 100001; i++ ){
temp = a;
a = b;
b = a;
}
return 0;
}
Evet heycanla bu kodu yazdım ve sonucu gerçekten çok merak ediyordum. Eğer tahminlerim doğruysa bu kodun çalışması en az 2 kat yavaş olacaktı çünkü fazladan bir temp değişkenine erişim vardı. Belleğe erişimin registerlar üzerinde xor işleminden çok daha fazla sürmesi gerekirdi. Şimdi sonuca bakalım:
Program Statistics
------------------
Command line at 2007 Jan 13 11:35: "D:\ITU\c++\fib\Debug\swap"
Total time: 2,228 millisecond
Time outside of functions: 1,538 millisecond
Call depth: 1
Total functions: 1
Total hits: 1
Function coverage: 100,0%
Overhead Calculated 3
Overhead Average 3
Module Statistics for swap.exe
------------------------------
Time in module: 0,690 millisecond
Percent of time in module: 100,0%
Functions in module: 1
Hits in module: 1
Module function coverage: 100,0%
Func Func+Child Hit
Time % Time % Count Function
---------------------------------------------------------
0,690 100,0 0,690 100,0 1 _main (swap.obj)
Evet herkes gördü sonucu, bende gördüm, gördüm sonra gözlerime inanamadım, inanamadım bir daha çalıştırdım, çalıştırdım yine aynı sonucu gördüm, gördüm gözlerime inanamadım...
Sonuç beni hem hayal kırıklığına uğratmıştı hem de heycanlandırmıştı. Bu sonucu beklemediğim açıktı. Demek ki ya ben bi yerlerde yanlış yaptım, ya da...
Evet ya da derleyici de bir sorun vardı:) Bu arada derleyici MSVS 6.0
Ve derleyiciden şüphe duydum! Daha önceki tecrübelerimden biliyordum ki derleyici assembly kodunu oluştururken arada geçici bellek atamaları yapıyordu. Kodu tekrar yazmalıydım ama bu sefer inline assembly kullanacaktım, kalp atışlarım hızlanmıştı.
Ama, evet ama önce söylediğim şeyin gerçek olduğunu size göstermeliydim. Test1 kodunun disassemblysine baktım işte size de göstereyim ( sadece for döngüsü içinde ki tek satır xor işlemleri) :
00401041 mov ecx,dword ptr [ebp-4] <- varan 1
00401044 xor ecx,dword ptr [ebp-8] <- varan 2
00401047 mov dword ptr [ebp-4],ecx <- varan 3
0040104A mov edx,dword ptr [ebp-8] ....
0040104D xor edx,dword ptr [ebp-4] ....
00401050 mov dword ptr [ebp-8],edx ....
00401053 mov eax,dword ptr [ebp-4] ....
00401056 xor eax,dword ptr [ebp-8] ....
00401059 mov dword ptr [ebp-4],eax <- varan 9
Evet kod gerçekten beni "in a horror" vaziyetine düşürmüştü! ben saf ve masum bir şekilde registerlar da xor işlemi yapiyordum. Ama derleyici her işlem sonucunu bir bellek gözünde saklıyordu!!! bu ise performansı inanılmaz bir şekilde düşürüyordu. Gerçekten vs 6.0 dan korkmaya başlamıştım...
ve test2 deki temp kullanarak gerçekleştirilen 3 atama işlemi ile swap yaptığım kodu disassembly ettim ve işte sonuc:
9: temp = a;
00401041 mov ecx,dword ptr [ebp-4]
00401044 mov dword ptr [ebp-10h],ecx
10: a = b;
00401047 mov edx,dword ptr [ebp-8]
0040104A mov dword ptr [ebp-4],edx
11: b = a;
0040104D mov eax,dword ptr [ebp-4]
00401050 mov dword ptr [ebp-8],eax
Bu kod kesinlikle belleğe daha az erişiyordu. Aslında tam da yapması beklenen işlemi yapıyordu. önce a değişkenini ecx e atıyor sonra ecx i temp bellek gözüne atıyordu ve diğer a=b ve b=a içinde aynılarını yapıyordu.
test2 nin kodu bu kadar iyi çalıştığı halde test1 neden bukadar kötüydü? Şeytan beni iyice kodu inline assembly de yazmaya itiyordu...
Ama önce son bir kez daha brain storming yapmak istedim. Düşündüm... registerlar üzerinde xor işlemi yapmak istiyordum. Ama yazdığım kod registerlar üzerinde değil bellek üzerinde, bellekten değerleri registerlar a çekerek, daha sonra registerlar da gerçekleştirdiği xor işlemlerini tekrar belleğe yazarak gerçekleştiriyordu. Evet yazarken farkediyodum herşeyi, bir emreknlk nasil bu kadar dikkatsizce davranabilirdi, bir emreknlk bu hatayi nasil yapabilirdi!
VS 6.0.. O kadar günahını aldığım derleyici. Aslında ben ne söylüyorsam onu yapıyordu! Onun hiç bir suçu yoktu tek suçlu vardı o da emreknlk! Kodu yazarken dikkat ederseniz değişkenler int a ve int b olarak tanımlamıştım. Yani ben dedim ki: Git esp den ( stack pointer) 8 çıkar! Değişkenleri yığında oluşturuyordum!!! Yani bellekte! sonra nasıl olurda bütün işlemleri registerlar üzerinde yapmasını bekleyebilirdim ki... Bellekten a ve b yi alıp tekrar a ve b yi belleğe yazması gerekiyor derleyicinin çünkü ben ona öyle yap demiştim!
Peki şimdi İnline assembly de yazmama gerek varmıydı? İnline assembly de yazarsam kodun hızlanacağını biliyordum. Çünkü asm kodunu ben gömecektim C nin içine. Ama C nin de bana sunduğu yetenekleri göz ardı edemezdim.
Evet register anahtar sözcüğü ( keyword ) değişkenleri bellekte değil, eğer mümkünse registerlar da oluşturuyordu. hemen
int a, b; ifadesini register int a, b; ifadesi olarak değiştirdim.
Sonucu merak ediyor olmalısınız. Sonuç değişmedi... Bir kaos içinde kalmıştım. Düşündüğüm hiç bir şey çalışmıyordu. Başarısızlık ard arda geliyordu. Belki de beni C ye bu kadar bağlayan şey buydu.
Araştırmaya başladım. niye çalışmadı niye sonuç aynıydı. tekrar disassebly ye baktım sonuçta yine a ve b değişkeni registerlarda değil yığında oluşturulmuştu! peki bu nasıl olabilirdi? Oysa ben açıkça registerlarda oluştur demiştim değişkenleri. Sonunda kendimi msdn de buldum. işte açıklamaları:
"The compiler does not accept user requests for register variables; instead, it makes its own register choices when global register-allocation optimization (/Oe option) is on. However, all other semantics associated with the register keyword are honored."
Evet vs 6.0 register anahtar sözcüğü için bizi sallamıyordu. belki de güvenmiyordu. Bu C nin esnekliğinin bir yerde kaybolması demekti. Düşündüm, kodu linux de derlesem çalışacaktı. Bundan şüphem yoktu. register anahtar sözcüğü ile test1 de yazdığımız xor lu kod hızlı çalışacaktı.
Ama bir sorun vardı! Birden adil davranmadığımı anladım. test2 içinde temp, a ve b değişkenlerini register anahtar sözcüğü ile tanımlasam daha o daha da hızlı çalışacaktı. 3 register da sadece 3 atama işlemi. işte hız buydu...
Peki son bir çırpınış, bu yazıma başlarken hatırlarsanız kodun okunabilirliğini sağlamak için yapılması gerekenleri anlatmak ama önce o kodun hızlı çalışması gerektiğini ispatlamak istiyordum. hızlı çalıştığını ispatlamadan nasıl olurda bu kodu kullanın diyebilirdim ki size, üstelik daha da okunabilirliği azaltırken.
Evet iki koda da adil olarak davrandığım sürece her yola başvurmalıydım. register fikri çok iyi bir fikir değildi. Büyük programlarda bu yöntem patlayabilirdi. Şimdi geriye malesef tek bir çözüm kaldı. Bu çözüm de başarısızlığa uğrarsa... düşünmek bile istemiyorum.
Inline assembly
Evet heycan dorukta. Bu sefer vs60 var bir de ben varım...
işte test 1, xor işlemleri ile yapılan swap işlemi ( Not: bu kod main içinde tanımlanmış ama swap fonksyonu içerisinen alınabilir, testleri yapmak için bu şekilde yazdım) :
#include
int main(void)
{
int a = 3, b = 5;
int i;
for( i = 0; i < 100001; i++ ){
__asm{
mov eax, [a]
mov ebx, [b]
xor eax, ebx
xor ebx, eax
xor eax, ebx
mov [a], eax
mov [b], ebx
}
}
return 0;
}
Gördüğünüz gibi asm kodu visual studio 6.0 içinde main içinde duruyor. şimdi bakalım sonuca:
Profile: Function timing, sorted by time
Date: Sat Jan 13 12:50:05 2007
Program Statistics
------------------
Command line at 2007 Jan 13 12:50: "D:\ITU\c++\fib\Debug\swap"
Total time: 1,702 millisecond
Time outside of functions: 1,112 millisecond
Call depth: 1
Total functions: 1
Total hits: 1
Function coverage: 100,0%
Overhead Calculated 3
Overhead Average 3
Module Statistics for swap.exe
------------------------------
Time in module: 0,589 millisecond
Percent of time in module: 100,0%
Functions in module: 1
Hits in module: 1
Module function coverage: 100,0%
Func Func+Child Hit
Time % Time % Count Function
---------------------------------------------------------
0,589 100,0 0,589 100,0 1 _main (swap.obj)
Evetttt, işte bu mudur? budur dedirten sonuç kendini gösterdi!!! 0.589 milisaniye şu ana kadar elde edilen en iyi süre. Şimdi biraz sevinç duyuyorum ama daha herşey bitmedi diğer kodu da bu şekilde yazıp sonuçları karşılaştırmam gerek.
işte temp kullanılarak gerçekleştirilen swap işleminin inline assembly li hali:
#include
int main(void)
{
int a = 3, b = 5;
int i,temp;
for( i = 0; i < 100001; i++ ){
__asm{
mov eax, [a]
mov [temp], eax ; a nin degeri temp de
mov ebx, [b]
mov [a], ebx ; b nin degeri a da
mov eax, [temp]
mov [b], eax ;temp in degeri b de
}
}
return 0;
}
ve sonuç geliyor:
Profile: Function timing, sorted by time
Date: Sat Jan 13 12:56:28 2007
Program Statistics
------------------
Command line at 2007 Jan 13 12:56: "D:\ITU\c++\fib\Debug\swap"
Total time: 21,834 millisecond
Time outside of functions: 21,197 millisecond
Call depth: 1
Total functions: 1
Total hits: 1
Function coverage: 100,0%
Overhead Calculated 3
Overhead Average 3
Module Statistics for swap.exe
------------------------------
Time in module: 0,637 millisecond
Percent of time in module: 100,0%
Functions in module: 1
Hits in module: 1
Module function coverage: 100,0%
Func Func+Child Hit
Time % Time % Count Function
---------------------------------------------------------
0,637 100,0 0,637 100,0 1 _main (swap.obj)
Evet en sonunda istediğim sonuç... 0.637 milisaniye . Biraz acımasız davrandım ikinci swap a kabul ediyorum ama en iyiye ulaşmak kolay olmuyor tabi :))
Dahası var...
inline assembly kullanarak temp i de atabilirz! işte 3. yol:
#include
int main(void)
{
int a = 3, b = 5;
int i;
for( i = 0; i < 100001; i++ ){
__asm{
mov eax, [a]
mov ebx, [b]
mov [a], ebx ; b nin degeri a da
mov [b], eax ; a nin degeri b de
}
}
return 0;
}
ve işte en kısası şimdi geliyorrrr :)
Profile: Function timing, sorted by time
Date: Sat Jan 13 13:00:59 2007
Program Statistics
------------------
Command line at 2007 Jan 13 13:00: "D:\ITU\c++\fib\Debug\swap"
Total time: 1,597 millisecond
Time outside of functions: 1,095 millisecond
Call depth: 1
Total functions: 1
Total hits: 1
Function coverage: 100,0%
Overhead Calculated 4
Overhead Average 4
Module Statistics for swap.exe
------------------------------
Time in module: 0,501 millisecond
Percent of time in module: 100,0%
Functions in module: 1
Hits in module: 1
Module function coverage: 100,0%
Func Func+Child Hit
Time % Time % Count Function
---------------------------------------------------------
0,501 100,0 0,501 100,0 1 _main (swap.obj)
Yani bu yazıdan çıkaracağımız pek çok sonuç var, ama en önemlisi vazgeçememek bana sorarsanız...
Sonuç olarak gelmek istediğim, asıl anlatmak istediğin noktaya gelemedim aslında, yazımın amacı kodu okunabilir yapmaktı. Bu konu hakkında bir cümleyle şunu söyleyebilirim ki: eğer elinizde daha efektif bir kod varsa, ve bu kodun okunabilirliği diğer algoritmalara göre daha kötüyse, o kodu, isminden görevinin anlaşılacağı bir fonksyon içerisine gömmek ( tek satır olsa dahi kodunuz) ve programınızı yazarken o koda ihtiyacınız olduğu yerde yazdığınız fonksyonu çağırmaktır. Fonskyonun ismini güzelce belirlerseniz, kodunuzu okuyanın fonksyon içerisinde yazdığınız kodu okuması gerekmeyecektir. Black box olara düşünülebilir fonksyonunuz.
Bir başka önemli nokta da, burada kodu zamanlama bakımından değerlendirdik. Günümüz bilgisayarlarında bellek sorunu olmamaktadır. ANCAK, gömülü sistemlerde, gerçek zaman sistemlerinde ciddi bellek kısıtlamaları vardır. Bu durumda 4 byte lık bir temp değişkenini bile kullanmak istemeyebilirsiniz. Bu durumda xor ile swap işlemi yapmak gerçekten işinize gelebilir. Kodu da büyük ihtimalle assembly ile yazacağınız için bu yöntem daha efektif olacaktır.
Yazı biraz uzadı ama ben yazarken gerçtekten keyif aldım, umarım sizde sıkılmamışsınızdır. Sonraki yazılarımda görüşmek dileğiyle...
Ozgur Macit arkadasimin deyimiyle;
Efendim gecen gun grubumuza bir mail geldi bi arkadasimiz tarafindan. Mail de herkesin bildiği bir swap islemi C/C++ dilinde farkli bir sekilde yazilmisti. Buyrun inceleyelim:
#include
int main(void)
{
int a = 3, b = 5;
a = a^b;
b = a^b;
a = a^b;
printf("%d\n", a);
printf("%d\n", b);
return 0;
}
// ^ XOR islemi bu arada :)
Alinti: Onur Dolu
Goruldugu gibi 3 tane XOR islemi yapilarak a ve b değiskenlerinin yeri değiştirimiş. Xor işlemi matematikte/programlamada çok işe yarıyor daha sonra başka örnekler yazmayı düşünüyorum da biz gelelim esas konuya: Bu kodu bilinen temp değişkeni üzerinden eski değeri saklayıp, daha sonra a ve b değişkenlerinin değerini değiştiren swap koduna tercih edilebilr mi?
Bu arada yukarıda yazılmış olan kod aşağıda ki şekilde de kısaltılabiliyor:
int a = 3, b = 5;
a ^= b ^=a ^=b;
Grupta bulunan sevdiğim bir arkadaşım bu koda doğal olarak karşı çıktı. Nedenini ise şu şekilde açıkladı:
"Okuması da oldukça zor oluyor..
Kod bir kere yazılır ama defalarca okunur..
Senden sonra programda değişlik yapması gereken bir programcı aşağıdaki satırı anlıyamıyabileceğ inden veya daha kötüsü yanlış anlıyabileceğinden saatler veya günler kaydebilir.. Proje başarızlığa uğrayabilir."...
Yukarıda aynen alıntısını aldığım yazı hakkında herhalde herkes fikir birliğine varmıştır. Bu kodu okumak matematik bilgisi çok iyi olmayan bir programcı için imkansıza yakın olduğu gibi, matematik bilgisi olan bir programci için de zaman alıcı ve can sıkıcıdır.
Bunun üzerine ne yapılabilir diye düşündüm. Kod daha efektif duruyordu. Yukardaki probleme bir çözüm üretmeden önce bunu teyid etmem gerekti ( Hazırsanız birazdan kendinizi sonu gelmeyen bir kaosun içinde bulacaksınız!! ) :
Test1 ( yeni swap )
#include
int main(void)
{
int a = 3, b = 5;
int i;
for( i = 0; i < 100001; i++ ){
a ^= b ^= a ^= b;
}
return 0;
}
Bu kodun çalışması sonucunda şu değerler elde edildi:
Program Statistics
------------------
Command line at 2007 Jan 13 11:28: "D:\ITU\c++\fib\Debug\swap"
Total time: 17,024 millisecond
Time outside of functions: 15,794 millisecond
Call depth: 1
Total functions: 1
Total hits: 1
Function coverage: 100,0%
Overhead Calculated 3
Overhead Average 3
Module Statistics for swap.exe
------------------------------
Time in module: 1,231 millisecond
Percent of time in module: 100,0%
Functions in module: 1
Hits in module: 1
Module function coverage: 100,0%
Func Func+Child Hit
Time % Time % Count Function
---------------------------------------------------------
1,231 100,0 1,231 100,0 1 _main (swap.obj)
Görüldüğü gibi döngü yaklaşık 1,231 milisaniye de tamamlandı.
Şimdi ikinci swap işlemini incelemeye geldi sıra. Bildiğmiz temp değişkeni üzerinden elde edilen swap....
Test1 ( klasik swap )
#include
int main(void)
{
int a = 3, b = 5;
int i, temp;
for( i = 0; i < 100001; i++ ){
temp = a;
a = b;
b = a;
}
return 0;
}
Evet heycanla bu kodu yazdım ve sonucu gerçekten çok merak ediyordum. Eğer tahminlerim doğruysa bu kodun çalışması en az 2 kat yavaş olacaktı çünkü fazladan bir temp değişkenine erişim vardı. Belleğe erişimin registerlar üzerinde xor işleminden çok daha fazla sürmesi gerekirdi. Şimdi sonuca bakalım:
Program Statistics
------------------
Command line at 2007 Jan 13 11:35: "D:\ITU\c++\fib\Debug\swap"
Total time: 2,228 millisecond
Time outside of functions: 1,538 millisecond
Call depth: 1
Total functions: 1
Total hits: 1
Function coverage: 100,0%
Overhead Calculated 3
Overhead Average 3
Module Statistics for swap.exe
------------------------------
Time in module: 0,690 millisecond
Percent of time in module: 100,0%
Functions in module: 1
Hits in module: 1
Module function coverage: 100,0%
Func Func+Child Hit
Time % Time % Count Function
---------------------------------------------------------
0,690 100,0 0,690 100,0 1 _main (swap.obj)
Evet herkes gördü sonucu, bende gördüm, gördüm sonra gözlerime inanamadım, inanamadım bir daha çalıştırdım, çalıştırdım yine aynı sonucu gördüm, gördüm gözlerime inanamadım...
Sonuç beni hem hayal kırıklığına uğratmıştı hem de heycanlandırmıştı. Bu sonucu beklemediğim açıktı. Demek ki ya ben bi yerlerde yanlış yaptım, ya da...
Evet ya da derleyici de bir sorun vardı:) Bu arada derleyici MSVS 6.0
Ve derleyiciden şüphe duydum! Daha önceki tecrübelerimden biliyordum ki derleyici assembly kodunu oluştururken arada geçici bellek atamaları yapıyordu. Kodu tekrar yazmalıydım ama bu sefer inline assembly kullanacaktım, kalp atışlarım hızlanmıştı.
Ama, evet ama önce söylediğim şeyin gerçek olduğunu size göstermeliydim. Test1 kodunun disassemblysine baktım işte size de göstereyim ( sadece for döngüsü içinde ki tek satır xor işlemleri) :
00401041 mov ecx,dword ptr [ebp-4] <- varan 1
00401044 xor ecx,dword ptr [ebp-8] <- varan 2
00401047 mov dword ptr [ebp-4],ecx <- varan 3
0040104A mov edx,dword ptr [ebp-8] ....
0040104D xor edx,dword ptr [ebp-4] ....
00401050 mov dword ptr [ebp-8],edx ....
00401053 mov eax,dword ptr [ebp-4] ....
00401056 xor eax,dword ptr [ebp-8] ....
00401059 mov dword ptr [ebp-4],eax <- varan 9
Evet kod gerçekten beni "in a horror" vaziyetine düşürmüştü! ben saf ve masum bir şekilde registerlar da xor işlemi yapiyordum. Ama derleyici her işlem sonucunu bir bellek gözünde saklıyordu!!! bu ise performansı inanılmaz bir şekilde düşürüyordu. Gerçekten vs 6.0 dan korkmaya başlamıştım...
ve test2 deki temp kullanarak gerçekleştirilen 3 atama işlemi ile swap yaptığım kodu disassembly ettim ve işte sonuc:
9: temp = a;
00401041 mov ecx,dword ptr [ebp-4]
00401044 mov dword ptr [ebp-10h],ecx
10: a = b;
00401047 mov edx,dword ptr [ebp-8]
0040104A mov dword ptr [ebp-4],edx
11: b = a;
0040104D mov eax,dword ptr [ebp-4]
00401050 mov dword ptr [ebp-8],eax
Bu kod kesinlikle belleğe daha az erişiyordu. Aslında tam da yapması beklenen işlemi yapıyordu. önce a değişkenini ecx e atıyor sonra ecx i temp bellek gözüne atıyordu ve diğer a=b ve b=a içinde aynılarını yapıyordu.
test2 nin kodu bu kadar iyi çalıştığı halde test1 neden bukadar kötüydü? Şeytan beni iyice kodu inline assembly de yazmaya itiyordu...
Ama önce son bir kez daha brain storming yapmak istedim. Düşündüm... registerlar üzerinde xor işlemi yapmak istiyordum. Ama yazdığım kod registerlar üzerinde değil bellek üzerinde, bellekten değerleri registerlar a çekerek, daha sonra registerlar da gerçekleştirdiği xor işlemlerini tekrar belleğe yazarak gerçekleştiriyordu. Evet yazarken farkediyodum herşeyi, bir emreknlk nasil bu kadar dikkatsizce davranabilirdi, bir emreknlk bu hatayi nasil yapabilirdi!
VS 6.0.. O kadar günahını aldığım derleyici. Aslında ben ne söylüyorsam onu yapıyordu! Onun hiç bir suçu yoktu tek suçlu vardı o da emreknlk! Kodu yazarken dikkat ederseniz değişkenler int a ve int b olarak tanımlamıştım. Yani ben dedim ki: Git esp den ( stack pointer) 8 çıkar! Değişkenleri yığında oluşturuyordum!!! Yani bellekte! sonra nasıl olurda bütün işlemleri registerlar üzerinde yapmasını bekleyebilirdim ki... Bellekten a ve b yi alıp tekrar a ve b yi belleğe yazması gerekiyor derleyicinin çünkü ben ona öyle yap demiştim!
Peki şimdi İnline assembly de yazmama gerek varmıydı? İnline assembly de yazarsam kodun hızlanacağını biliyordum. Çünkü asm kodunu ben gömecektim C nin içine. Ama C nin de bana sunduğu yetenekleri göz ardı edemezdim.
Evet register anahtar sözcüğü ( keyword ) değişkenleri bellekte değil, eğer mümkünse registerlar da oluşturuyordu. hemen
int a, b; ifadesini register int a, b; ifadesi olarak değiştirdim.
Sonucu merak ediyor olmalısınız. Sonuç değişmedi... Bir kaos içinde kalmıştım. Düşündüğüm hiç bir şey çalışmıyordu. Başarısızlık ard arda geliyordu. Belki de beni C ye bu kadar bağlayan şey buydu.
Araştırmaya başladım. niye çalışmadı niye sonuç aynıydı. tekrar disassebly ye baktım sonuçta yine a ve b değişkeni registerlarda değil yığında oluşturulmuştu! peki bu nasıl olabilirdi? Oysa ben açıkça registerlarda oluştur demiştim değişkenleri. Sonunda kendimi msdn de buldum. işte açıklamaları:
"The compiler does not accept user requests for register variables; instead, it makes its own register choices when global register-allocation optimization (/Oe option) is on. However, all other semantics associated with the register keyword are honored."
Evet vs 6.0 register anahtar sözcüğü için bizi sallamıyordu. belki de güvenmiyordu. Bu C nin esnekliğinin bir yerde kaybolması demekti. Düşündüm, kodu linux de derlesem çalışacaktı. Bundan şüphem yoktu. register anahtar sözcüğü ile test1 de yazdığımız xor lu kod hızlı çalışacaktı.
Ama bir sorun vardı! Birden adil davranmadığımı anladım. test2 içinde temp, a ve b değişkenlerini register anahtar sözcüğü ile tanımlasam daha o daha da hızlı çalışacaktı. 3 register da sadece 3 atama işlemi. işte hız buydu...
Peki son bir çırpınış, bu yazıma başlarken hatırlarsanız kodun okunabilirliğini sağlamak için yapılması gerekenleri anlatmak ama önce o kodun hızlı çalışması gerektiğini ispatlamak istiyordum. hızlı çalıştığını ispatlamadan nasıl olurda bu kodu kullanın diyebilirdim ki size, üstelik daha da okunabilirliği azaltırken.
Evet iki koda da adil olarak davrandığım sürece her yola başvurmalıydım. register fikri çok iyi bir fikir değildi. Büyük programlarda bu yöntem patlayabilirdi. Şimdi geriye malesef tek bir çözüm kaldı. Bu çözüm de başarısızlığa uğrarsa... düşünmek bile istemiyorum.
Inline assembly
Evet heycan dorukta. Bu sefer vs60 var bir de ben varım...
işte test 1, xor işlemleri ile yapılan swap işlemi ( Not: bu kod main içinde tanımlanmış ama swap fonksyonu içerisinen alınabilir, testleri yapmak için bu şekilde yazdım) :
#include
int main(void)
{
int a = 3, b = 5;
int i;
for( i = 0; i < 100001; i++ ){
__asm{
mov eax, [a]
mov ebx, [b]
xor eax, ebx
xor ebx, eax
xor eax, ebx
mov [a], eax
mov [b], ebx
}
}
return 0;
}
Gördüğünüz gibi asm kodu visual studio 6.0 içinde main içinde duruyor. şimdi bakalım sonuca:
Profile: Function timing, sorted by time
Date: Sat Jan 13 12:50:05 2007
Program Statistics
------------------
Command line at 2007 Jan 13 12:50: "D:\ITU\c++\fib\Debug\swap"
Total time: 1,702 millisecond
Time outside of functions: 1,112 millisecond
Call depth: 1
Total functions: 1
Total hits: 1
Function coverage: 100,0%
Overhead Calculated 3
Overhead Average 3
Module Statistics for swap.exe
------------------------------
Time in module: 0,589 millisecond
Percent of time in module: 100,0%
Functions in module: 1
Hits in module: 1
Module function coverage: 100,0%
Func Func+Child Hit
Time % Time % Count Function
---------------------------------------------------------
0,589 100,0 0,589 100,0 1 _main (swap.obj)
Evetttt, işte bu mudur? budur dedirten sonuç kendini gösterdi!!! 0.589 milisaniye şu ana kadar elde edilen en iyi süre. Şimdi biraz sevinç duyuyorum ama daha herşey bitmedi diğer kodu da bu şekilde yazıp sonuçları karşılaştırmam gerek.
işte temp kullanılarak gerçekleştirilen swap işleminin inline assembly li hali:
#include
int main(void)
{
int a = 3, b = 5;
int i,temp;
for( i = 0; i < 100001; i++ ){
__asm{
mov eax, [a]
mov [temp], eax ; a nin degeri temp de
mov ebx, [b]
mov [a], ebx ; b nin degeri a da
mov eax, [temp]
mov [b], eax ;temp in degeri b de
}
}
return 0;
}
ve sonuç geliyor:
Profile: Function timing, sorted by time
Date: Sat Jan 13 12:56:28 2007
Program Statistics
------------------
Command line at 2007 Jan 13 12:56: "D:\ITU\c++\fib\Debug\swap"
Total time: 21,834 millisecond
Time outside of functions: 21,197 millisecond
Call depth: 1
Total functions: 1
Total hits: 1
Function coverage: 100,0%
Overhead Calculated 3
Overhead Average 3
Module Statistics for swap.exe
------------------------------
Time in module: 0,637 millisecond
Percent of time in module: 100,0%
Functions in module: 1
Hits in module: 1
Module function coverage: 100,0%
Func Func+Child Hit
Time % Time % Count Function
---------------------------------------------------------
0,637 100,0 0,637 100,0 1 _main (swap.obj)
Evet en sonunda istediğim sonuç... 0.637 milisaniye . Biraz acımasız davrandım ikinci swap a kabul ediyorum ama en iyiye ulaşmak kolay olmuyor tabi :))
Dahası var...
inline assembly kullanarak temp i de atabilirz! işte 3. yol:
#include
int main(void)
{
int a = 3, b = 5;
int i;
for( i = 0; i < 100001; i++ ){
__asm{
mov eax, [a]
mov ebx, [b]
mov [a], ebx ; b nin degeri a da
mov [b], eax ; a nin degeri b de
}
}
return 0;
}
ve işte en kısası şimdi geliyorrrr :)
Profile: Function timing, sorted by time
Date: Sat Jan 13 13:00:59 2007
Program Statistics
------------------
Command line at 2007 Jan 13 13:00: "D:\ITU\c++\fib\Debug\swap"
Total time: 1,597 millisecond
Time outside of functions: 1,095 millisecond
Call depth: 1
Total functions: 1
Total hits: 1
Function coverage: 100,0%
Overhead Calculated 4
Overhead Average 4
Module Statistics for swap.exe
------------------------------
Time in module: 0,501 millisecond
Percent of time in module: 100,0%
Functions in module: 1
Hits in module: 1
Module function coverage: 100,0%
Func Func+Child Hit
Time % Time % Count Function
---------------------------------------------------------
0,501 100,0 0,501 100,0 1 _main (swap.obj)
Yani bu yazıdan çıkaracağımız pek çok sonuç var, ama en önemlisi vazgeçememek bana sorarsanız...
Sonuç olarak gelmek istediğim, asıl anlatmak istediğin noktaya gelemedim aslında, yazımın amacı kodu okunabilir yapmaktı. Bu konu hakkında bir cümleyle şunu söyleyebilirim ki: eğer elinizde daha efektif bir kod varsa, ve bu kodun okunabilirliği diğer algoritmalara göre daha kötüyse, o kodu, isminden görevinin anlaşılacağı bir fonksyon içerisine gömmek ( tek satır olsa dahi kodunuz) ve programınızı yazarken o koda ihtiyacınız olduğu yerde yazdığınız fonksyonu çağırmaktır. Fonskyonun ismini güzelce belirlerseniz, kodunuzu okuyanın fonksyon içerisinde yazdığınız kodu okuması gerekmeyecektir. Black box olara düşünülebilir fonksyonunuz.
Bir başka önemli nokta da, burada kodu zamanlama bakımından değerlendirdik. Günümüz bilgisayarlarında bellek sorunu olmamaktadır. ANCAK, gömülü sistemlerde, gerçek zaman sistemlerinde ciddi bellek kısıtlamaları vardır. Bu durumda 4 byte lık bir temp değişkenini bile kullanmak istemeyebilirsiniz. Bu durumda xor ile swap işlemi yapmak gerçekten işinize gelebilir. Kodu da büyük ihtimalle assembly ile yazacağınız için bu yöntem daha efektif olacaktır.
Yazı biraz uzadı ama ben yazarken gerçtekten keyif aldım, umarım sizde sıkılmamışsınızdır. Sonraki yazılarımda görüşmek dileğiyle...
Saturday, December 02, 2006
Monday, November 27, 2006
Normalizasyon
Bu yazim da siz degerli okurlarima veritabani normalizasyonu hakkinda bildikleri mi aktarmaya calisacagim :) Fikir babasi Tonguç abi ye ve yazimi yazarken kaynaklarini kullandiğım Turgut Uyar hocama tesekkurlerimi sunuyorum oncelikle:)
Normalizasyonun bilinçli bir şekilde yapılabilmesi için işlevsel bağımlılık kavramının anlaşılması gerekteğinden öncelikle bu konuya değiniyoruz:
İşlevsel bağımlılık:
Z bir kümeyse, A ve B bu kümenin iki alt kümesi ise, A nın her elemanı için B de yalnız ve yalnız bir eleman karşılık düşmesi A nın B yi işlevsel olarak belirlemesi demektir.
Her işlevsel bağımlılık bir bütünlük kısıtlamasıdır çünkü A ve B nin bir arada bulunması anlamlıdır.
İşlevsel bağımlılığı açıklamak için aşağıda ki tabloyu göz önüne alalım:

Tabloda yer alan varsayımı inceleyecek olursak tablo da yer alan COUNTRY ( COU ) alanının LANGUAGE ( LANG ) alanını işlevsel gerektirdiğini görürüz. Bunun sebebi tablonun tasarimini yaparken kabul ettiğimiz koşuldur. Her film çevrildiği ülkenin dilin de çekildiğine göre her ülkeye yalnız bir dil karşılık düşürülmektedir.
Bunun tersi doğru değildir: Her dil e bir ülke karşı düşürülmemiştir örneğin EN ( english ) diline hem UK ( United Kingdom ) hem de US ( Seattle :p ) karşı düşürülmüştür. Bu yüzden LAN COU yu işlevsel gerektiriyor diyemiyoruz.
Açıklayıcı olması için bir örnek daha vermek istiyorum: Tablo da yer alan ACTORID ve NAME alanları birbirlerini karşılıklı işlevsel gerektirmektedirler. Buna göre her ACTORID ye karşılık yalnız bir NAME ve her NAME e karşılık yalnız bir ACTORID vardır.
İşlevsel bağımlılıkların yalnızca birer alan arasında olması diye bir zorunluluk yoktur. Örneğin: MOVIEID ve ACTORID ikisi birlikte ORD ( ORDER ) alanını işlevsel belirler. Burada ORD alanı aktörün filmde ki sırasını belirlemektedir. Bir film de birden fazla aktör olduğundan sadece MOVIEID alanı ORD alanını işlevsel olarak bağlayamaz çünkü böyle olsaydı bir MOVIEID ye karşılık sadece bir ORD alanı olması gerekir ki tabloyu inceleyecek olursak 70 id li movie ye karşılık ORD alanın da 2 farklı değer vardır. Ama MOVIEID ve ACTORID birlikte kullanıldığında tabloda karşılığı olan yalnız 1 ORD değeri olacaktır.
İndirgenemez küme: Bir S bağıntısında ( tablosunda ) yer alan bütün işlevsel bağımlılıkların kümesine T diyelim. T nin özelliği olabildiğince az eleman içermesi ( tabloda ki birbirine bağımlı sütunların mümkün olduğunca az tutulması ) ve S ana kümesinde ki her işlevsel bağımlılığın T kümesinden türetilebilmesidir. ( Yani tabloda ki veri tutarlılığı bütünlüğü bozulmasın).
Normalizasyon:
Burada değinmek istediğim normalizasyon türleri 1NF, 2NF, 3NF ve BCNF dir.
Her NF ( normal form ) bir öncekinin kapsamını daraltmaktadır.
1NF de nitelikler bölünemez. Bütün veriler bir tek tablo da yer alır. Yukarı da şeklini gördüğünüz tablo yapısı 1NF dir, kaydı tutulmak istenen her veri tabloya bir satır olarak girer. 1NF yapısı çoğu zaman tercih edilmez. Bu form da yer alan sorunlara bakarsak:
1) Bir filmin hangi ülkede çekildiğini biliyoruz ama film de oynayan bir oyuncu bilmediğimiz için yukardaki tablomuzda ülke bilgisini de saklayamıyoruz. ( veri ekleme sorunu )
2) Bir film de oynayan bir oyuncuyu silmek istiyoruz ancak tabloda film hakkında verisi olan tek satır bu ise, satır silindiği zaman film hakkında ki diğer bilgilerde kaybolmuş olacak. ( örn: filmin ülkesi, dili .. ) ( veri silme sorunu )
3) Bir kayıdı güncellemek istediğimiz de tabloda bulunan birden fazla kayıdı güncellemek zorunda kalabiliriz. Örneğin bir filmin ülkesi değiştirilmek istenirse, o filme ait kaç satır varsa hepsinde aynı değişikliği yapmamız gerekecek! ( güncelleme sorunu )
Bu sorunları engellemek için 2NF forma geçilebilir. 2NF form da anahtar olmayan her nitelik birincil anahtara bağlı olmak zorundadır:
Yukardaki tablodan inceleyecek olursak:
Ne demiştik; anahtar olmayan alanlar birincil anahtara bağlı olsunlar.
R1 tablosuna bakacak olursak MOVIEID alanı birincil anahtar, TITLE, COU ve LANG alanları birincil anahtara bağlı alanlardır. Burada MOVIED nin birincil anahtar seçilmesinin sebebi tabloda ki bir satırı tek başına temsil edebilmesidir. TITLE alanı birincil anahtar olamazdı çünkü aynı isimde filmler tabloda yer alabilir. Bu yapıda birincil anahtar olmayan alanların bir birincil anahtara bağlanması yeterlidir.
Bu yapı da ayrımı yaparken sadece bakacağımız koşul anahtar olmayan alanların birincil anahtara bağlı olmasıdır. Başka ek birşey yapılmaz. örneğin LANG alanı birincil anahtar dışında COU alanına da bağlıdır ancak bu durum göz ardı edilir.
R3 tablosunda ActorID ve NAME alanları ayrılmıştır ve ACTORID birincil anahtardır. Tablolar arası ilişkiyi kaybetmemek için R4 tablosu oluşturulmuştur. Burada amaç foreign key dediğimiz yapıyla R1 ve R3 tabloları arasında ki ilişkiyi sağlamaktır.
Bu yapının da ekleme silme ve güncelleme sorunları devam etmekdir.
3NF formda ise yapılması gereken şey bir alanın yalnız ve yalnız birincil anahtara bağlı olması başka hiçbir alana bağlı olmaması gereğidir. Bu durumda 2NF de bulunan LAN alanının R1 tablosundan çıkarılması gerekecektir. Çünkü LAN alanı hem MOVIEID hem COU ya bağlı olamaz. Tablonun yeni hali:

BCNF formu ise benim tam incelemediğim bir konudur:) Bilenler varsa comment lerse sevinirim her beraber öğrenmiş oluruz.
Sonra ki yazılarımda görüşmek dileğiyle...
Normalizasyonun bilinçli bir şekilde yapılabilmesi için işlevsel bağımlılık kavramının anlaşılması gerekteğinden öncelikle bu konuya değiniyoruz:
İşlevsel bağımlılık:
Z bir kümeyse, A ve B bu kümenin iki alt kümesi ise, A nın her elemanı için B de yalnız ve yalnız bir eleman karşılık düşmesi A nın B yi işlevsel olarak belirlemesi demektir.
Her işlevsel bağımlılık bir bütünlük kısıtlamasıdır çünkü A ve B nin bir arada bulunması anlamlıdır.
İşlevsel bağımlılığı açıklamak için aşağıda ki tabloyu göz önüne alalım:
Tabloda yer alan varsayımı inceleyecek olursak tablo da yer alan COUNTRY ( COU ) alanının LANGUAGE ( LANG ) alanını işlevsel gerektirdiğini görürüz. Bunun sebebi tablonun tasarimini yaparken kabul ettiğimiz koşuldur. Her film çevrildiği ülkenin dilin de çekildiğine göre her ülkeye yalnız bir dil karşılık düşürülmektedir.
Bunun tersi doğru değildir: Her dil e bir ülke karşı düşürülmemiştir örneğin EN ( english ) diline hem UK ( United Kingdom ) hem de US ( Seattle :p ) karşı düşürülmüştür. Bu yüzden LAN COU yu işlevsel gerektiriyor diyemiyoruz.
Açıklayıcı olması için bir örnek daha vermek istiyorum: Tablo da yer alan ACTORID ve NAME alanları birbirlerini karşılıklı işlevsel gerektirmektedirler. Buna göre her ACTORID ye karşılık yalnız bir NAME ve her NAME e karşılık yalnız bir ACTORID vardır.
İşlevsel bağımlılıkların yalnızca birer alan arasında olması diye bir zorunluluk yoktur. Örneğin: MOVIEID ve ACTORID ikisi birlikte ORD ( ORDER ) alanını işlevsel belirler. Burada ORD alanı aktörün filmde ki sırasını belirlemektedir. Bir film de birden fazla aktör olduğundan sadece MOVIEID alanı ORD alanını işlevsel olarak bağlayamaz çünkü böyle olsaydı bir MOVIEID ye karşılık sadece bir ORD alanı olması gerekir ki tabloyu inceleyecek olursak 70 id li movie ye karşılık ORD alanın da 2 farklı değer vardır. Ama MOVIEID ve ACTORID birlikte kullanıldığında tabloda karşılığı olan yalnız 1 ORD değeri olacaktır.
İndirgenemez küme: Bir S bağıntısında ( tablosunda ) yer alan bütün işlevsel bağımlılıkların kümesine T diyelim. T nin özelliği olabildiğince az eleman içermesi ( tabloda ki birbirine bağımlı sütunların mümkün olduğunca az tutulması ) ve S ana kümesinde ki her işlevsel bağımlılığın T kümesinden türetilebilmesidir. ( Yani tabloda ki veri tutarlılığı bütünlüğü bozulmasın).
Normalizasyon:
Burada değinmek istediğim normalizasyon türleri 1NF, 2NF, 3NF ve BCNF dir.
Her NF ( normal form ) bir öncekinin kapsamını daraltmaktadır.
1NF de nitelikler bölünemez. Bütün veriler bir tek tablo da yer alır. Yukarı da şeklini gördüğünüz tablo yapısı 1NF dir, kaydı tutulmak istenen her veri tabloya bir satır olarak girer. 1NF yapısı çoğu zaman tercih edilmez. Bu form da yer alan sorunlara bakarsak:
1) Bir filmin hangi ülkede çekildiğini biliyoruz ama film de oynayan bir oyuncu bilmediğimiz için yukardaki tablomuzda ülke bilgisini de saklayamıyoruz. ( veri ekleme sorunu )
2) Bir film de oynayan bir oyuncuyu silmek istiyoruz ancak tabloda film hakkında verisi olan tek satır bu ise, satır silindiği zaman film hakkında ki diğer bilgilerde kaybolmuş olacak. ( örn: filmin ülkesi, dili .. ) ( veri silme sorunu )
3) Bir kayıdı güncellemek istediğimiz de tabloda bulunan birden fazla kayıdı güncellemek zorunda kalabiliriz. Örneğin bir filmin ülkesi değiştirilmek istenirse, o filme ait kaç satır varsa hepsinde aynı değişikliği yapmamız gerekecek! ( güncelleme sorunu )
Bu sorunları engellemek için 2NF forma geçilebilir. 2NF form da anahtar olmayan her nitelik birincil anahtara bağlı olmak zorundadır:
Ne demiştik; anahtar olmayan alanlar birincil anahtara bağlı olsunlar.
R1 tablosuna bakacak olursak MOVIEID alanı birincil anahtar, TITLE, COU ve LANG alanları birincil anahtara bağlı alanlardır. Burada MOVIED nin birincil anahtar seçilmesinin sebebi tabloda ki bir satırı tek başına temsil edebilmesidir. TITLE alanı birincil anahtar olamazdı çünkü aynı isimde filmler tabloda yer alabilir. Bu yapıda birincil anahtar olmayan alanların bir birincil anahtara bağlanması yeterlidir.
Bu yapı da ayrımı yaparken sadece bakacağımız koşul anahtar olmayan alanların birincil anahtara bağlı olmasıdır. Başka ek birşey yapılmaz. örneğin LANG alanı birincil anahtar dışında COU alanına da bağlıdır ancak bu durum göz ardı edilir.
R3 tablosunda ActorID ve NAME alanları ayrılmıştır ve ACTORID birincil anahtardır. Tablolar arası ilişkiyi kaybetmemek için R4 tablosu oluşturulmuştur. Burada amaç foreign key dediğimiz yapıyla R1 ve R3 tabloları arasında ki ilişkiyi sağlamaktır.
Bu yapının da ekleme silme ve güncelleme sorunları devam etmekdir.
3NF formda ise yapılması gereken şey bir alanın yalnız ve yalnız birincil anahtara bağlı olması başka hiçbir alana bağlı olmaması gereğidir. Bu durumda 2NF de bulunan LAN alanının R1 tablosundan çıkarılması gerekecektir. Çünkü LAN alanı hem MOVIEID hem COU ya bağlı olamaz. Tablonun yeni hali:
BCNF formu ise benim tam incelemediğim bir konudur:) Bilenler varsa comment lerse sevinirim her beraber öğrenmiş oluruz.
Sonra ki yazılarımda görüşmek dileğiyle...
Saturday, November 18, 2006
Interviewing with Microsoft ( sde, sdet )
In this post, i write about the interviewing with microsoft. i write this post in english because of internets search results :)
The adventure starts with the sending a resume to hr. Resume should be good enough for passing to next stage. it should clearly identify your skills.
If hr likes your resume, then an email message arrives to your mail box, you feel excited at this stage:) mail tells you, you have a phone call with hr about two days and also they give you to exact date.
You wait until they call you. on the phone, Hr asks you some questions. These are genereally the basic questions for testing your knowledge. You should think a bit then answer the questions. a few questions which they asked to me:
1) how can you define a character pointer named foo
my answer: char * foo; // :))))
2) How can you describe best code
my answer: i dont describe security, easy to read etc. i simply say it should be well documented. because i thought other topics are discussed so much in every where and generally all people knows that a code must be secure or maintanable...
i was asked about 10 questions in the phone, and after 1 week, there was another mail in my inbox:) they said they came to Turkiye and wanted to interview with me face to face. They then sent lots of mail messages for giving info. and sources. i studied lot of things like OS's kernels, low level c , software testing methods etc...
In the interview day, i was a little excited but i pretended to be relax:) i was meeting with 5 people who are testers, developers and hr. it continued about 4.5 hours. they asked me lots of questions. they dont ask only about coding, but also about design. for instances i was asked for designing structures.
code questions are about data structres and algorithms. converting a hexa to decimal, designing a data structures etc.
After a long day, i felt tired and went back to my home, then we were waiting again until they told us the results of interview.
It was a nice day for me, different experience. Also maybe you wonder my result:) i accepted to SDE in USA! now i am waiting the next stages, offer letters another exciting phone call etc..
The adventure starts with the sending a resume to hr. Resume should be good enough for passing to next stage. it should clearly identify your skills.
If hr likes your resume, then an email message arrives to your mail box, you feel excited at this stage:) mail tells you, you have a phone call with hr about two days and also they give you to exact date.
You wait until they call you. on the phone, Hr asks you some questions. These are genereally the basic questions for testing your knowledge. You should think a bit then answer the questions. a few questions which they asked to me:
1) how can you define a character pointer named foo
my answer: char * foo; // :))))
2) How can you describe best code
my answer: i dont describe security, easy to read etc. i simply say it should be well documented. because i thought other topics are discussed so much in every where and generally all people knows that a code must be secure or maintanable...
i was asked about 10 questions in the phone, and after 1 week, there was another mail in my inbox:) they said they came to Turkiye and wanted to interview with me face to face. They then sent lots of mail messages for giving info. and sources. i studied lot of things like OS's kernels, low level c , software testing methods etc...
In the interview day, i was a little excited but i pretended to be relax:) i was meeting with 5 people who are testers, developers and hr. it continued about 4.5 hours. they asked me lots of questions. they dont ask only about coding, but also about design. for instances i was asked for designing structures.
code questions are about data structres and algorithms. converting a hexa to decimal, designing a data structures etc.
After a long day, i felt tired and went back to my home, then we were waiting again until they told us the results of interview.
It was a nice day for me, different experience. Also maybe you wonder my result:) i accepted to SDE in USA! now i am waiting the next stages, offer letters another exciting phone call etc..
Monday, November 13, 2006
Let's Make It Faster...
Bu yazimda zaten hızlı olan bir seyi daha hızlı nasıl yapabiliriz onu gostericem :)
1. yol C dilinde asm komutları yazalım.
include
int main(){
int base, power ,result;
printf("us ve power degerleri:");
scanf("%d %d",&base,&power );
asm(
"movl %1, %%ebx\n\t" //base degiskeni ebx saklayıcısında
"movl %2, %%ecx\n\t" //power degiskeni ecx saklayıcısında"
"xorl %%edx, %%edx\n\t" //edx saklayıcısının içeri sıfırlandı çarpma işlemi için.
"movl $1, %%eax\n\t" //sonuc eax saklayıcısında tutulsun, baslangic degeri 1
"back:\n\t"
"cmp $0, %%ecx\n\t" //power == 0 mı ?
"je bitir\n\t" //evet ise dongu biter
"mul %%ebx\n\t" //degil ise base degiskeni ile sonucu carp ve sonuca ata
"decl %%ecx\n\t" //power ı 1 azalt
"jmp back\n" //donguye devam et, back e dallan
"bitir:\n\t" //dongu sonu
:"=a"(result) //result degiskeni eax saklayıcısından programa geri donecek
:"g"(base),"g"(power) //giris parametreleri base ve power degiskenleri
:"%ebx","%ecx","%edx" //asm blogunda degeri degisen saklayıcılar
);
printf("sonuc: %d\n",result);
return 0;
}
Program da goruldugu gibi hiz acisindan kritik olan kod parcasi asm blogu icinde assembly ile yazilmistir. Programci saglamsa cogu zaman derleyicinin urettigi koddan daha hizli olmaktadir:)
ornegin yukarıdaki kodun saf c karsiligi:
#include
int main(){
int base, power ,result;
printf("us ve power degerleri:");
scanf("%d %d",&base,&power );
result = 1;
for( ; power != 0; power--)
result = result * base;
printf("sonuc: %d\n",result);
return 0;
}
Ve bu fonksiyonu derleyip olusan object kodunu reassembler ettigimiz aman karsimiza gelen makine kodu:
lea ecx,[esp+4]
and esp,0xfffffff0
push DWORD PTR [ecx-4]
push ebp
mov ebp,esp
push ecx
sub esp,0x24
mov DWORD PTR [esp],0x0
call 19
lea eax,[ebp-16]
mov DWORD PTR [esp+8],eax
lea eax,[ebp-12]
mov DWORD PTR [esp+4],eax
mov DWORD PTR [esp],0x17
call 33
mov DWORD PTR [ebp-8],0x1
jmp 55
mov edx,DWORD PTR [ebp-12]
mov eax,DWORD PTR [ebp-8]
imul eax,edx
mov DWORD PTR [ebp-8],eax
mov eax,DWORD PTR [ebp-16]
sub eax,0x1
mov DWORD PTR [ebp-16],eax
mov eax,DWORD PTR [ebp-16]
test eax,eax
jne 40
mov eax,DWORD PTR [ebp-8]
mov DWORD PTR [esp+4],eax
mov DWORD PTR [esp],0x1d
call 6b
mov eax,0x0
add esp,0x24
pop ecx
pop ebp
lea esp,[ecx-4]
ret
Görüldüğü gibi makine kodunu benim yazdığım kodla karşılaştırmamız zor, çünkü ben c ve assemblyi karıştırdım, peki benim karıştırılmış kodumun object kodunu reassebler edersem ne görücem:
lea ecx,[esp+4]
and esp,0xfffffff0
push DWORD PTR [ecx-4]
push ebp
mov ebp,esp
push esi
push ebx
push ecx
sub esp,0x1c
mov DWORD PTR [esp],0x0
call 1b
lea eax,[ebp-24]
mov DWORD PTR [esp+8],eax
lea eax,[ebp-20]
mov DWORD PTR [esp+4],eax
mov DWORD PTR [esp],0x17
call 35
mov esi,DWORD PTR [ebp-20]
mov eax,DWORD PTR [ebp-24]
mov ebx,esi
mov ecx,eax
xor edx,edx
mov eax,0x1
0000004a:
cmp ecx,0x0
je 54
mul ebx
dec ecx
jmp 4a
00000054:
mov DWORD PTR [ebp-16],eax
mov eax,DWORD PTR [ebp-16]
mov DWORD PTR [esp+4],eax
mov DWORD PTR [esp],0x1d
call 66
mov eax,0x0
add esp,0x1c
pop ecx
pop ebx
pop esi
pop ebp
lea esp,[ecx-4]
ret
anlaşılması kolay olsun diye satır numaraları ve byte code ları çıkarıp sadece assembly kodlarını koydum. Bu iki kodu karsilastirirsak gozuken o ki, benim yazdigim kod, derleyicinin urettigi koddan sadece 4 byte daha az :)) derleyicinin kodu 0x7c ye kadar giderken benim yazdığım kod 0x79 a kadar gitti. Aslında daha dikkatli asm bloğu ile bu farkı açabiliriz, ancak benim değinmek istedigim nokta iyi bir programcı daima compiler dan daha iyi kod yazabilir. Tabi bunu gerektirdigi noktalarda kullanmak gerekir. Tutupta butun kodu asm ile yazmak kotu bir yaklasimdir. Cunku bu adress binding dedigimiz, sembollerin adreslere dönüştürme işleminin erken gerçekleşmesine neden olur. Ancak hız kritik ve bellek kapasitesinin az olduğu uygulamalarda yukardaki yaklaşım önemlidir....
2.yol asm içinde C kutuphane fonksiyonlarının çağrılmasıdır. Bu konu ile ilgili örnekleri daha sonra verebilirim talep olursa:) ancak temek fikir ; çağrılacak C fonksiyonları asm kodunda extern olarak belirtilir. Böylece derleyici asm kodunu derlerken hata üretmez ve oluşturduğu object kodunun sembol tablosuna "imported symbol" olarak bu fonksiyon çağrısını ekler. Daha sonra linker da object kodunu C kutuphanesi ile link ederiz ve en son yürütülebilir dosya elimizde oluşur.
C fonksiyonlarını asm içinden çağırmak için gerekli olan bir önemli husus C nin calling conventions dedigimiz çağırma kurallarına uymamızdır. Parametre aktarımı yığın üzerinden olur ve fonksiyona aktarılacak parametreler, parametre listesine gore sagdan sola dogru yığına atılırlar.
Böylece bir yazımında sonuna gelmiş bulunmaktayım. Yeni yeni yazılarla karşınızda olmak dileğiyle şimdilik hoşçakalın :)))
1. yol C dilinde asm komutları yazalım.
include
int main(){
int base, power ,result;
printf("us ve power degerleri:");
scanf("%d %d",&base,&power );
asm(
"movl %1, %%ebx\n\t" //base degiskeni ebx saklayıcısında
"movl %2, %%ecx\n\t" //power degiskeni ecx saklayıcısında"
"xorl %%edx, %%edx\n\t" //edx saklayıcısının içeri sıfırlandı çarpma işlemi için.
"movl $1, %%eax\n\t" //sonuc eax saklayıcısında tutulsun, baslangic degeri 1
"back:\n\t"
"cmp $0, %%ecx\n\t" //power == 0 mı ?
"je bitir\n\t" //evet ise dongu biter
"mul %%ebx\n\t" //degil ise base degiskeni ile sonucu carp ve sonuca ata
"decl %%ecx\n\t" //power ı 1 azalt
"jmp back\n" //donguye devam et, back e dallan
"bitir:\n\t" //dongu sonu
:"=a"(result) //result degiskeni eax saklayıcısından programa geri donecek
:"g"(base),"g"(power) //giris parametreleri base ve power degiskenleri
:"%ebx","%ecx","%edx" //asm blogunda degeri degisen saklayıcılar
);
printf("sonuc: %d\n",result);
return 0;
}
Program da goruldugu gibi hiz acisindan kritik olan kod parcasi asm blogu icinde assembly ile yazilmistir. Programci saglamsa cogu zaman derleyicinin urettigi koddan daha hizli olmaktadir:)
ornegin yukarıdaki kodun saf c karsiligi:
#include
int main(){
int base, power ,result;
printf("us ve power degerleri:");
scanf("%d %d",&base,&power );
result = 1;
for( ; power != 0; power--)
result = result * base;
printf("sonuc: %d\n",result);
return 0;
}
Ve bu fonksiyonu derleyip olusan object kodunu reassembler ettigimiz aman karsimiza gelen makine kodu:
lea ecx,[esp+4]
and esp,0xfffffff0
push DWORD PTR [ecx-4]
push ebp
mov ebp,esp
push ecx
sub esp,0x24
mov DWORD PTR [esp],0x0
call 19
lea eax,[ebp-16]
mov DWORD PTR [esp+8],eax
lea eax,[ebp-12]
mov DWORD PTR [esp+4],eax
mov DWORD PTR [esp],0x17
call 33
mov DWORD PTR [ebp-8],0x1
jmp 55
mov edx,DWORD PTR [ebp-12]
mov eax,DWORD PTR [ebp-8]
imul eax,edx
mov DWORD PTR [ebp-8],eax
mov eax,DWORD PTR [ebp-16]
sub eax,0x1
mov DWORD PTR [ebp-16],eax
mov eax,DWORD PTR [ebp-16]
test eax,eax
jne 40
mov eax,DWORD PTR [ebp-8]
mov DWORD PTR [esp+4],eax
mov DWORD PTR [esp],0x1d
call 6b
mov eax,0x0
add esp,0x24
pop ecx
pop ebp
lea esp,[ecx-4]
ret
Görüldüğü gibi makine kodunu benim yazdığım kodla karşılaştırmamız zor, çünkü ben c ve assemblyi karıştırdım, peki benim karıştırılmış kodumun object kodunu reassebler edersem ne görücem:
lea ecx,[esp+4]
and esp,0xfffffff0
push DWORD PTR [ecx-4]
push ebp
mov ebp,esp
push esi
push ebx
push ecx
sub esp,0x1c
mov DWORD PTR [esp],0x0
call 1b
lea eax,[ebp-24]
mov DWORD PTR [esp+8],eax
lea eax,[ebp-20]
mov DWORD PTR [esp+4],eax
mov DWORD PTR [esp],0x17
call 35
mov esi,DWORD PTR [ebp-20]
mov eax,DWORD PTR [ebp-24]
mov ebx,esi
mov ecx,eax
xor edx,edx
mov eax,0x1
0000004a
cmp ecx,0x0
je 54
mul ebx
dec ecx
jmp 4a
00000054
mov DWORD PTR [ebp-16],eax
mov eax,DWORD PTR [ebp-16]
mov DWORD PTR [esp+4],eax
mov DWORD PTR [esp],0x1d
call 66
mov eax,0x0
add esp,0x1c
pop ecx
pop ebx
pop esi
pop ebp
lea esp,[ecx-4]
ret
anlaşılması kolay olsun diye satır numaraları ve byte code ları çıkarıp sadece assembly kodlarını koydum. Bu iki kodu karsilastirirsak gozuken o ki, benim yazdigim kod, derleyicinin urettigi koddan sadece 4 byte daha az :)) derleyicinin kodu 0x7c ye kadar giderken benim yazdığım kod 0x79 a kadar gitti. Aslında daha dikkatli asm bloğu ile bu farkı açabiliriz, ancak benim değinmek istedigim nokta iyi bir programcı daima compiler dan daha iyi kod yazabilir. Tabi bunu gerektirdigi noktalarda kullanmak gerekir. Tutupta butun kodu asm ile yazmak kotu bir yaklasimdir. Cunku bu adress binding dedigimiz, sembollerin adreslere dönüştürme işleminin erken gerçekleşmesine neden olur. Ancak hız kritik ve bellek kapasitesinin az olduğu uygulamalarda yukardaki yaklaşım önemlidir....
2.yol asm içinde C kutuphane fonksiyonlarının çağrılmasıdır. Bu konu ile ilgili örnekleri daha sonra verebilirim talep olursa:) ancak temek fikir ; çağrılacak C fonksiyonları asm kodunda extern olarak belirtilir. Böylece derleyici asm kodunu derlerken hata üretmez ve oluşturduğu object kodunun sembol tablosuna "imported symbol" olarak bu fonksiyon çağrısını ekler. Daha sonra linker da object kodunu C kutuphanesi ile link ederiz ve en son yürütülebilir dosya elimizde oluşur.
C fonksiyonlarını asm içinden çağırmak için gerekli olan bir önemli husus C nin calling conventions dedigimiz çağırma kurallarına uymamızdır. Parametre aktarımı yığın üzerinden olur ve fonksiyona aktarılacak parametreler, parametre listesine gore sagdan sola dogru yığına atılırlar.
Böylece bir yazımında sonuna gelmiş bulunmaktayım. Yeni yeni yazılarla karşınızda olmak dileğiyle şimdilik hoşçakalın :)))
Friday, November 10, 2006
RISC vs CISC revisited
Geçenlerde yazdığım RISC ve CISC ile ilgili bir yazıya gelen yorum su sekildeydi
( yorum sahibinden ozur dilerim bir turlu publish edemedim comment i )
"Peki hangi program icin RISC ve CISC bunu da biraz acabilirmisin??"
Yazımda kullanacağimiz uygulamaya göre işlemci türünü seçmeliyiz demiştim. Peki hangi türlerde hangi işlemci türü faydalı olur? Bunu aşağıdaki kriterlere göre incelemek istiyorum
1) BELLEK GEREKSINIMI
Uygulama bellek uzerinde cok islem yapiyorsa, bellegi yogun olarak kullaniyorsa, yada uygulamanin kendisi bellekte cok yer kapliyorsa ( ki bu sayfalama ya (paging) yol açar ) bu durumda işlemcinin belleğe hızlı erişmesi işlerimizi kolaylaştıracaktır. CISC mimarilerde bellek erişim komutları ve bellek üzerinde işlem yapan komutlar RISC lere göre daha gelişmiştir. Bu yüzden bellek gereksinimi yoğun ise CISC ler seçilebilir.
2) Giriş/Çıkış GEREKSİNİMİ
Bir program yazdık, io istegi cok fazla, dosya işlemleri yapiyor, database güncelliyor, dataware house işlemleri yapıyor, dışardan veri geliyor vs. Bu durumda modern sistemler giriş çıkış işlemini CPU üzerinden değil DMA ( direct memory access ) denetleyicisi kullanarak yaparlar. Daha eski bir tasarım CPU kullanarak kesme ile yapılan aktarımdır ancak bu işlemciyi gereksiz meşgul eder. Bunun yerine DMA denetliyicisi belleği veri aktarırken yada bellekten veri okurken CPU kendi içindeki bellek ile ilgili olmayan işlemlerini yürütebilir. Aslında DMA nın çalışması için iki yöntem vardır bunlar i) çevrim çalma ( cycle stealing ) ve ii ) blok aktarımdır ( block transfer ). DMA ile ilgili ayrıntıları bir başka gün ele alırım inş. Ancak burada değinmek istediğim eğer DMA denetliyicisi veri aktarımı yapıyorken CPU kendi iç işlemlerini gerçekleştirebiliyorsa iç register/saklayıcı sayısının fazla olmasını isteriz. Bu durumda RISC mimari daha uygun gözükmektedir.
Fakat DMA nın olmadığı bir sistem de io işlemi için CPU kullanılacağından bu durumda kesin bir şey söylemek mümkün değildir.
3) Interactive / Batch UYGULAMALAR
Bir uygulamanın interactive yada batch çalışmasına bağlı olması da işlemci seçiminde önemlidir. Mesala interactive uygulamalarda yanıt alma süresi önemlidir. RISC mimariler de pipeline ( iş hattı ) kullanılarak işler hızlandırılmış ve paralel hale getirilmiştir.. Bu yüzden interactive kullanım sadece CPU işleri ile ilgili ise RISC işlemci kullanılabilir. Diğer yandan bellek üzerinde çok işlem yapan türden bir uygulama ise CISC mimarisi daha uygundur.
Batch programlar ise genelde bir giriş e karşılık işlenen veriyi çıkışa aktarma şeklinde yürür. veri üzerinde yapılan işlem bellek kullanmayı gerektirecekse CISC seçilebilir. Diğer yandan CPU işleminin ve io işleminin yoğun olması durumu yüksek olacağından RISC mimari bu durumlar da seçilebilir.
RISC ve CISC lerin seçilmesine yönelik bilgi ve öneriler vermeye çalıştım. Burdaki bilgilerin hepsinin doğru olduğunu savunmuyorum. Aslında hepsi kendi görüşümdür.Kaynak belirtemem. Sonraki yazılarda yine beraber olmak dileğiyle :))
( yorum sahibinden ozur dilerim bir turlu publish edemedim comment i )
"Peki hangi program icin RISC ve CISC bunu da biraz acabilirmisin??"
Yazımda kullanacağimiz uygulamaya göre işlemci türünü seçmeliyiz demiştim. Peki hangi türlerde hangi işlemci türü faydalı olur? Bunu aşağıdaki kriterlere göre incelemek istiyorum
1) BELLEK GEREKSINIMI
Uygulama bellek uzerinde cok islem yapiyorsa, bellegi yogun olarak kullaniyorsa, yada uygulamanin kendisi bellekte cok yer kapliyorsa ( ki bu sayfalama ya (paging) yol açar ) bu durumda işlemcinin belleğe hızlı erişmesi işlerimizi kolaylaştıracaktır. CISC mimarilerde bellek erişim komutları ve bellek üzerinde işlem yapan komutlar RISC lere göre daha gelişmiştir. Bu yüzden bellek gereksinimi yoğun ise CISC ler seçilebilir.
2) Giriş/Çıkış GEREKSİNİMİ
Bir program yazdık, io istegi cok fazla, dosya işlemleri yapiyor, database güncelliyor, dataware house işlemleri yapıyor, dışardan veri geliyor vs. Bu durumda modern sistemler giriş çıkış işlemini CPU üzerinden değil DMA ( direct memory access ) denetleyicisi kullanarak yaparlar. Daha eski bir tasarım CPU kullanarak kesme ile yapılan aktarımdır ancak bu işlemciyi gereksiz meşgul eder. Bunun yerine DMA denetliyicisi belleği veri aktarırken yada bellekten veri okurken CPU kendi içindeki bellek ile ilgili olmayan işlemlerini yürütebilir. Aslında DMA nın çalışması için iki yöntem vardır bunlar i) çevrim çalma ( cycle stealing ) ve ii ) blok aktarımdır ( block transfer ). DMA ile ilgili ayrıntıları bir başka gün ele alırım inş. Ancak burada değinmek istediğim eğer DMA denetliyicisi veri aktarımı yapıyorken CPU kendi iç işlemlerini gerçekleştirebiliyorsa iç register/saklayıcı sayısının fazla olmasını isteriz. Bu durumda RISC mimari daha uygun gözükmektedir.
Fakat DMA nın olmadığı bir sistem de io işlemi için CPU kullanılacağından bu durumda kesin bir şey söylemek mümkün değildir.
3) Interactive / Batch UYGULAMALAR
Bir uygulamanın interactive yada batch çalışmasına bağlı olması da işlemci seçiminde önemlidir. Mesala interactive uygulamalarda yanıt alma süresi önemlidir. RISC mimariler de pipeline ( iş hattı ) kullanılarak işler hızlandırılmış ve paralel hale getirilmiştir.. Bu yüzden interactive kullanım sadece CPU işleri ile ilgili ise RISC işlemci kullanılabilir. Diğer yandan bellek üzerinde çok işlem yapan türden bir uygulama ise CISC mimarisi daha uygundur.
Batch programlar ise genelde bir giriş e karşılık işlenen veriyi çıkışa aktarma şeklinde yürür. veri üzerinde yapılan işlem bellek kullanmayı gerektirecekse CISC seçilebilir. Diğer yandan CPU işleminin ve io işleminin yoğun olması durumu yüksek olacağından RISC mimari bu durumlar da seçilebilir.
RISC ve CISC lerin seçilmesine yönelik bilgi ve öneriler vermeye çalıştım. Burdaki bilgilerin hepsinin doğru olduğunu savunmuyorum. Aslında hepsi kendi görüşümdür.Kaynak belirtemem. Sonraki yazılarda yine beraber olmak dileğiyle :))
Sunday, October 22, 2006
Software Testings
Yazılımı yazıyoruz ama testini yapıyor muyuz? Test etmek için kullanılan bir kaç felsefeyi buraya yazmayı uygun gördüm:
Regression Testinglar
Regression testing nedir? Bir yazılım sürecinde yazılımı geliştirdikçe bir yandan da ortaya çıkan hataları düzeltiriz. Bug olarak adlandırdığımız bu hatalar düzeltilmesine rağmen, yazılım geliştikçe yeni modüller eklendikçe yada başka hatalar düzeltikçe tekrara ortaya çıkabilir! Bunun için yazılımın belli anlarında, eskiden düzeltilmiş olan hatalar tekrar test edilmelidir. Eski bugların tekrar ortaya çıkma ihtimaline karşı yazılımı kontrol etmeliyiz. Regression testing bu amacı güder.
Unit Testing
Unit testing denilen test bicimi, yazılımın belirli modüllerini tüm test koşullarıyla test etmektir. Unit testing yazılımı oluşturan bağımsız modüllerin doğru bir şekilde çalıştığını göstermeyi hedefler.
Fakat unit testing yazılımdaki her hatayı bulamaz. çünkü sadece bireysel modülleri kendi başına test eder, bir modülün diğer modül ile olan bağlantısı test edilmez. Bir başka sorun da bir modülü test edebilmek için gerekli olan input sayısının sonsuza gitmesidir. Modüle verilecek giriş sayısı sonsuz olamayacağından unit testing hataların yokluğunu değil hataların varlığını gösterebilir.
Integration Testing
Bireysel modüllerimizi unit testing aşamasından geçirdik ama hayla modüller birlikte çalışırken düzgün çalışırlar mı bilemeyiz. Bunun için integration testing uygularız. Bu test in girişleri modüllerdir. Testin amacı modüllerin birlikte çalıştığını doğrulamakttır. Paylaşılan bellek bölgeleri, IPC ( inter process control ) gibi processlerin ortak kullandıkları yapılar test edilir. Integration testing, unit testingden sonra gelir ve yazılımı system testing için hazırlar. Integration testing yaparken uygulanacak test stratejileri bu testi kategorilere koyar. Bunlar: Big Bang, Top Down, Bottom Up, ve Back bone test stratejileridir.
System Testing
System testing, integration testing den sonraki aşamadır. Integrasyonluğu doğrulanmış modüller birleştirilip en son yazılım ortaya çıkarıldıktan sonra system testing uygulanır ve bu yıkıcı en son testdir. System testing uygularken black-box yaklaşımı kullanılır. Yani kod a bakılmaz inputlar verilir ve sistemin ayakta kalıp kalmadığına bakılır. Alpha ve beta olarak iki fazı vardır.
Acceptence Testing
Buraya kadar olan test metodları yazılımı üreten programcılar ve test takımları tarafından yapılıyordu. Yani yazılım şirketi kendi yazılımını test ediyordu. Acceptence testing de ise kullanıcılar ve diğer üreticler de yazılımı test ederler. Bu yazılım da black-box yaklaşımı ile çalışır.
Özetlersek, bir yazılımı test etmek için gerekli olan en temel testleri soyledik. Tabiki bu testlerden başka daha bir çok test de mevcuttur. Bunlar:
# Functional testing
# User interface testing
# Usability testing
# Compatibility testing
# Model based testing
# Error exit testing
# User help testing
# Security testing
# Capacity testing
# Performance testing
# Sanity testing
# Regression testing
# Reliability testing
# Recovery testing
# Installation testing
# Maintenance testing
olarak sayılabilir. Bir yazılım sürecinde bizim bahsettiğimiz testler şu sırada gerçekleşir.
Unit testing -> integration testing -> system testing -> acceptence testing.
ve regression testing ise her önemli değişiklikte eski hataları test etme biçiminde bütün yazılım sürecinde uygulanır.
Regression Testinglar
Regression testing nedir? Bir yazılım sürecinde yazılımı geliştirdikçe bir yandan da ortaya çıkan hataları düzeltiriz. Bug olarak adlandırdığımız bu hatalar düzeltilmesine rağmen, yazılım geliştikçe yeni modüller eklendikçe yada başka hatalar düzeltikçe tekrara ortaya çıkabilir! Bunun için yazılımın belli anlarında, eskiden düzeltilmiş olan hatalar tekrar test edilmelidir. Eski bugların tekrar ortaya çıkma ihtimaline karşı yazılımı kontrol etmeliyiz. Regression testing bu amacı güder.
Unit Testing
Unit testing denilen test bicimi, yazılımın belirli modüllerini tüm test koşullarıyla test etmektir. Unit testing yazılımı oluşturan bağımsız modüllerin doğru bir şekilde çalıştığını göstermeyi hedefler.
Fakat unit testing yazılımdaki her hatayı bulamaz. çünkü sadece bireysel modülleri kendi başına test eder, bir modülün diğer modül ile olan bağlantısı test edilmez. Bir başka sorun da bir modülü test edebilmek için gerekli olan input sayısının sonsuza gitmesidir. Modüle verilecek giriş sayısı sonsuz olamayacağından unit testing hataların yokluğunu değil hataların varlığını gösterebilir.
Integration Testing
Bireysel modüllerimizi unit testing aşamasından geçirdik ama hayla modüller birlikte çalışırken düzgün çalışırlar mı bilemeyiz. Bunun için integration testing uygularız. Bu test in girişleri modüllerdir. Testin amacı modüllerin birlikte çalıştığını doğrulamakttır. Paylaşılan bellek bölgeleri, IPC ( inter process control ) gibi processlerin ortak kullandıkları yapılar test edilir. Integration testing, unit testingden sonra gelir ve yazılımı system testing için hazırlar. Integration testing yaparken uygulanacak test stratejileri bu testi kategorilere koyar. Bunlar: Big Bang, Top Down, Bottom Up, ve Back bone test stratejileridir.
System Testing
System testing, integration testing den sonraki aşamadır. Integrasyonluğu doğrulanmış modüller birleştirilip en son yazılım ortaya çıkarıldıktan sonra system testing uygulanır ve bu yıkıcı en son testdir. System testing uygularken black-box yaklaşımı kullanılır. Yani kod a bakılmaz inputlar verilir ve sistemin ayakta kalıp kalmadığına bakılır. Alpha ve beta olarak iki fazı vardır.
Acceptence Testing
Buraya kadar olan test metodları yazılımı üreten programcılar ve test takımları tarafından yapılıyordu. Yani yazılım şirketi kendi yazılımını test ediyordu. Acceptence testing de ise kullanıcılar ve diğer üreticler de yazılımı test ederler. Bu yazılım da black-box yaklaşımı ile çalışır.
Özetlersek, bir yazılımı test etmek için gerekli olan en temel testleri soyledik. Tabiki bu testlerden başka daha bir çok test de mevcuttur. Bunlar:
# Functional testing
# User interface testing
# Usability testing
# Compatibility testing
# Model based testing
# Error exit testing
# User help testing
# Security testing
# Capacity testing
# Performance testing
# Sanity testing
# Regression testing
# Reliability testing
# Recovery testing
# Installation testing
# Maintenance testing
olarak sayılabilir. Bir yazılım sürecinde bizim bahsettiğimiz testler şu sırada gerçekleşir.
Unit testing -> integration testing -> system testing -> acceptence testing.
ve regression testing ise her önemli değişiklikte eski hataları test etme biçiminde bütün yazılım sürecinde uygulanır.
Saturday, October 21, 2006
Kernel tipleri
Kernel işletim sisteminin bir parçasıdır. Process scheduling, memory management, thread management gibi management işleri ile uğraşır daha çok. Donanım( hardware ) ile kabuk ( shell ) arasında bağlantı oluşturur. Demek istediğim kullanıcılar direk olarak donanıma erişemezler. sistem çağrılarını kullanırlar. sistem çağrılarını kernele ulaşan fonksyonlar olarak düşünebiliriz.
"Kernel attack" linuxte handle edilemeyen errorleri belirtir. ( %30 ingilizce yazıyorum :) ) bir process te bir hata olduğu zaman eğer bu hata fatal ise kernel attack oluşur.
Günümüzde ki popüler işletim sistemlerine baktığımızda kernel i genel olarak 3 gruba ayırabiliriz ki bu grupların sayısı gerçekte daha fazladır.
1) Monolitik kernel: Tüm kernel kodu tek bir yerde bulunur. Bütün kernel, kernel space de çalışır. Bu kerneller çok yer kaplar ama hızlıdır. Linux gibi işletim sistemlerinde kernele modül eklemek mümkündür ancak bu ekelenen modüllerde kernel space de çalışmaktadır.
2) Mikrokernel: Kernel, kernel space de minumum tutulmuştur. genel olarak process scheduling memory management gibi hayati işleri ele alır. Sisteme modül eklenebilir dışardan. Bu eklenen modüller genel olarak user space te çalışır. Bu yüzden biraz daha yavaş kaçar. Çünkü user space ten OS hizmetleri system call lar aracılığı ile çalıştırılır.
3) Hybrid kernel: Bu da yukardaki iki maddenin karışımıdır. Windows NT nin nasıl bir kernel olduğu meçhuldür :) bu konuda ms de çalışanlarda tam emin değildir. Her nekadar ilk çıktığı sırada mikrokerneldir denildiyse de daha sonraları bu görüş değişti. Şu anda hybrid ve monolitik diyenlere rastlayabilirsiniz....
"Kernel attack" linuxte handle edilemeyen errorleri belirtir. ( %30 ingilizce yazıyorum :) ) bir process te bir hata olduğu zaman eğer bu hata fatal ise kernel attack oluşur.
Günümüzde ki popüler işletim sistemlerine baktığımızda kernel i genel olarak 3 gruba ayırabiliriz ki bu grupların sayısı gerçekte daha fazladır.
1) Monolitik kernel: Tüm kernel kodu tek bir yerde bulunur. Bütün kernel, kernel space de çalışır. Bu kerneller çok yer kaplar ama hızlıdır. Linux gibi işletim sistemlerinde kernele modül eklemek mümkündür ancak bu ekelenen modüllerde kernel space de çalışmaktadır.
2) Mikrokernel: Kernel, kernel space de minumum tutulmuştur. genel olarak process scheduling memory management gibi hayati işleri ele alır. Sisteme modül eklenebilir dışardan. Bu eklenen modüller genel olarak user space te çalışır. Bu yüzden biraz daha yavaş kaçar. Çünkü user space ten OS hizmetleri system call lar aracılığı ile çalıştırılır.
3) Hybrid kernel: Bu da yukardaki iki maddenin karışımıdır. Windows NT nin nasıl bir kernel olduğu meçhuldür :) bu konuda ms de çalışanlarda tam emin değildir. Her nekadar ilk çıktığı sırada mikrokerneldir denildiyse de daha sonraları bu görüş değişti. Şu anda hybrid ve monolitik diyenlere rastlayabilirsiniz....
Sunday, July 23, 2006
Bitirme Projem
Bir yazimda sevdigim bir arkadasim benden projemi anlatmam icin comment birakmisti, bu eksikligi kapatmak amaci ile bu yaziyi sizlere yaziyorum:)
DOGA ESINLI ALGORITMALARLA YUZ URETME...
Bir cinayet olayi oldu, suclu olay yerinde bizim vehbi yi bicaklayarak oldurdu! Suclunun yuzunu bir kac saniyelik goren HAYDAR abimiz olay yerinden kacarak canini zor kurtardi. suclu sehrin karanlik sokaklarinda yeni kurbanlar ariyor...
Haydar abi korkuyor, polis zabit tutmus haydar abi tanik olarak YUZLESME ODASINA aliniyor. peki yuzlesme odasinda ne mi var ? orada bilgisayar dunyasinin en son algoritmalari kullanilarak gelistirilmis olan bir yazilim kendisini kullanacak olan kisiyi bekliyor.
Haydar abi heycanli bir sekilde programa yoneldi ve calistirdi, karsisina gelen menuden bir algoritma secerek hırsız veri tabanindan uretilen ilk populasyonla karsi karsiya geldi...

Haydar abi katile benzetebildigi bir kac yuzu gordu ve isaretledi ardindan next butonuna basarak yeni yuzler uretilmeye baslandi , eger hicbir katili gormeseydi reinit butonuna basip yeni yuzleri karsisina alacakti. Haydar abi next butonuna bastikca kafasinda hayali olan katile daha cok benzeyen yuzleri karsisinda goruyor ve saskinligini polis sefi EMREKNLK dan gizleyemiyordu. emreknlk hemen haydar abi ye bu programda her iterasyonda kullanicinin secmis oldugu yuzlere daha benzer yuzler uretildigini cunku yeni parametrelerin genetik algoritmalarla uretildigini soyledi. Haydar abi bir an olsun rahatlamisti cunku bunun artik seytan icati degil yazilimci icati oldugunu kavrayabilmisti. En sonunda aradigi yuzu bulan haydar abimiz stop butonuna basarak islemleri bitirdi ve katilin robot resmini polis sefi emreknlk ya teslim etti.
Emreknlk robot resmi alarak sehrin karanlik sokaklarinda katilin ardindan dolasmaya basladi, katili kendine bir kurban ararken yakaladi ve hapse atti! katil ummadigi bir anda nasil bu kadar cabuk ele gecirildigini anlayamadi. Polis sefi emreknlk nin ise agzindan su cumleler dokuldu:
- Daha onceden isledigin suclar yuzunden polis veritabanimizda yuzun vardi, o yuzden tanigimiz XXX in senin yuzunu programla uretmesi zor olmadi! Ancak resminin veritabaninda olmamasi halinde de basarili bir sekilde robot resmine yaklasilabilecekti. Program 5 farkli algoritma ile calisir ve ilk populasyon veritabaninda ki resimler kullanilarak rasgele degerler ile uretilir. Ardindan tanigimizin sectigi resimlerin parametreleri kullanilarak genetik algoritmalar ile yeni parametreler hesaplanir ve yeni yuzler veritabanindan bu parametrelere gore uretilir. En sonunda senin resmin ortaya cikar ve ben seni kosebasinda yakalar sonra ...
--- END ---
bir kac test sonucunu sizlere aktarmak istiyorum:
Algoritmalar: ES ( evolutionary stregies ) emreknlk + merve
DE ( differential evolution ) emreknlk
GGA ( generational genetic algorithm ) nildem
SSGA ( steady state genetic algorithm ) nildem
PSO ( particle swarm optimization ) tugba + fatma
DOGA ESINLI ALGORITMALARLA YUZ URETME...
Bir cinayet olayi oldu, suclu olay yerinde bizim vehbi yi bicaklayarak oldurdu! Suclunun yuzunu bir kac saniyelik goren HAYDAR abimiz olay yerinden kacarak canini zor kurtardi. suclu sehrin karanlik sokaklarinda yeni kurbanlar ariyor...
Haydar abi korkuyor, polis zabit tutmus haydar abi tanik olarak YUZLESME ODASINA aliniyor. peki yuzlesme odasinda ne mi var ? orada bilgisayar dunyasinin en son algoritmalari kullanilarak gelistirilmis olan bir yazilim kendisini kullanacak olan kisiyi bekliyor.
Haydar abi heycanli bir sekilde programa yoneldi ve calistirdi, karsisina gelen menuden bir algoritma secerek hırsız veri tabanindan uretilen ilk populasyonla karsi karsiya geldi...

Haydar abi katile benzetebildigi bir kac yuzu gordu ve isaretledi ardindan next butonuna basarak yeni yuzler uretilmeye baslandi , eger hicbir katili gormeseydi reinit butonuna basip yeni yuzleri karsisina alacakti. Haydar abi next butonuna bastikca kafasinda hayali olan katile daha cok benzeyen yuzleri karsisinda goruyor ve saskinligini polis sefi EMREKNLK dan gizleyemiyordu. emreknlk hemen haydar abi ye bu programda her iterasyonda kullanicinin secmis oldugu yuzlere daha benzer yuzler uretildigini cunku yeni parametrelerin genetik algoritmalarla uretildigini soyledi. Haydar abi bir an olsun rahatlamisti cunku bunun artik seytan icati degil yazilimci icati oldugunu kavrayabilmisti. En sonunda aradigi yuzu bulan haydar abimiz stop butonuna basarak islemleri bitirdi ve katilin robot resmini polis sefi emreknlk ya teslim etti.
Emreknlk robot resmi alarak sehrin karanlik sokaklarinda katilin ardindan dolasmaya basladi, katili kendine bir kurban ararken yakaladi ve hapse atti! katil ummadigi bir anda nasil bu kadar cabuk ele gecirildigini anlayamadi. Polis sefi emreknlk nin ise agzindan su cumleler dokuldu:
- Daha onceden isledigin suclar yuzunden polis veritabanimizda yuzun vardi, o yuzden tanigimiz XXX in senin yuzunu programla uretmesi zor olmadi! Ancak resminin veritabaninda olmamasi halinde de basarili bir sekilde robot resmine yaklasilabilecekti. Program 5 farkli algoritma ile calisir ve ilk populasyon veritabaninda ki resimler kullanilarak rasgele degerler ile uretilir. Ardindan tanigimizin sectigi resimlerin parametreleri kullanilarak genetik algoritmalar ile yeni parametreler hesaplanir ve yeni yuzler veritabanindan bu parametrelere gore uretilir. En sonunda senin resmin ortaya cikar ve ben seni kosebasinda yakalar sonra ...
--- END ---
bir kac test sonucunu sizlere aktarmak istiyorum:
Algoritmalar: ES ( evolutionary stregies ) emreknlk + merve
DE ( differential evolution ) emreknlk
GGA ( generational genetic algorithm ) nildem
SSGA ( steady state genetic algorithm ) nildem
PSO ( particle swarm optimization ) tugba + fatma
USA nedir ne değildir hepsi burada:)
Amerika maceramiza baslamadan once asagidaki resmi sizlere gostermek istiyorum...
Çok artist cikmisim yine dimi :)))
YOLCULUK BASLIYOR...
Daha hayatimda ucaga binmemisim bir de tuttum ilk ucak yolculugumu Amerikaya yapiorum.
Istanbul->Paris->Ciccinati mi ne garip bir sehir amerikada ismini unuttum oraya aktarmali uctuk oradan da Seattle a toplam 19 saat havada kaldik basim da ve karnimda agrilarla Allaha sukur sonunda ulasmistik seattle a gecenin 10un da, 24 saat gunesle birlikteydik uyku duzenimiz bozulduysa da ertesi gun uyaninca toparlanmistik...
Iste kaldigimiz otel:
Amerikayi anlatmaya Seattle ile basliyim: Seattle da nufus az, yollar temiz, binalar cok guzel. Seattle in guzel bir sehir oldugunu daha once de duymustuk. Yalniz sokaklar evsiz insanlarla dolu ancak zararsizlar. Seattle da hava genelde yagisliymis ancak biz gittigimizde sadece 1 gun yagdi onun disinda hava cok guzeldi. Seattle gercekten yasanabilecek bir sehir olurdu ama malesef yemek yerken bayagi bir zorluk cektik damak tadi hic bizimkine benzemiyor zaten cin lokantalari dolmus bir cok yer oralar guzel kokmuyor uzak durmaya calistik. Hosuma giden sadece bir meksika yemegi var ismide brutto with tacco mu neydi, resmini sizlere gostereyim :)
Seattle in cok ilginc bir ozelligi inanilmaz bir sey ama her kose de en az 1 starbucks var!!! bir apartmanin icinde 3 tane bile oldugu oluyor, seattle starbucksin dogdugu yermis meger, amam bu kadarda cocuk yapilmaz ki kardesim dedim kendi kendime:) Amerikaliliar zaten ucmus, fast food kulturleri kahve kulturleri bayagi bir gelismis, ancak sokakta ki insalarin yarisi 200 kilo dan fazla! abartmiyorum cidden fazladir yani biz sok olduk arkadaslarla...
Seattle da gozlemledigim diger olaylar ; arac suruculeri yayalara son derece saygili yesil de bile yol veriolar cok guzel bir aliskanlik oyle atliyorum yola herkes duruyor:) Bir de amerikalilar yolda yururken durmadan excuse me diyip diyip duruyorlar hatta bazen adamin biri sana carpacak ilkin excuse me deyip ozur diliyor sonra kolu filan carpio sana o kadar asmislar yani:)
Bizim seattle da bulunma amacimiz ise bir workshop a katilip bitirmem odevimizi sunmaktiii, sunduk iki kere, biri poster sunumuydu digeri ise ppt sunumu, ingilizcem cok ii degilmis ama bayagi bir anlastik konustuk yine de insanlarla. hatta kanada dan yuksek lisans icin teklif bile aldim ama kabul etmeyecegim birakamam guzelim yurdumu:) workshoptan bir goruntu sizlere:
Gelelim donus yolculuguna, eve donerken newyorkta ucagimiz bir gun kalacakti, 6 saat ucup seattle dan newyork a ulastik, o gece tam disari cikip havaalanindan newyork sehir merkezine gidelim dedik ama sonra gec oldugu icin vazgectik ki iiki vazgecmisiz cunku 1bucuk saat surdu sabah gitmemiz newyorka. O gece havalaninda kaldik koltuklarda uyuduk bayagi konforluydu:) sabah 5 bucukta ise newyork a sehir merkezine indik ve oglen 1 e kadar inanilmaz bir sekilde dolastik ayaklarim yara oldu sonra:) empire state i king kongun dustugu binayi gorduk, ozgurluk heykelini uzaktan gorebildik, 11 eylul saldirilarinin oldugu yeri gorduk, newyork cok guzel ama cok kalabalik, heryer isil isildi times meydani basta olmak uzere.
Kisacasi bir haftalik amerika gezimiz yorucu bir sekilde bitti ve geldikten sonra bayagi bir sure uyudum, bence yurdum gibisi yok yine de ...
iste son olarak bogazdan bir manzara sizlere :)
Wednesday, July 19, 2006
Algoritmaların Analizi
Bugun bilgisayar dunyasında bilgisayar programciliği bir yere kadar kendine iş bulabilir. Bilgisayar mühendisinin karşılaşılan sorunlara daha kolay cevap bulabildiğini söyler çoğu kişi. Peki bilgisayar mühendisi problemlere nasıl daha kolay cevap bulabiliyor? bence bunun altinda yaptiği algoritma tasarımları, algoritma analizleri saklı...
Bir graph teorisini bilmeyen programci network programlama işine girerse ne olur? İstemciye gidecek paket belki en sonunda istemciye ulaşır ama network üzerinde en kısa yol algoritması koşmuyorsa yada TSP gibi algoritmalar dikkate alınmadan programlama yapılıyorsa paket gitmesi gerekenden çok sonra istemciye ulaşacaktır. Performansın ise nasıl bir kriter olduğunu söylemeye gerek yoktur herhalde.
Bugun sıkça kullanılan algoritmalardan bir kaçına değinmek istiyorum:
Greedy algoritmaları: Bu algoritmaların temel prensibi algoritmanın üzerinde çalışacağı elemanları bir kritere göre sıralamak ve sıra ile deneyerek en sonunda en optimum çözümü elde etmektir.
Divide and Conquer: Bu algoritmalar genel de ağaç veri yapısı üzerine kurulur ve problemi kendi içerisinde aynı türden daha küçük problemlere bölerek, alt problemerin çözümünden bütün problemin çözümünü elde etme yoluna gider. Rekürsif çağrı yapmaya uygun algoritmalardır.
Dynamic programming: Greedy algoritmaları her probleme optimum çözüm getiremeyebilir. Dinamik programlama da problemin çözümü; kendisinden bir küçük problemin çözümü ile kendi çözümü arasındaki optimumu seçme ve bu şekilde büyüyerek en sondaki problemi çözmeye bağlıdır. En küçük problemden başlayarak en büyük probleme doğru optimum çözümler seçilerek ilerlenir.
NP ( non-deterministic polynomial time ) Problems: Bu problemlerin çözümü tam olarak bulanmasa da kendisine benzeyen ve çözümü bilinen bir problemin çözümünden yola çıkalarak problemi çözme yoluna gidilir. Polinomal zamanda çözülen bir algoritmanın çözümü NP problemi çözecek şekilde değiştirilir.
Yukarıda bahsi geçen algoritmalar ve bahsi geçmeyen algoritmalar bilgisayar bilimlerinin yakından ilgilendiği yıllardır üzerinde çalışılan konulardır. Gerçek problemlere uygun çözümleri bulabilmek için bu algoritmaları ve kullanılan veri yapılarını özümsemek gerektiğine inanıyorum.
Bir graph teorisini bilmeyen programci network programlama işine girerse ne olur? İstemciye gidecek paket belki en sonunda istemciye ulaşır ama network üzerinde en kısa yol algoritması koşmuyorsa yada TSP gibi algoritmalar dikkate alınmadan programlama yapılıyorsa paket gitmesi gerekenden çok sonra istemciye ulaşacaktır. Performansın ise nasıl bir kriter olduğunu söylemeye gerek yoktur herhalde.
Bugun sıkça kullanılan algoritmalardan bir kaçına değinmek istiyorum:
Greedy algoritmaları: Bu algoritmaların temel prensibi algoritmanın üzerinde çalışacağı elemanları bir kritere göre sıralamak ve sıra ile deneyerek en sonunda en optimum çözümü elde etmektir.
Divide and Conquer: Bu algoritmalar genel de ağaç veri yapısı üzerine kurulur ve problemi kendi içerisinde aynı türden daha küçük problemlere bölerek, alt problemerin çözümünden bütün problemin çözümünü elde etme yoluna gider. Rekürsif çağrı yapmaya uygun algoritmalardır.
Dynamic programming: Greedy algoritmaları her probleme optimum çözüm getiremeyebilir. Dinamik programlama da problemin çözümü; kendisinden bir küçük problemin çözümü ile kendi çözümü arasındaki optimumu seçme ve bu şekilde büyüyerek en sondaki problemi çözmeye bağlıdır. En küçük problemden başlayarak en büyük probleme doğru optimum çözümler seçilerek ilerlenir.
NP ( non-deterministic polynomial time ) Problems: Bu problemlerin çözümü tam olarak bulanmasa da kendisine benzeyen ve çözümü bilinen bir problemin çözümünden yola çıkalarak problemi çözme yoluna gidilir. Polinomal zamanda çözülen bir algoritmanın çözümü NP problemi çözecek şekilde değiştirilir.
Yukarıda bahsi geçen algoritmalar ve bahsi geçmeyen algoritmalar bilgisayar bilimlerinin yakından ilgilendiği yıllardır üzerinde çalışılan konulardır. Gerçek problemlere uygun çözümleri bulabilmek için bu algoritmaları ve kullanılan veri yapılarını özümsemek gerektiğine inanıyorum.
CISC - RISC
Complex Instruction Set Computer
Reduced Instruction Set Computer
Bir önceki yazımda Karşılıklı dışlamayı anlatırken arada bir CISC lafı ettiğimi gördüm.
Peki nedir bu CISC ? birde bunun RISC i varmış! Biz mikroişlemci alırken CISC mi alıcaz RISC mi alıcaz yoksa risk mi alıcaz:) risk almamak için CISC ve RISC lerin ne olduğuna biraz değinmek istiyorum.
Bilgisayar tarihinin ilk başlarında RISC işlemciler vardı, bu işlemciler az mikroişlemci komutuna sahipti ( çoğunda < 20 ), çoğunda bellek okuma ve yazma işlemleri dışında bellek üzerinde işlem yapan toplama çıkarma tümleme gibi komutlar yoktu. Herşey mikro işlemcinin içerisinde yapıldığından mikroişlemci içerisinde 100 - 200 belki daha fazla registerlar yerleştirliyordu. Yapılacak işler kısa kısa komutlar halinde yapılabiliyordu ancak bilgisayar yazılımlarının büyümesi RISC de yazılan programların uzun ve karışık olmasına yok açtı ve tahmin edeceğiniz üzere CISC doğdu.
CISC ler üretilirken komut kümeleri geniş tutuldu, bellek üzerinde işlem yapabilen komutları eklediler, bir komut yazarak bellekteki 2 sayıyı toplayabilip başka bir bellek gözüne yazabiliyorduk. RISC lere göre daha az iç register ları vardı ve daha az komutla daha çok iş yapabiliyorduk.
Fakat her güzel şeyin bir bedeli oluyor galiba... CISC mimarisinde ki mikroişlemciler de ki fazla komut sayıları ve karmaşık komut yapıları işlemci içindeki iç yolların da karmaşıklığını arttırmaktaydı, bu ise hem işlemci maliyetini etkiliyordu hem de mikroişlemcinin çabuk ısınmasına yol açıyordu. Üstelik CISC de tasarlanan komutların çoğu da çok sık kullanılmayan komutlar olabiliyordu.
Bütün bu etkenlerden dolayı RISC lere tekrar gün doğmuştu. RISCler için tasarlanan kesişimli pencereler ve KOMUT BORU HATTI ( pipeline) sayesinde RISC işlemcilerin hızı artmıştı.
Bugün ise bilgisayar dünyasında hem RISC hem de CISC mimarisinde ki mikroişlemciler sıkça kullanılmaktadır. ÜZerinde çalışacak programa göre yukarıda belirtilen avantajlar ve dezavantajlara göre CISC yada RISC işlemciler seçilmeli, risk almaktan kaçınılmalıdır...
Reduced Instruction Set Computer
Bir önceki yazımda Karşılıklı dışlamayı anlatırken arada bir CISC lafı ettiğimi gördüm.
Peki nedir bu CISC ? birde bunun RISC i varmış! Biz mikroişlemci alırken CISC mi alıcaz RISC mi alıcaz yoksa risk mi alıcaz:) risk almamak için CISC ve RISC lerin ne olduğuna biraz değinmek istiyorum.
Bilgisayar tarihinin ilk başlarında RISC işlemciler vardı, bu işlemciler az mikroişlemci komutuna sahipti ( çoğunda < 20 ), çoğunda bellek okuma ve yazma işlemleri dışında bellek üzerinde işlem yapan toplama çıkarma tümleme gibi komutlar yoktu. Herşey mikro işlemcinin içerisinde yapıldığından mikroişlemci içerisinde 100 - 200 belki daha fazla registerlar yerleştirliyordu. Yapılacak işler kısa kısa komutlar halinde yapılabiliyordu ancak bilgisayar yazılımlarının büyümesi RISC de yazılan programların uzun ve karışık olmasına yok açtı ve tahmin edeceğiniz üzere CISC doğdu.
CISC ler üretilirken komut kümeleri geniş tutuldu, bellek üzerinde işlem yapabilen komutları eklediler, bir komut yazarak bellekteki 2 sayıyı toplayabilip başka bir bellek gözüne yazabiliyorduk. RISC lere göre daha az iç register ları vardı ve daha az komutla daha çok iş yapabiliyorduk.
Fakat her güzel şeyin bir bedeli oluyor galiba... CISC mimarisinde ki mikroişlemciler de ki fazla komut sayıları ve karmaşık komut yapıları işlemci içindeki iç yolların da karmaşıklığını arttırmaktaydı, bu ise hem işlemci maliyetini etkiliyordu hem de mikroişlemcinin çabuk ısınmasına yol açıyordu. Üstelik CISC de tasarlanan komutların çoğu da çok sık kullanılmayan komutlar olabiliyordu.
Bütün bu etkenlerden dolayı RISC lere tekrar gün doğmuştu. RISCler için tasarlanan kesişimli pencereler ve KOMUT BORU HATTI ( pipeline) sayesinde RISC işlemcilerin hızı artmıştı.
Bugün ise bilgisayar dünyasında hem RISC hem de CISC mimarisinde ki mikroişlemciler sıkça kullanılmaktadır. ÜZerinde çalışacak programa göre yukarıda belirtilen avantajlar ve dezavantajlara göre CISC yada RISC işlemciler seçilmeli, risk almaktan kaçınılmalıdır...
Karşılıklı Dışlama Hakkında Bir Yazı
KARŞILIKLI DIŞLAMA
Bu yazıyı yazmamın sebebi bilgisayar dünyasının çokça kullandığı ama tam olarak ne olduğuda çoğu bilişimci için bilinmeyen bir konuya açıklık getirmeye çalışmaktır. Benimde bilgilerim yeterli olmayabilir o yuzden herşeye inanmayıp araştırmanızı tavsiye ederim;)
"Karşılıklı Dışlama nedir?" sorusunun cevabını şu şekilde özetleyebiliriz: Aynı kaynaklara ( kaynak: RAM, DISK, FILE, EXTERNAL DEVICE etc ) ulaşmak isteyen birden fazla proses olması durumunda bu kaynaklara erişimin kaynak tipine göre paylaşılması ve belli bir anda sadece izin verilen proseslerin bu kaynaklara erişmesinin sağlanmasıdır.
Yukarıdaki tanım biraz karışık gelmiş olabilir. Örnek verelim: Printer paylaşılmayan bir kaynaktır ve karşılıklı dışlama gerektirir bir zaman da sadece bir proses printer ı kullanarak çıkış alabilir.
Dosyalar okuma yapıldığı zaman paylaşılabilir ve okuma için açılan dosyalarda karşılıklı dışlama gerekmez, ancak yazma yapıldığı zaman dosya karşılıklı dışlanmalı ve bir anda bir proses dosyayı elinde tutmalıdır aksi takdirde dosya bütünlüğü tehlikeye girer.
Karşılıklı dışlamayı gerçekleştirmek için bir çok algoritma ortaya atılmıştır. Fakat bir çoğu yetersiz kalmıştır. Örneğin ünlü Banker algoritması kaynak sayısının ve proseslerin sabit olması kısıtı altında çalışarak problemi çözme yoluna gitmiştir.
Donanım düzeyinde gerçeklemelerde özel mikroişlemci komutları CISC işlemcilerde bulunmaktadır. örneğin motorola 68000 deki TAS ( Test and Set ) komutu bir kaynağı bir anda bir prosese vermek için bir bayrağı test eder bayrak uygun durumdaysa kaynağı verir ve bayrağı set eder. Bu işlemler (test ve set) arada bölünemez şekilde tasarlanmıştır, bu yüzden donanım seviyesinde bir çözüm olarak görülebilirse de proseslerin kaynağı alması için sonsuza kadar beklemeyecekleri bu yolla garanti edilemez.
Günümüz İşletim sistemleri çeşitli çözümler sunar. Unix sistemlerde kullanılan semafor yapıları proseslerin karşılıklı dışlama ilkesine göre çalışmasına olanak sağlar. Semaforlar işletim sisteminin sağladığı özel değişkenlerdir ve işletim sistemi kontrolü ile çalışır. Semaforları kullanmak için yine işletim sisteminin sağladığı sistem çağrıları kullanılır. Sistem çağrıları kendi içlerinde bölünemez olarak tasarlandıklarından kaynak paylaşımı karşılıklı dışlama ilkesine göre yapılabilmektedirler.
Karşılıklı dışlama konusuna bu kadar alt düzeyden baktıktan sonra daha yüksek seviyelerde de aslında bu konuya dikkat edildiğine değinmekte yarar var. Örneğin database tasarımında yazma işlemlerin de kilit kullanılması karşılıklı dışlamayı sağlamak içindir.
Karşılıklı dışlama hakkında genel bir fikir vermek istedim, bugun maximum sayida işin maximum süre hizmet görmesi için geliştirilmiş iş sıralama algoritmaları vardır. Karşılıklı dışlama ve iş sıralama algoritmaları performansa direk olarak etki ettiğinden günümüzde önemli bir yere sahiptir.
Bu yazıyı yazmamın sebebi bilgisayar dünyasının çokça kullandığı ama tam olarak ne olduğuda çoğu bilişimci için bilinmeyen bir konuya açıklık getirmeye çalışmaktır. Benimde bilgilerim yeterli olmayabilir o yuzden herşeye inanmayıp araştırmanızı tavsiye ederim;)
"Karşılıklı Dışlama nedir?" sorusunun cevabını şu şekilde özetleyebiliriz: Aynı kaynaklara ( kaynak: RAM, DISK, FILE, EXTERNAL DEVICE etc ) ulaşmak isteyen birden fazla proses olması durumunda bu kaynaklara erişimin kaynak tipine göre paylaşılması ve belli bir anda sadece izin verilen proseslerin bu kaynaklara erişmesinin sağlanmasıdır.
Yukarıdaki tanım biraz karışık gelmiş olabilir. Örnek verelim: Printer paylaşılmayan bir kaynaktır ve karşılıklı dışlama gerektirir bir zaman da sadece bir proses printer ı kullanarak çıkış alabilir.
Dosyalar okuma yapıldığı zaman paylaşılabilir ve okuma için açılan dosyalarda karşılıklı dışlama gerekmez, ancak yazma yapıldığı zaman dosya karşılıklı dışlanmalı ve bir anda bir proses dosyayı elinde tutmalıdır aksi takdirde dosya bütünlüğü tehlikeye girer.
Karşılıklı dışlamayı gerçekleştirmek için bir çok algoritma ortaya atılmıştır. Fakat bir çoğu yetersiz kalmıştır. Örneğin ünlü Banker algoritması kaynak sayısının ve proseslerin sabit olması kısıtı altında çalışarak problemi çözme yoluna gitmiştir.
Donanım düzeyinde gerçeklemelerde özel mikroişlemci komutları CISC işlemcilerde bulunmaktadır. örneğin motorola 68000 deki TAS ( Test and Set ) komutu bir kaynağı bir anda bir prosese vermek için bir bayrağı test eder bayrak uygun durumdaysa kaynağı verir ve bayrağı set eder. Bu işlemler (test ve set) arada bölünemez şekilde tasarlanmıştır, bu yüzden donanım seviyesinde bir çözüm olarak görülebilirse de proseslerin kaynağı alması için sonsuza kadar beklemeyecekleri bu yolla garanti edilemez.
Günümüz İşletim sistemleri çeşitli çözümler sunar. Unix sistemlerde kullanılan semafor yapıları proseslerin karşılıklı dışlama ilkesine göre çalışmasına olanak sağlar. Semaforlar işletim sisteminin sağladığı özel değişkenlerdir ve işletim sistemi kontrolü ile çalışır. Semaforları kullanmak için yine işletim sisteminin sağladığı sistem çağrıları kullanılır. Sistem çağrıları kendi içlerinde bölünemez olarak tasarlandıklarından kaynak paylaşımı karşılıklı dışlama ilkesine göre yapılabilmektedirler.
Karşılıklı dışlama konusuna bu kadar alt düzeyden baktıktan sonra daha yüksek seviyelerde de aslında bu konuya dikkat edildiğine değinmekte yarar var. Örneğin database tasarımında yazma işlemlerin de kilit kullanılması karşılıklı dışlamayı sağlamak içindir.
Karşılıklı dışlama hakkında genel bir fikir vermek istedim, bugun maximum sayida işin maximum süre hizmet görmesi için geliştirilmiş iş sıralama algoritmaları vardır. Karşılıklı dışlama ve iş sıralama algoritmaları performansa direk olarak etki ettiğinden günümüzde önemli bir yere sahiptir.
Thursday, June 01, 2006
It's finally over ...
En sonunda finallerim bitti, bende soluğu itü nün spor salonunda aldım tabi :) artık notlarımızı bekliyoruz. Yazın çalışacak bir yer bulamazsam okuldaki projelere el atıcam inşallah, bir sürü proje beni bekliyor aslında. Haftaya bitirme ödevleri sunumu var ama çok yorulacağımı zannetmiyorum, güzel bir yaz olacak...
Monday, May 29, 2006
Proje Süreci
Bugün proje yonetimi ve organizasyonu konusunda bir ilk daha yaşamanın heyecanı içindeyim. Sayısal işaret işleme lab. için yapacağımız matlab projemiz de 3 kisi çalısıyoruz. Tabi hiçbir zaman bahtı açık olmamış kahramanımız emreknlk projenin yetişmeme olasılığını düşünürken ekip arkadaşıyla aralarında şöyle bir diyalog geçiyor:
xxx : ekip arkadaşının ismi,
emreknlk -> ya xxx bu proje yetişmezse bu hoca bizi bırakır boşuna bir daha alıcaz dersi sonra.
xxx -> olsun ben kalsam da farketmez seneye bir daha alırım.
Bu sözleri duyan emreknlk proje de ekip çalışmasının ekip elemanlarının projeye olan etkisinin ne denli fazla olduğunu tekrar anlıyor.
Bir proje yaparken takım arkadaşları insanı zafere de sürükleyebilir, çuvallamaya da.
Örneğin turkcell stajını yaparken ki takım dayanışmamızı hatırlıyorum da development bir tarafta hüsnü, mennan ve süper paremetre giricimiz ufuk tarafından yapılırken, diğer yandan " test to destruct " ekibizi ben gözde ve fatma dayanışma ve birlik içinde, eğlenceyi de yeri geldiğinde işin içine katarak çok güzel çalışmalar çıkarmıştık. Bütün bunlar ekip elemanlarının uyumunun ve sorumluluk bilincinin hedefe ulaşmada ki katkısını bize gösteriyor.
İkinci Şok
Proje de ekip dayanışması dedik, xxx i örnek verdik, ancak emreknlk nın içinde bulunduğu durum bunla da bitmiyor.
kendisini yyy diye adlandıracağım projeyi bizlere veren ve takip eden sayın hocamız, bizlere üniversite öğrencisi yerine askerliğini yapan er muamelesi yapmaya devam ediyor! Bağırışmaların bini bir para, hal böyle olunca ben dahil diğer proje takımlarının ne kod yazası geliyor ne de araştırma yapası.
Çıkarılan 2. ders: Burdan anlıyorum ki projeyi yapan ekip elemanları kadar projeyi yöneten şahsın dahi sonuca ulaşmadaki katkısı büyüktür. Ekip elemanlarının motivasyonunu düşürücü davranışlar içinde bulunmak, fikir vereceğine fikirleri küçümsemek gibi tutumlar içine giren bir proje danışmanı o projeyi başlamadan bitirir.
Biz gelelim güzel şeylere: Turkcell de hatırlıyorum da bir yöneticimiz daha da ötesinde abimiz olan Tonguç Yılmaz var. Yeri geldiğinde fikirlerimizi dikkatle dinler üzerinde tartışır, yeri geldiğinde olması gerekeni söyler yapmaya çalışırdık. Motivasyon, enerji , dinamizm en üst seviyedeydi. Hüsnünün gece gündüz ayakta kalmasını da buna bağlıyorum zaten:)
Uzun lafın kısası proje sürecinde ki ekip elemanlarının dayanışmasının ve proje yöneticisinin projelerin başarımına olan katkısına değinmek istedim. Birazdan lab. projeme devam edicem. Inşallah sağ sağlim dersi bir şekilde geçmek nasip olur...
xxx : ekip arkadaşının ismi,
emreknlk -> ya xxx bu proje yetişmezse bu hoca bizi bırakır boşuna bir daha alıcaz dersi sonra.
xxx -> olsun ben kalsam da farketmez seneye bir daha alırım.
Bu sözleri duyan emreknlk proje de ekip çalışmasının ekip elemanlarının projeye olan etkisinin ne denli fazla olduğunu tekrar anlıyor.
Bir proje yaparken takım arkadaşları insanı zafere de sürükleyebilir, çuvallamaya da.
Örneğin turkcell stajını yaparken ki takım dayanışmamızı hatırlıyorum da development bir tarafta hüsnü, mennan ve süper paremetre giricimiz ufuk tarafından yapılırken, diğer yandan " test to destruct " ekibizi ben gözde ve fatma dayanışma ve birlik içinde, eğlenceyi de yeri geldiğinde işin içine katarak çok güzel çalışmalar çıkarmıştık. Bütün bunlar ekip elemanlarının uyumunun ve sorumluluk bilincinin hedefe ulaşmada ki katkısını bize gösteriyor.
İkinci Şok
Proje de ekip dayanışması dedik, xxx i örnek verdik, ancak emreknlk nın içinde bulunduğu durum bunla da bitmiyor.
kendisini yyy diye adlandıracağım projeyi bizlere veren ve takip eden sayın hocamız, bizlere üniversite öğrencisi yerine askerliğini yapan er muamelesi yapmaya devam ediyor! Bağırışmaların bini bir para, hal böyle olunca ben dahil diğer proje takımlarının ne kod yazası geliyor ne de araştırma yapası.
Çıkarılan 2. ders: Burdan anlıyorum ki projeyi yapan ekip elemanları kadar projeyi yöneten şahsın dahi sonuca ulaşmadaki katkısı büyüktür. Ekip elemanlarının motivasyonunu düşürücü davranışlar içinde bulunmak, fikir vereceğine fikirleri küçümsemek gibi tutumlar içine giren bir proje danışmanı o projeyi başlamadan bitirir.
Biz gelelim güzel şeylere: Turkcell de hatırlıyorum da bir yöneticimiz daha da ötesinde abimiz olan Tonguç Yılmaz var. Yeri geldiğinde fikirlerimizi dikkatle dinler üzerinde tartışır, yeri geldiğinde olması gerekeni söyler yapmaya çalışırdık. Motivasyon, enerji , dinamizm en üst seviyedeydi. Hüsnünün gece gündüz ayakta kalmasını da buna bağlıyorum zaten:)
Uzun lafın kısası proje sürecinde ki ekip elemanlarının dayanışmasının ve proje yöneticisinin projelerin başarımına olan katkısına değinmek istedim. Birazdan lab. projeme devam edicem. Inşallah sağ sağlim dersi bir şekilde geçmek nasip olur...
Sunday, May 28, 2006
Karar...
Sabah düşünüyordum blog a akademik yazılarımı koyup insanlığa katkıda bulunayim diye, aklıma bir kaç fikir geldi, önce MFC de arayüz nasıl oluşturur buton nasıl eklenir anlatiyim kodlarını yazayim dedim, sonra aklıma Feza hocam geldi, Feza bey hakkındaki düşüncelerimi başka zaman buraya ekliyecem inşallah, programlama kodu vermek yerine blogu programlama nedir olarak kullanmaya karar verdim. En yakın zamanda özellikle OOP üzerine olacak konularla fikirlerimi buraya yazmayı düşünüyorum.
Subscribe to:
Posts (Atom)

-709068.jpg)
-773890.jpg)