ROM'unuzu Kullanın

Uzun zamandır ROM rutinlerini incelemek için gerekli hazırlıklarla uğraşıyorduk. Tabii ki bu arada birkaç önemli rutin gördük, ama bunların hiçbiri size söz verdiğim SIN, COS, vb. fonksiyonlarını yapmanızı sağlamıyordu. Geçen ay işlememiz gereken son konuyu, yani değişkenlerin ve dizilerin yapılarını da anlattıktan sonra, ertelenebilecek hiçbir konu kalmadı. Artık BASIC'in yapabileceği tüm matematik işlemlerini makine dilinde yaptırmayı sağlayacak bilgileri vereceğim. Ama her şeyden önce geçen sayının ROM'unda yapılan bir hatayı düzeltmek istiyorum: İlk örneğimizde 7 ile 13'ü birbiriyle çarpmak istiyorduk, ama çarpma rutininde $BA2B'ye değil $BF2B'ye sıçramanız gerektiği yazılmış. Aslında ufak bir hata gibi görülebilir, ama düzeltilmezse programınız hiçbir zaman çalışmaz. Doğru adresler için aynı sayıda yayınlanmış olan küçük tabloyu kullanmanız gerekiyor. Basit işlemler dışında kalan işlemleri tek tek vermek yerine, daha genel olan fonksiyonlardan bahsedeceğim biraz. Matematikçiler fonksiyonları

Y=F(X)

olarak yazmaya bayılırlar. Buradaki X, fonksiyonun girdisi, ya da argümanı, F fonksiyon ve Y'de sonuçtur. Kayan noktalı fonksiyonları çağırmadan önce argüman X, ya da kısaca FAC'a yerleştirilmiş olmalıdır. Sonuç Y, fonksiyondan dönüldükten sonra gene FAC'da bulunabilir. BASIC yorumlayıcısının kullandığı fonksiyonlar ve adreslerini Tablo 1'de görebilirsiniz. Bu tablodaki hesap uzunlukları PI sayısını argüman olarak verdikten sonra hesaplanmıştır.

İsim Adres Hesaplanma süresi - Açıklama ABS $BC58 0.0 ms mutlak değer ATN $E30E 44.6 ms arctanjant COS $E264 27.9 ms cosinüs EXP $BFED 26.6 ms e üzeri .. FRE $B37D 0.6 ms boş bellek miktarı INT $BCCC 0.9 ms tam değer fonksiyonu LOG $B9EA 22.2 ms doğal logaritma POS $B39E 0.3 ms cursor'un bulunduğu kolon RND $E097 3.5 ms rastlantısal sayı SGN $BC39 0.4 ms işaret SIN $E26B 24.5 ms sinüs SQR $BF71 51.2 ms kök TAN $E2B4 49.8 ms tanjant

BASIC işlemcisinin fonksiyonları ve adresleri.

Tablodan da görebileceğiniz gibi, fonksiyonların uzunlukları üç ana grupta toplanmış: Neredeyse 0 olanlar, 20-30 arası ve 44-50 arası. Ve gene fark edeceğiniz gibi; SIN, COS, EXP, LOG, TAN, ATN, SQR gibi komutlar göreli olarak daha uzun sürüyorlar. Bu fonksiyonların özellikleri, daha ön-

ce nasıl yapıldığını gördüğümüz dört işlemle hesaplanamamaları. Bunun yanında, değerlerinin de tam olarak bulunması imkansız. Ancak dört işlem kullanarak yaklaşık değerleri hesaplanabilir. Matematikçiler sağ olsunlar, bu tür fonksiyonların polinom gösterimi kullanılarak da hesaplanabileceğini bulmuşlar (konuya ilgi duyanlar MacLaurin ve Taylor Serileri konusunda bilgi edinmeye çalışabilirler). Bu polinomlar aşağıdaki formdadırlar:

A4a5Xx.54..

Eğer y'nin gerçek değerini bulmak isterseniz sonsuz sayıda terimi hesaplamalısınız. Tabii ki pratikte bunu yapmanız imkansız olacağı için gerçek değere yeterince yaklaştığınız bir noktada bu seriyi kesmeniz gereklidir. Bu da kaçınılmaz olarak gerçek değerden küçük bir miktar uzaklaştıracaktır sizi. Ne kadar fazla terim alırsanız o kadar kesin sonuçlar alırsınız, fakat hesabınız da oldukça uzar bu arada. Bu polinomların (diyelim ki) ilk altı terimini hesaplamak isterseniz

