Çözüm : Şadi Evren ŞEKER
Çözüme geçmeden önce, sizlerle görüşme imkanımız olmadığı için bir iki noktayı buradan açıklama ihtiyacı hissettim. Öncelikle, bilinmelidir ki bu sınavda sorulan bütün sorular, derste anlatılan konular kapsamında hazırlanmıştır. Bazı sorulara çözüm olabilecek derste birden fazla yol gösterilmiştir, buradaki cevaplarda bir tanesini seçip (genelde en uzun ve karmaşık olanını vermeye çalışıyorum) anlatıyorum ancak diğer yollar da doğru kabul edilecektir. Hatta derste anlatılmayan ama JAVA dilinde doğru olan yöntemler kullandıysanız (sonuçta derste anlatmadığım ama JAVA Tutorial içinde bulunan ve sizin ders dışı çalışarak öğrendiğiniz konular olabilir) bunları da doğru kabul edeceğim.
Ayrıca sınavlarınızın bir kısmını okudum ve genel olarak çalışmadığınız görülüyor. Nasıl bir sınav bekliyordunuz bilmiyorum ama bu dönem itibariyle hayal kırıklığına uğradığımı söyleyebilirim. Özellikle final sınavında birebir derste anlattığım kodları sormuştum. Finaldeki toplam 5 sorunun tamamını derste adım adım kodlayıp çalıştırıp sizlere anlatmıştım. Özellikle finaldeki 0. soruyu çözemeyip, ekrana ismini ve numarasını bastıramayan kişi sayısı sınıfın çoğunluğunu oluşturuyor. Bu durum da gösteriyor ki bu derse hiç çalışılmamış. Bütünleme sınavlarının henüz tamamını okumadım ama görülen durum, derste anlatılan konuları, bildiğiniz veya bilmenizi beklediğimiz konuları, farklı problemlere uygulayamadığınız. Örneğin Thread sorusunda, derste anlattıklarımın dışında yeni hiçbir bilgiye ihtiyacınız olmadığı halde genelde bu soruda durum çok kötü. Bu dönem itibariyle ilk defa üniversitenizde ders verdiğim için sanırım benim hatam sizlere fazla güvenmem ve çalışacağınıza olan inancımdı. Bu dönemden sonra, her hafta ödev, dönem projesi, quiz ve sıkı bir laboratuvar programı uygulamamız gerektiğini, ve sizleri çalışmaya zorlamamız gerektiğini anlamış bulunuyorum.
Aşağıdaki çözümleri web sayfası olarak yayınlarken bazan hatalar olabiliyor. Kod hassas bir yazı olduğu için bu tip hatalara mahal vermemek adına, çalışan bir örnek kodu aşağıdaki linkten indirebilirsiniz:
Sınavın çözüm kodu (netbeans projesi olarak) indirmek için tıklayın.
Soru 0) Bir kesir (fraction) sınıfı kodlayınız. Kodunuza iki kesiri toplayan fonksiyonu ekleyiniz. (15 puan)
Öncelikle bilinmelidir ki rasyonel sayılar kümesi reel sayılar kümesinden farklıdır. Ayrıca kesirli sayıların paydası 0 olamaz. Sınavda bu problemi çözmek için istisna yakalama (exception handling) kullanabileceğiniz gibi, basit bir if ile kontrolünüz de doğru kabul edilecektir. Buna göre kodlanmış hali aşağıdaki şekildedir:
package butunleme; class kesir{ public int getPay() { return pay; } public void setPay(int pay) { this.pay = pay; } public int getPayda() { return payda; } public void setPayda(int payda) { if(payda==0) // kesirli sayıların paydası 0 olamaz. payda = 1; this.payda = payda; } public kesir(int pay, int payda) { setPayda(payda); setPay(pay); } int obeb(int a,int b){ if(b==0) return a; else return obeb(b,a%b); } public void topla(kesir k){ int obeb = obeb(k.payda, payda); k.pay *= payda/obeb; pay *= k.payda/obeb; pay += k.pay; payda = (k.payda/obeb ) * (payda/obeb); } int pay; int payda; } public class Butunleme { public static void main(String[] args) { // TODO code application logic here kesir k = new kesir(3,4); kesir m = new kesir(4,5); k.topla(m); System.out.println("toplam : "+k.pay + " / "+ k.payda); } }
Ekran çıktısı :
toplam : 31 / 20
Soru 1) 0. Soruda verdiğiniz cevabı kullanarak, bir çok terimli (polynom) sınıfı kodlayanız. Toplama (summation) , çarpma (multiplication), türev (derivation) ve çözme (evaluation) metotlarını kodlayınız. Kodunuzda, kapsülleme (encapsulation), çok şekillilik (polymorphism), yapıcı metotlar (constructor methods) bulunmalı ve kodunuzu çalıştıran main fonksiyonunu yazmalısınız. Ayrıca kodunuzu yazdıktan sonra konsol üzerinde nasıl derlenip çalıştırığını da yazınız.
Örnek:
(¾ x2 + ½ x + 5) çok terimlisi ile (5x3 + 1/3 x + 2) çok terimlisinin toplamı :
(5x3 + ¾ x2 + 5/6 x + 7) olarak bulunmalıdır. Yukarıdaki iki soru için tek bir kod yazabilirsiniz. (35 puan)
Sorunun çözümünü dosya olarak ekliyorum. Soru için genel olarak birden fazla çözüm yolu bulunuyor. Örneğin iki çok terimlinin toplamını 3. bir çok terimliye döndürmek veya mevcut çok terimliye bir parametre eklemek arasındaki tercih notlamayı etkilemez. Örnek kodda çarpma için üçüncü bir çok terimli döndürdüm ve toplama için mevcut çok terimliye ilave ettim, dolayısıyla iki yolda görülebiliyor. Ayrıca çok terimlileri sadeleştirmek veya sadeleştirmemek de notlama için önemli değil. Yine örnek çözümde terim isminde bır sınıf kullanıp, çok terimlinin her terimini bu sınıftan bir nesne halinde vektöre yerleştirdim. Derste birden fazla nesneyi tutmak için iki yol görmüştük, vektör yerine diğer yol olan dizi kullanılabilir veya terim sınıfı yerine 3 farklı dizi paralel şekilde tutulabilirdi (ders veri yapıları olmadığı için bu tip, aslında veri yapısı hatası olan kodlamaları kabul edebiliriz). Yine örnek kodda, obeb (gcd) hesabı için özyineli (recursive) fonksiyon kullandım, iteratif kullanım da yapılabilirdi. Anlatmaya çalıştığım üzere sonucu doğru olan birden fazla yol bulunmakta ve hangisi ile yapılması istendiği, soruda beliritilmediği için önemli olmamaktadır.
Soru 2)Grafik arayüzü kullanarak (swing kütüphanesi), bir çok terimliyi okuyan ve yukarıdaki kodunuzu kullanarak bir nesne oluşturan kodu yazınız. (20 puan)
Bu soruda da farklı seçimler yapılabilir. Örneğin swing kütüphanesi kullanılarak basit bir arayüz tasarlayıp tek bir metin kutusundan çok terimli okunabilir. Okuduğunuz çok terimliyi daha sonra tokenize etmeniz gerekeceği için swing kısmı basit ama arkadaki string işleme kısmı kuvvetli bir kod yazabileceğiniz gibi, çok terimlinin her terimini okuyan ayrı birer kutu da yerleştirilebilir. Sonuçta amacımız bir çok terimliyi ekrandan okumak.
package butunleme; import javax.swing.*; import java.awt.*; import java.awt.event.*; public class ekran implements ActionListener{ //www.bilgisayarkavramlari.com JButton dugme; JButton tamam; JFrame x; int derece; JTextField tf; JLabel jl; JTextField ctparam []; public ekran(){ x = new JFrame(); x.setLayout(new FlowLayout()); jl = new JLabel("Çok Terimlinin derecesini giriniz:"); x.add(jl); tf = new JTextField(5); x.add(tf); dugme=new JButton("Devam"); x.add(dugme); dugme.addActionListener(this); x.setSize(400,200); x.setVisible(true); } public static void main(String args[]){ new ekran(); } public void actionPerformed (ActionEvent e){ if(e.getSource()==dugme){ derece = Integer.parseInt(tf.getText()); x=new JFrame(); x.setLayout(new GridLayout(derece+2,2)); x.setSize(150,300); x.add(new JLabel("pay")); x.add(new JLabel("payda")); x.add(new JLabel("üst")); ctparam = new JTextField [derece*3]; for(int i = 0;i<derece;i++){ ctparam[3*i]=new JTextField(); ctparam[3*i+1]=new JTextField(); ctparam[3*i+2]=new JTextField(); x.add(ctparam[3*i]); x.add(ctparam[3*i+1]); x.add(ctparam[3*i+2]); } tamam = new JButton("Tamam"); x.add(tamam); tamam.addActionListener(this); x.setVisible(true); } if(e.getSource() == tamam){ cokTerimli ct = new cokTerimli(); for(int i = 0;i<derece;i++){ ct.ct.add(new terim(Integer.parseInt(ctparam[3*i+2].getText()), new kesir(Integer.parseInt(ctparam[3*i].getText()), Integer.parseInt(ctparam[3*i+1].getText())))); } ct.goster(); } } }
Kodun ekran çıktısı aşağıdaki şekildedir:
Ve kod konsoldan aşağıdaki çok terimliyi basar:
2/3x^4 + 5/6x^5 + 3/1x^2 + 3/4x^3 + 1/1x^1
Soru 3) Bir çok terimlinin x ekseni ile arasında kalan alanın hesaplanması için, kullanılan yöntemlerden birisi de, belirli aralıklarla x değerleri verilerek dikdörtgenler elde etmek ve bu dikdörtgen alanlarının toplamlarını hesaplamaktır.
Örneğin yukarıda, şekli verilen çok terimlinin alanı hesaplanırken, belirli aralıklara sahip x değerleri verilmiş ardından bu değerlerin çok terimlideki sonuçları ile aralık miktarları çarpılarak elde edilen dikdörtgenlerin alanları bulunmuştur. Çok terimlinin alanı, bu dikdörtgenlerin alanlarının toplamı olarak bulunabilir.
Bu hesaplama işlemi, karmaşık çok terimliler için, çok küçük aralıklarla hesaplama istendiğinde, bilgisayara yüksek miktarda yük getirebilmektedir. Sizden istenen hesaplama işlemini çok life bölmenizdir.
Çok lifli (multi threaded) kod yazarak hesaplanacak alanı en az 3 life (thread) bölünüz ve sonucu ekranda gösteren main fonksiyonunu kodlayınız.
Not: kolaylık olması için bu soruda, hesaplanacak alanın başlangıç ve bitiş değerlerini (x’in alt ve üst limitlerini), aralık değerini (delta) ve lif sayısını, kullanıcıdan alabilirsiniz.
(30 puan)
Yukarıdaki soru için yazılabilecek çözümlerden birisi aşağıdaki şekildedir:
package butunleme; class alanLif extends Thread { cokTerimli ct ; int basla,bit; int delta; anaLif al ; public alanLif(cokTerimli ct,int basla, int bit, int delta,anaLif al){ this.ct = ct; this.basla = basla;this.bit=bit;this.delta=delta; this.al = al; } public void run(){ int hareket = basla; int toplam = 0; while(hareket < bit){ toplam += ct.coz(hareket)*delta; hareket += delta; } al.getSonuc(toplam); System.out.println(" alan : "+ toplam + " aralik " + basla + " - "+ bit); } } public class anaLif { int toplam=0; int sonucGelen = 0; public anaLif(){ cokTerimli ct = new cokTerimli(); ct.ct.add(new terim(2,new kesir(2,1))); ct.ct.add(new terim(1,new kesir(3,1))); ct.ct.add(new terim(0,new kesir(5,1))); ct.goster(); int basla = 0; int bit = 100; int ara= (bit-basla)/5,arabasla=0,arabit=ara; for(int i = 0;i<5;i++){ new alanLif(ct,arabasla,arabit,1,this).start(); arabasla+=ara; arabit += ara; } } public static void main(String args[]){ anaLif al = new anaLif(); while(al.sonucGelen < 5) try{ Thread.sleep(50); } catch(Exception e){} System.out.println("alanın toplam değeri:"+al.toplam); } public void getSonuc(int sonuc){ toplam += sonuc; sonucGelen ++; } }
Yukarıdaki kodda, alanLif isimli thread sınıfı, verilen aralık ve delta değeri için alan hesaplamaktadır. Bu sırada, çok terimli sınıfında bulunan çöz fonksiyonunu kullanmaktadır. Ayrıca analif sınıf, 5 adet (bu örnek için lif sayısını ben 5 kabul ettim, sayı farklı olabilir, soruda 3’ten fazla olması istenmiştir) lif (thread) oluşturmaktadır.
Son aşamada, main fonksiyonu altında, bütün threadler bitene kadar (ki bittiklerini hepsinin sonuç döndürmesinden anlıyoruz) bekliyoruz. Bütün thraedler sonuçlarını analif’e döndürünce, her threadden gelen değeri alıp sonuç toplamını hesaplıyor ve ekrana basıyoruz.
Yukarıdaki kod için örnek ekran çıktısı aşağıdaki şekildedir:
2/1x^2 + 3/1x^1 + 5/1x^0 alan : 5610 aralik 0 – 20
alan : 102410 aralik 40 – 60
alan : 38010 aralik 20 – 40
alan : 198810 aralik 60 – 80
alan : 327210 aralik 80 – 100
alanın toplam değeri:672050