Emre S. Tasci emre.tasci@hacettepe.edu.tr
Grafik çizerken, x değerlerimiz için bir liste oluşturmayı görmüştük. Örneğin, x = [-3,3] aralığı için 0.5 artan şekilde bir listeyi:
x = -3:0.5:3
diyerek oluşturabiliyorduk. Aralık büyüklüğü ile uğraşmak istemeyip, doğrudan "-3 ile 3 arasında 100 noktayı düzenli şekilde alayım" dediğimizde ise yardımımıza linspace
komutu yetişiyordu:
x = linspace(-3,3,100)
for... döngüsü belirlediğimiz bir listenin elemanlarını sıra ile ve tek tek işleme sokar.
Basit bir örnek olarak 1'den 5'e kadar olan sayıları yazdıralım:
a = 1
a = 2
a = 3
a = 4
a = 5
Görüleceği üzere, hemen hemen aynı satırı 5 kere küçük bir değişiklikle yazıp çalıştırıyoruz, ki bu oldukça sıkıcı ve zahmetli. Satırlardaki tek değişen şeyin a'yı eşitlediğimiz sayı olduğunu görüyoruz. Demek ki a = i
diye bir şey düşünsek, ve i'nin değerini 1'den başlayıp, her seferinde 1 arttırarak 5'e kadar getirsek işler hayli kolaylaşacak.
i'nin değerinin 1'den 5'e birer birer arttırıldığı halini yapmayı biliyoruz:
n = 1:5
Burada listemize "i" yerine "n" adını verdik çünkü n, i'nin alacağı bütün değerleri barındıran bir kutu; i ise bu değerlerin her biri. for döngüsünü şu şekilde tanımlıyoruz:
for <değişkenin adı> = <tek tek ve sıra ile alacağı değerlerin tutulduğu liste> yapılacak iş #1... yapılacak iş #2... yapılacak iş #3... ... endfor
for ... endfor arasında yer alan ve yapılacak işleri tutan kısma blok diyoruz.
Şu halde, a'nın değerini 1 ile 5 arasında değiştirecek ilk döngü örneğimiz şöyle olur:
for i = 1:5
a = i
endfor
Açık açık 1:5
yazmak yerine, önceden tanımlamış olduğumuz ve aynı değerleri tutan n'yi de kullanabilirdik:
n = 1:5;
for i = n
a = i
endfor
(unutmayın ki Octave sembolik bir dil değil, yani n gördüğü yere n neye karşılık geliyorsa onu alıp yerleştiriyor: i = 1:5
yazmakla i = n
yazmak arasında işlemsel hiçbir fark yok (pratik açıdansa programlarınızı değişkenler üzerinden yazmak yüksek esneklik sağlamakta).
Biraz daha ilginç bir örnek yapalım, örneğin x'in değerini -3'den 3'e 0.5'e kadar arttırıp, her bir değerin karesini s diye bir değişkende toplayalım:
s = 0; % Değerleri s'de toplayacağımız için ilk olarak s'yi tanımlayıp sıfırlıyoruz.
xler = -3:0.5:3; % 'xler' ile 'x' arasındaki farka dikkat edin!
for x = xler
s = s + x*x;
endfor
s
Başta da belirttiğimiz üzere, for döngüsündeki değerler bir listeden sıralı ve tek tek olarak alınır. Listenin kendisinin sıralı olmasına gerek yok. Sınıftan 5 kişiye akıllarına gelen bir sayıyı söylemelerini isteyelim ve onlar da 5,-3,19,12,-2 sayılarını söylemiş olsunlar. Bir önceki örneği biraz değiştirerek bu sayıların karelerini toplayan bir program yazalım:
s = 0;
xler = [5,-3,19,12,-2];
for x = xler
printf("x'in şimdiki değeri: %3d\n",x) % printf() ekrana düzgün bir şekilde
% yazdırmak için kullanılır, yoksayabilirsiniz.
s = s + x*x;
endfor
s
Peki ya verdiğimiz sayıların karelerinin toplamını bulmak yerine, her bir sayının karesini bir listede toplamak istersek? Bunu doğrudan liste üzerinde işlem yaparak bulabileceğimizi görmüştük, örneğin:
xler = [5,-3,19,12,-2];
xkareler = xler.^2
Ama şimdi bunu for döngüsü ile gerçekleştirmek istiyoruz (ileride böyle kolaylıkla aritmetik yoldan yapamayacağımız durumlara hazırlık olarak).
Öncesinde, bir listeye değerleri tek tek nasıl toplayacağımızı düşünelim... Mesela, xler listesini tek tek oluşturalım (listenin içine önce 5'i, sonra -3'ü, ardından 19'u, vs. atarak):
xler = []
xler = [5]
xler = [5 -3]
xler = [5 -3 19]
Burada bir duralım zira saçmasapan bir iş yapıyoruz. Tamam, ilk iş olarak, değerleri toplayacağımız kutumuz olan xler
i boş olarak tanımladık, sonra da ilk eleman 5'i ekledik, bu da tamam, ama daha sonra ikinci eleman -3'ü ve üçüncü eleman 19'u eklerken aslında ekleme yapmayıp, tekrar tekrar öncekileri yazdık (bir başka deyişle sadece xler = [5 -3 19]
deseydik de yeterdi -- öncekileri yazmaya hiç gerek yoktu)!..
Burada yine Octave'ın sembolik bir dil olmayışının nimetlerinden faydalanalım:
Üçüncü satırda xler = [5 -3]
derken biz \xler = [xler -3]
olarak da yazabilirdik. \xler = [5 -3 19]
yerine xler = [xler 19]
olarak yazabilirdik. Özetle:
xler = []
xler = [xler 5]
xler = [xler -3]
xler = [xler 19]
xler = [xler 12]
xler = [xler -2]
Bu yöntem, döngülerde çok işimize yarayacak. Artık verilmiş bir xler listesindeki x değerlerinin karelerini tek tek bir başka listede toplayacak bilgimiz var:
xler = [5,-3,19,12,-2];
xkareler = [];
for x = xler
xkareler = [xkareler x*x];
endfor
xkareler
while döngüsü, döngüyü kurarken belirttiğimiz önerme doğru (bilgisayar dilinde konuşursak '1') olduğu sürece, döngüyü devam ettirir. Önergenin doğru olması ne anlama geliyor? Birkaç sayısal önerme yazalım:
Özellikle son iki önermeye dikkat edin: onlaraa gelinceye kadar, aşağı yukarı matematikte kullandığımız işaretlerin benzerlerini yazdık ama iş "eşittir"e gelince, tek bir "=" işareti yerine, "==" olarak, iki tane yazdık. Bunun sebebi, "=" işaretinin her zaman için **değer atama** anlamına gelmesi. Bu nedenle, "eşittir" önermesini "==" şeklinde, çift "=" işareti ile karşılıyoruz.
Bu önermeleri Octave'a soralım, bakalım ne cevap verecek:
3 > 1
5 < 4
12 <= 13
12 >= 12
3 != 7
7 == 7
3 == 5
"1 : Doğru" ve "0 : Yanlış" olmak üzere yorumlarsak, cevapları anlamış oluruz.
O zaman -3'ten 3'e kadar olan sayıların karelerin toplamını bir kez daha, bu sefer while döngüsü ile hesaplayalım:
kareler_toplami = 0;
x = -3; % başlangıç değerimiz
while (x <= 3)
kareler_toplami = kareler_toplami + x*x;
x = x + 1;
endwhile
kareler_toplami
Bloğumuz, önermemiz doğru olduğu müddetçe çalıştırılıyor.
-3 <= 3
doğru olduğundan blok çalışıyor, kareler_toplami = 0 + (-3)*(-3)
işleminden 9 oluyor. -2 <= 3
de doğru olduğundan, blok yine çalıştırılıyor. kareler_toplami = 9 + (-2)*(-2)
işleminden 13 oluyor. kareler_toplami = 19 + (3)*(3)
işleminden 28 oldu. İlginç bir detay olarak, x'in döngü bittiğindeki değerini düşünelim... 9. adımda 4 olmuştu, bunu teyit etmek istersek:
x
Aslında an itibarı ile karar mekanizması hakkında bir bilgimiz var zira while döngüsünü işlerken, önermenin -hâlâ- doğru olup olmadığına bakarken karar mekanizmasını kullandık. Tek başına hallerde ise karar vermek(/verdirmek) için if.. karar mekanizmasını kullanıyoruz.
a = 5
if (a == 5)
disp("a, 5'e eşit")
endif
if(a > 6)
disp("a, 6'dan büyük")
endif
if(a < 9)
disp("a, 9'dan küçük")
endif
Yukarıdaki kodu çalıştırdığımızda, sadece doğru önermelere sahip if bloklarının işleme konduğunu görüyoruz. Bu örnekte a'nın değerine bağlı olarak üç olasılıktan biri olmak zorunda:
a:
Üç ayrı if bloğu yazmak yerine, bunları tek bir if bloğunda toplayabiliriz:
a = 5
if(a == 5)
disp("a 5'e eşit")
elseif(a > 5)
disp("a 5'ten büyük")
else
disp("a 5'ten küçük")
endif
a'nın değerinin 5'ten küçük olmasını kontrol ettirmeyip "a, 5'e eşit değilse, 5'ten büyük de değilse, o zaman 5'ten küçük olmak zorundadır." mantığıyla hareket ettiğimize dikkat edin. Tek bir değer üzerinden gittiğimizden kod biraz sıkıcı oldu, o nedenle bir for döngüsü içinde çağıralım:
alar = [7 -9 3 -7 8 5 6 -2 2 5 0]
for a = alar
a
if(a==5)
disp("a 5'e eşit!")
elseif(a>5)
disp("a 5'ten büyük.")
else
disp("a 5'ten küçük")
endif
disp("---------------------")
endfor
İşleri biraz geliştirelim. Verilmiş sayıları tek/çift olarak ayıralım:
alar = [7 -9 3 -7 8 5 6 -2 2 5 0]
tekler = [];
ciftler = [];
for a = alar
if(mod(a,2) == 0)
% a, 2 ile bölündüğünde kalanı sıfır oluyor (mod)
% o zaman çift demektir
ciftler = [ciftler a];
else
tekler = [tekler a];
endif
endfor
disp("Tek sayılar:")
tekler
disp("Çift sayılar:")
ciftler
Asal sayılar, tanımları gereği kendileri ve 1 dışında hiçbir sayıya tam olarak bölünemeyen sayılar. 2 ile 10 arasındaki asal sayıları bulmak için biri kötü, diğeri iyi iki yoldan gideceğiz.
Kötü olan metot, akla ilk gelen: elimizdeki sayı n olsun. 2'den başlayarak (n-1)'e kadar sayıları tek tek deneyip, n'i tam olarak bölüp bölemediklerine bakacağız, bir yandan da koddaki eksiklikleri tespit edip, adım adım geliştireceğiz:
asallar = []; % bulduğumuz asalları bu listenin içine koyacağız
for sayi = 2:10
% bu bizim asallığını kontrol etmek istediğimiz sayı
disp("Asallığını kontrol ettiğimiz sayı:")
sayi
disp("") % Bir boş satır ekleyelim
for bolen = 2:sayi-1
% bölenlerin döngüsünün bitişini
% sayi'ya bağlı olarak tanımladığımıza dikkat edin!
bolen
kalan = mod(sayi,bolen)
if(kalan == 0)
% Bu sayı asal olamaz.
disp("Sayı asal değil!")
disp("") % Bir boş satır ekleyelim
else
% Buraya sadece asal sayılar mı ulaşabiliyor acaba?
% Hayır! 8)
% Örneğin sayi 9, bolen 2,4,5,6,7,8 olduğunda
% kalan 0 olmayacak ama biliyoruz ki sayı asal değil
endif
disp("") % Bir boş satır ekleyelim
endfor
disp("-------------------")
endfor
sayi = 2 ve 3 için güzel gitti ama sayi = 4 durumunu inceleyelim:
Asallığını kontrol ettiğimiz sayı:
sayi = 4
bolen = 2
kalan = 0
Sayı asal değil!
bolen = 3
kalan = 1
buradaki sıkıntı, 2'ye bölündüğünü bulduğumuz halde (yani sayının asal olmadığını anladığımız halde) hala kontrole devam ediyor oluşumuz. Bunu engellemek için döngüyü kırmalıyız (break
)
asallar = []; % bulduğumuz asalları bu listenin içine koyacağız
for sayi = 2:10
% bu bizim asallığını kontrol etmek istediğimiz sayı
disp("Asallığını kontrol ettiğimiz sayı:")
sayi
disp("") % Bir boş satır ekleyelim
for bolen = 2:sayi-1
% bölenlerin döngüsünün bitişini
% sayi'ya bağlı olarak tanımladığımıza dikkat edin!
bolen
kalan = mod(sayi,bolen)
if(kalan == 0)
% Bu sayı asal olamaz.
disp("Sayı asal değil! - döngüden burada çıkıyorum.")
disp("") % Bir boş satır ekleyelim
break; % "bolen = 2:sayi-1" döngüsünü kırıyoruz
endif
disp("") % Bir boş satır ekleyelim
endfor
% Buraya iki yoldan gelmiş olabiliriz:
% ya sayi kalansız bolundu ve döngü break ile kırıldı
% (bu durumda kalan == 0)
% ya da hiçbir bolen kalansız bölemedi ve 2:sayi-1 döngüsü
% normal yoldan sona erdi (bu durumda kalan != 0)
if(kalan != 0)
disp("Sayı asal!")
asallar = [asallar sayi];
endif
disp("-------------------")
endfor
asallar
break
komutu o an içerisinde bulunulan döngüyü sonlandırmakta kullanılır.
Örneğin, satır ve sütunu eşit oluncaya kadar (o eleman dahil) değerleri 1 olan bir matris oluşturalım:
m = zeros(5,5) % bütün elemanları 0 olan, 5x5 bir matris oluşturur.
for satir=1:5
for sutun = 1:5
m(satir,sutun) = 1;
if(satir == sutun)
break;
% şu anda sutun=1:5 döngüsünün içinde olduğumuzdan
% break ile sadece bu bloktan çıkarız.
endif
endfor
endfor
m
Yukarıdaki yaklaşımda, 7'nin asal olup olmadığını kontrol ederken şu aşamalardan geçtik:
Asallığını kontrol ettiğimiz sayı:
sayi = 7
bolen = 2
kalan = 1
bolen = 3
kalan = 1
bolen = 4
kalan = 3
bolen = 5
kalan = 2
bolen = 6
kalan = 1
Sayı asal!
Buradaki sıkıntı, 2'ye bölünmeyen bir sayının 4'e ve 6'ya bölünüp bölünmediğini kontrol etmemiz. Halbuki 2'ye bölünmüyorsa, 2'nin katlarına da bölünemez. Benzer şekilde, 3'e bölünmüyorsa, 6'ya ve 9'a da bölünemez, vs.. O halde boşu boşuna kontrol ediyoruz.
Asal sayıların tanımını biraz geliştirelim: kendilerinden ve 1'den başka hiçbir asal sayıya kalansız olarak bölünmeyen sayılara asal sayı denir. diyelim. Sonuçta asal olmayan bir sayıyı her zaman için asal çarpanlarının çarpımı şeklinde yazabiliriz (12 = 2 x 6 = 2 x 2 x 3 = 2^2 x 3 gibi).
Tekrar 7'nin asallık kontrolüne geldiğimizi düşünelim. O anda elimizdeki asallar
listesinde kimler var? 2,3,5 --> o halde 7'nin sadece bu sayılara tam bölünüp bölünmediğini kontrol etmek yeterli. Kodu bu şekilde değiştirmek demek, bölenlerin listesini "2:sayi-1" yerine asallar
listesine eşitlemek demek:
asallar = [2]; % bulduğumuz asalları bu listenin içine koyacağız
for sayi = 3:10
% bu bizim asallığını kontrol etmek istediğimiz sayı
disp("Asallığını kontrol ettiğimiz sayı:")
sayi
disp("") % Bir boş satır ekleyelim
for bolen = asallar
% asallar listesinin dinamik bir liste olduğunu
% yani mesela 4'e gelindiğinde [2 3];
% 9'a gelindiğinde [2 3 5 7] olduğuna dikkat edin!
bolen
kalan = mod(sayi,bolen)
if(kalan == 0)
% Bu sayı asal olamaz.
disp("Sayı asal değil! - döngüden burada çıkıyorum.")
disp("") % Bir boş satır ekleyelim
break; % "bolen = 2:sayi-1" döngüsünü kırıyoruz
endif
disp("") % Bir boş satır ekleyelim
endfor
% Buraya iki yoldan gelmiş olabiliriz:
% ya sayi kalansız bolundu ve döngü break ile kırıldı
% (bu durumda kalan == 0)
% ya da hiçbir bolen kalansız bölemedi ve 2:sayi-1 döngüsü
% normal yoldan sona erdi (bu durumda kalan != 0)
if(kalan != 0)
disp("Sayı asal!")
asallar = [asallar sayi];
endif
disp("-------------------")
endfor
asallar
Dikkat ederseniz, bu sefer asallar listesini en başta 2 olacak şekilde başlattığımızı, sayi döngüsünü de 3'ten başlattığımızı göreceksiniz. Bunun sebebi "for bolen = asallar" döngüsünün asallar listesi boş olduğu zaman çalışmaması ve bu yüzden asal avına daha baştan çıkamamamız. En azından 2'yi koyuyoruz ki, 3'ü kontrol edecek bir bölenimiz olsun.