14 çarpım ve beş de toplama yapmanız gerekecektir (çarpılan terimleri birbirine eklemek için). Fakat bu işlemi yapmak için önerilen bir başka metod da vardır (Teşekkürler matematikçiler...). “Horner Metodu” adı verilen bu metod sayesinde beş terimlik bir işlemi parantezlere alarak şu şekilde yazabiliriz:

ya Xxtal

Bu sayede sadece beş çarpma ve beş toplama y'nin değerini hesaplamaya yetecektir. Genel olarak n. dereceden bir polinomun belli bir x için değerini hesaplamak

100 Y - A(N)
110 FOR IT - N-1
130 NEXT Y

Tablo-2: n. dereceden polinomun belirli bir X için değerini hesaplayan program.

n(n+1)/2 çarpma ve n toplama gerektirirken, Horner metoduyla n çarpma ve n toplama yapmak yeterli olmaktadır. Bu işlemi yapacak bir program yazmanın ne kadar basit olduğunu Tablo 2'de yer alan programdan da görebilirsiniz. Bu program n. dereceden bir polinomun belirli bir x için alacağı değer hesaplar ve sonucu y'de bırakır. A(k) dizisi de a0'dan an'e kadar olan katsayıları tutar. Bu anlattığım teori, fonksiyonların çoğunun bilgisayarlar tarafından hesaplanabilmesini mümkün kılar. BASIC yorumlayıcısı da n. dereceden polinom hesaplayıcı bir rutin sayesinde SIN, COS gibi fonksiyonları hesaplayabilir.

Polinom Değeri Hesaplama

Demin bahsettiğim rutin $E059 adresinde yer alır ve şu değerleri ister: FAC: x'in değerini tutar. Y, A: polinom değer tablosu. A — düşük değerlikli, Y— yüksek değerlikli. Polinom değeri tablosu, şu şekilde hazırlanmış olmalıdır.

polinom derecesi n n. derecenin katsayı değeri (n-1). derecenin katsayı değeri

1. derecenin katsayı değeri 0. derecenin katsayı değeri

Buradaki polinom derecesi tek baytlık işaretsiz bir sayıdır. n. derecenin katsayısı dediğimiz şey de x^n'li terimin katsayısıdır. Bu katsayı değerleri hep 5'er baytlık kesirli sayılar olarak saklanırlar. Artık bu bilgilerimizden yararlanarak polinom değerlerini hesaplayan bir rutin yazabiliriz rahatlıkla. Normal bir Assembler ile çalışırken kesirli sayıların datalarını belleğe geçirmek zordur. En kötü ihtimalle, bir değişkene bu kesirli sayıyı atayıp, bir monitör programı aracılığıyla

Böylece bu değişkenin datalarını kağıda yazıp, .BYT a,b,c,d,e şeklinde girebiliriz. Ama ASSEMBLER/MONITOR:64 kesirli sayıları doğrudan doğruya kaynak (source) listesine eklemenize izin veriyor. Bu iş için de .FLP komutunu kullanıyoruz. Assembler her .FLP gördüğü yerden sonra gelen sayıları otomatik olarak beşer baytlık kesirli sayı datasına çeviriyor. Neyse, sözü fazla uzatmadan bilgilerimizi ortaya koyalım ve şu polinomun lim:

Program 1'e bakarsanız bu hesabı yapan makine dili programını görebilirsiniz.

*-828 ;$033C, yani
kaset buffer
POLINOM - $E059
LDA #<KATSAYI
LDY #>KATSAYI
JMP POLINOM
3
KATSAYI .BYT 4
.FLP 0.5 3A(4)
.FPL -2.3  şA(3)
.FLP 8.2
.FLP 2.5 şA(1)
.FLP 0.7 şA(0)

) Program-1: Basit bir polinomun değerini hesaplayan program.

Rutinin tek yaptığı iş, katsayı adresini polinom hesaplayan ROM rutinine iletmek.

USR( ) Fonksiyonu

Peki bu POL(x) fonksiyonunu nasıl kullanacağız? SYS komutunu kullanmamız olanaksız. X değerini rutine nasıl ileteceğiz ki? Bize gereken, SIN( ), COS( ) gibi bir fonksiyon. Neyse ki BASIC yorumlayıcısı bunu da düşünmüş. Her türlü amaca hizmet etmek için USR( ) (USeR defined: kullanıcı tarafından tanımlanmış) adlı bir fonksiyon yaratmışlar. Bu fonksiyonu istediğiniz gibi tanımlayabilirsiniz. Sadece yorumlayıcıya fonksiyonun yerini bildirmemiz gerekli. Bu fonksiyonun yerini, her zaman yaptığımız gibi düşük-yüksek değerlikli bayt formatında 785/786 ($0311/$0312) adreslerine yerleştirmeliyiz:

POKE 785,828AND255:POKET86,828/256

Artık POL( ) fonksiyonumuz tanımlanmıştır. Şu komutu girerek bir test yapalım:

PRINT USR(1)

Sonuç olarak 9.6'yı ekranda görebilirsiniz. Bakalım doğru olmuş mu:

y=0.742.548.2-2.34

Daha fazla kontrolle uğraşmak isterseniz bir de şu döngüyü kurun:

FOR 1--5 TO 5:PRINT USR():NEXT
193.2
397.1
169.6
54,9
9.6
28.1
60.4
122.7
243.2

Eğer bir BASIC programında polinomlarla uğraşacaksanız ve aynı polinomu sık sık kullanıyorsanız, bu metod size kesin bir üstünlük sağlayacaktır. Tek başına kullanılsaydı 12.5 ms süren bu rutin çoğu BASIC fonksiyonundan hızlı çalışmaktadır. USR( ) fonksiyonunun yediği zamanı da hesaba katarsak 50 ms'ye çıkan bu süre gene de çok iyidir (isterseniz BASIC programla aynı işlemi yapmayı deneyin bakalım). Polinom derecesi arttıkça ve formül karmaşıklaştıkça rutin biraz daha yavaşlayacak, fakat hiçbir zaman BASIC'in o akıllara durgunluk veren yavaşlığına düşmeyecektir. Program 1'deki örnekte de iyice pekiştirdiğimiz gibi, katsayılar x'in en yüksek üslü değerinden başlar ve x olmayan terime doğru gider. Eğer bu sırayı doğru vermezseniz doğru sonuç alamazsınız. x=1'de yaptığınız kontrol de bu hatayı ortaya çıkarmaz. En iyisi x=1 ve x=0 vererek polinomları kontrol etmektir. Eklemem gereken bir şey daha var: Eğer herhangi bir terim formülde yoksa (y=1+4x gibi) bu terimin katsayısını sıfır alarak listeye eklemelisiniz.

Faktöriyel de Alalım

Geçen sayı söz verdiğim gibi, örneklerle uğraşmaya devam ediyoruz. Bu sefer de faktöriyel alma işlemiyle uğraşalım azıcık. Çoğunuz biliyorsunuz faktöriyel alma işlemi bu şekilde tanımlanmıştır:

(k-2)x...x2x1

Ünlem işareti “faktöriyel” olarak okunur ve faktöriyel alma işlemini temsil eder. Örneğin “5 faktöriyel”i hesaplarsak:

değerini elde ederiz. Buradan sadece tam sayıların faktöriyelleri bulunabilmiş gibi görünüyor, ama matematikçiler 0 ile 1 arasındaki sayıların faktöriyelini hesaplamak için de bir polinom bulmuşlar. Bu sayede (mesela) 4.6'nın faktöriyelini rahatlıkla hesaplayabiliriz: Tabii ki ilk olarak 0.6'nın faktöriyelini hesaplayabilmeliyiz. Bunu (yeterince yaklaşmak için) 8. dereceden bir polinom olarak yazdığımızda şu katsayıları elde ederiz:

al — 1 al- -.577191652 a2- -,897056937 ad - ,918206B57 a5 - -,756704078 a6 — 482199394 -.193527818 a8 — 035868343

Program 2'ye bir göz atarsanız 0 ile 1 arasındaki sayıların faktöriyelini hesaplayan makine dili rutinini görebilirsiniz.

POLINOM —
LDA #<KATSAYI
LDY #>KATSAYI
JMP POLİNOM
$E059
KATSAYI .BYT 8
.FLP .035868343
.FPL -.193527818
.FLP .482199394
.FLP -.756704078
.FLP
.FLP
918206857
-.897056937
.FLP ,988206891
.FLP -.57719652
.FLP

Program-2: 0 ile 1 arasındaki sayıların faktöriyelini hesaplayan program.

USR fonksiyonunun 828'i göstermesini de sağladıktan sonra

PRINT USR(X) komutuyla X sayısının faktöriyelini görebilirsiniz. Örneğin:

- -

0.951350564 0.886227246

Ve tüm sayıların faktöriyelini hesaplamak
istersek kısa bir BASIC program makine dili
rutinimize eşlik edebilir. Program 3'de bu
işi yapacak olan BASIC programını görebi-
lirsiniz. Programda farkedeceğiniz gibi,
USR(X) fonksiyonunu her türlü değer ata-
malarında (Y— Yx USR(X) gibi) kullanabi-
lirsiniz.
10 INPUT "ARGUMAN"; X
20 TF X<0 OR X>33 THEN 10
30 IF X-0 THEN Y-İ: GOTO 70
40 Y-X: IF X<1 THEN Y-USR(X): GOTO 70
50 X-X-1: TF X>1 THEN Y-Y*XŞ GOTO 50
60 IF THEN Y-Y*USR(X)
70 PRİNT "FAKTOÖRİYEL -"; Y

Program-3: Program-2'yi kullanarak, tüm sayıların faktöriyelinin alınmasını sağlayan BASIC programı.

BASIC programın 20. satırı, negatif ve 30'dan büyük sayıların faktöriyelini almaya çalışmamızı engelliyor. Faktöriyel işlemi, tanım olarak sadece sıfır ve üstü için geçerlidir. 30'un üstündeki sayıların faktöriyeli, bilgisayarınızın hesaplayabileceğinden (1E38) daha büyük bir sonuç vereceğinden, program hata verecektir. Sıfır faktöriyel 1 olarak tanımlandığından, 30. satırla bu kontrolü yapıyoruz. 50. satır ise programın beynini oluşturuyor. Sayı 0 ile bir arasında bir değere ulaşana kadar Y ile çarpılıp bir eksiltiliyor. Son olarak, sayının artan kısmı birden küçükse USR(X) ile Y'yi çarpıyoruz. Y'nin değeri 70. satırda ekrana yazılıyor. Programı birkaç örnek değer için çalıştırırsak:

0 - | - | 15 — 1.32934087 2 - 2 3 - 6 05 — ,886227246

7.35 = 102087.3151 Aslında tüm faktöriyel alma rutinini makine dili kullanarak yazabiliriz. Bunun için sadece deminki BASIC programının makine dili eşdeğerini yazmamız gerekecektir. Tablo 3'te bu makine dili programının akış şemasını görebilirsiniz. Kendinizi denemeniz için bu programı yazma kısmını size bırakıyorum. Eğer sonuçlarınızı bana yollarsanız, ben de sizin konuyu ne kadar takip edebilmiş olduğunuzu anlayabileceğim. İlk sayı sonra kaç arkadaşımızın bu programı yapabilmiş olduklarını ve genel hataların (çalıştıramayanlar da bana yazsın demek oluyor bu) neler olduğunu açıklayacağım. Tabii ki böyle bir şeyi yapmam için bana yazmanız gerekiyor. Nedense sizlerle bir iletişim ağı kurmayı pek başaramadım. Bu sebeple de konuları hâlâ körü körüne seçip “Umarım birilerinin işine yarıyordur” demek zorunda kalıyorum. Yanlış anlamayın, “Su Şişesi”yle rekabet gibi bir amacım yok, Yalnızca sizin burada anlatılanlardan ne kadar yararlanabildiğinizi anlamak istiyorum.

SON

SON

Neyse, bu ayki vaazımı da verdiğime göre yazıyı bitirebilirim. Gelecek ay garip garip konularda buluşmak üzere hoşça kalın.