Jätkub arvutiprogrammide koostamise põhimõtteid ja –võtteid tutvustav artiklisari, mis algas jaanuarinumbris. Uue teemana võtame seekord vaatluse alla korduslaused, mis võimaldavad lühikese programmiga kirjeldada suure hulga tööd.
Kodutöö lahendus
Eelmise numbri koduste ülesannete lahendamiseks on kõigepealt kasulik tähele panna, et pikima ja kahe ülejäänud külje pikkuste omavaheliste suhete kontrollimiseks ei pea me välja selgitama, milline külg on pikim.
Oletame näiteks, et pikim külg on A. Siis on positiivsete A, B ja C korral juba ette teada, et B < A + C ja C < A + B ning kontrollida on vaja ainult tingimuse A < B + C kehtivust. Analoogiliselt saame arutleda ka juhul, kui pikim on kas B või C. Lisaks pole universaalse “ei ole kolmnurk” veateate väljastamisel vaja eraldi kontrollida ka küljepikkuste positiivsust, sest tingimused B < A + C ja C < A + B saavad samaaegselt kehtida ainult juhul, kui A > 0. Seega võime esimese ülesande lahenduseks kirjutada
IF A < B + C AND B < A + C AND C < A + B THENMsgBox("On kolmnurk") ELSE
MsgBox("Ei ole kolmnurk") ENDIF
ning teise omaks näiteks
IF A <= 0 THENMsgBox("Külg A ei ole positiivne") ELSEIF B <= 0 THEN
MsgBox("Külg B ei ole positiivne") ELSEIF C <= 0 THEN
MsgBox("Külg C ei ole positiivne") ELSEIF A >= B + C THEN
MsgBox("Külg A on liiga pikk") ELSEIF B >= A + C THEN
MsgBox("Külg B on liiga pikk") ELSEIF C >= A + B THEN
MsgBox("Külg C on liiga pikk") ELSE
MsgBox("On kolmnurk") ENDIF
Muidugi pole need ainuvõimalikud variandid.
Õiged lahendused saatsid Andres Vahter, Andres Võsa, Toivo Hein, Andres Mähar, Toomas Vahter, Kirstel Kivikangur, Anu Adler, Tõnu Leemet, Ingmar Aasoja, Margus Rätsepp, Allan Voog, Kert Sasi, Aira Lõhmus, Avo Joorits, Roger Mikomägi, Karl Janson, Harri Poom, Taavi Saar, Peeter Salong, Taavi Ojaveer, Neeme Vaino, Mart Vill, Riina Kukkur ja Villu Orav. Auhinna saab loosi tahtel Andres Mähar, kellel palume toimetusega ühendust võtta.
Loendajaga kordus
Kui programmid koosneks lisaks käskudele ainult valikulausetest, siis tähendaks see, et igas programmis täidetakse iga käsku ülimalt üks kord. Sel juhul jõuaksid kogu maailma programmeerijad kokku ära kasutada vahest paari moodsa arvuti jõudluse. Selleks, et arvuti täpsuse kõrval oleks kasu ka tema kiirusest, on vaja võimalust talle vähese kirjutamisega suur hulk tööd ette anda. Just selleks ongi kasulikud korduslaused, mis võimaldavad sama tegevust korduvalt täita.
Kõige lihtsam korduslause on loendajaga kordus, mille üldkuju Basicus on
FOR muutuja = esimene TO viimane STEP sammkäsud NEXT muutuja
mis tähendab, et muutuja-le omistatakse järjest väärtused esimene, esimene + samm, esimene + 2 * samm, ..., viimane ja iga omistamise järel täidetakse uuesti käsud. Lihtne näide, mis väljastab 11 teadet:
FOR C = 0 TO 100 STEP 10F = C * 9 / 5 + 32
MsgBox(C & " ºC on " & F & " ºF") NEXT C
Kui loendajaga korduses STEP-fraas puudub, võetakse vaikimisi sammuks 1. Samm võib olla ka negatiivne, korduse FOR muutuja = esimene TO viimane STEP -samm täitmisel omistatakse muutujale väärtused esimene, esimene - samm, esimene - 2 * samm, ..., viimane.
Loendajaga kordustest rääkides on kasulik meelde tuletada vana trikkülesanne, millega lapsi umbes kolmandas klassis matemaatikatunnis õnge võetakse: kui aias on post iga 10 meetri järel, siis mitu posti on 100-meetrises aias? Muidugi pole õige vastus 10, vaid (vastavalt sellele, kas aed on kahe maja vahel või keset põldu) 9 või 11. Osutub, et ka vanemad inimesed langevad sageli sama loogikavea ohvriks, isegi nii sageli, et programmeerimises on seda tüüpi vigadel eraldi nimi: neid kutsutakse — üllatus küll — aiaposti-vigadeks.
Tabeli kasutamine
Selleks, et korduslausetest rohkem kasu oleks, peaks loobuma ka andmete ükshaaval sisestamisest ja väljastamisest. Kuna kogu meie programmeerimine toimub tabelarvutussüsteemi keskkonnas, on loomulik kasutada andmete sisestamiseks ja väljastamiseks töölehte. Kõige lihtsamal juhul on sinna andmeid mugavam sisestada, rääkimata juba sellest, et töölehele saab neid välistest allikatest importida ja hilisemaks taaskasutamiseks ka salvestada.
Töölehe kasutamist on OpenOffice.org Basicu keskkonnas hea alustada omistamisest
Sheet = ThisComponent.CurrentController.ActiveSheet
mis seab muutuja Sheet osutama aktiivsele töölehele. Pärast seda on töölehe lahtrites olevaid väärtusi võimalik kasutada avaldistega
Sheet.getCellRangeByName("A2").Value
või
Sheet.getCellByPosition(0, 1).Value
Kui “käsitsi” kasutamiseks võib esimene variant mugavam tunduda, siis programmeerimiseks on üldiselt teine parem, sest sel juhul on veeru- ja reanumber kaks eraldi arvu ja nendega on Basicus lihtsam opereerida. Tuleb ainult meeles pidada, et indeksid algavad nullist, mitte ühest! Näiteks lihtne kordus, mis liidab kokku töölehe esimese veeru 20 esimeses reas olevad arvud ja salvestab tulemuse 21. ritta:
Sheet = ThisComponent.CurrentController.ActiveSheet S = 0 FOR I = 0 TO 19S = S + Sheet.getCellByPosition(0, I).Value NEXT I Sheet.getCellByPosition(0, 20).Value = S
Muidugi, selle tulemuse oleks palju lihtsamini saanud, kasutades töölehe summafunktsiooni, aga kordus- ja valikulauseid kombineerides on Basicus võimalik kirjutada palju keerulisemaid avaldisi.
Joonis 1: Õpilaste andmed töölehel
Oletame, et meil on töölehe esimeses veerus 20 esimeses reas vaheldumisi õpilase nimi ja tema hinne ja me tahame leida A-tähega algavate nimedega õpilaste keskmist hinnet (näiteks selleks, et võrrelda seda terve klassi keskmisega ja kontrollida nii Pan Kleksi hüpoteesi A-täheliste andekusest). Otse töölehel oleks seda üsna tülikas (kuigi mitte võimatu) teha, aga Basicus päris lihtne:
Sheet = ThisComponent.CurrentController.ActiveSheet S = 0 : N = 0 FOR I = 0 TO 18 STEP 2nimi = Sheet.getCellByPosition(0, I).Formula
hinne = Sheet.getCellByPosition(0, I + 1).Value
IF Left(nimi, 1) = "A" THEN
S = S + hinne : N = N + 1
ENDIF NEXT I IF N > 0 THEN
MsgBox("A-täheliste keskmine on " & S / N) ELSE
MsgBox("Pole ühtki A-tähelist") ENDIF
Eelkontrolliga kordus
Teine tähtsam korduslausete liik on eelkontrolliga kordus. Lause kujul
WHILE tingimuskäsud WEND
tähendab, et kui tingimus kehtib, täidetakse käsud; kui tingimus kehtib ka pärast seda, täidetakse jälle käsud; kui tingimus ikka veel kehtib, täidetakse uuesti käsud; jne kuni ükskord tingimus enam ei kehti.
Eelnevast järeldub, et loendajaga korduse
FOR muutuja = esimene TO viimane STEP sammkäsud NEXT muutuja
võib positiivse sammu korral üles kirjutada eelkontrolliga kordusena kujul
muutuja = esimene WHILE muutuja <= viimanekäsud
muutuja = muutuja + samm WEND
Nagu eelnevast näha, on loendajaga kordus veidi kompaktsem ja ülevaatlikum kui samaväärne eelkontrolliga kordus. Lisaks on loendajaga kordus ka veidi “lollikindlam”: loendajaga korduse keha täidetakse alati täpselt (viimane - esimene) / samm + 1 korda (kus jagamisel ümardame tulemuse allapoole), eelkontrolliga kordus aga võib jääda ka lõpmatult tööle. Näiteks eeltoodud kordus ei lõpeta oma tööd, kui programmeerija unustab korduse kehas muutuja väärtust suurendada.
Samas on eelkontrolliga korduse abil võimalik lahendada ka selliseid ülesandeid, mida loendajaga korduse abil on kas väga tülikas või suisa võimatu kirja panna. Oletame näiteks, et me tahame liita tabeli esimeses veerus kõik väärtused kuni esimese tühja lahtrini ja salvestada summa sellesse tühja lahtrisse. Loendajaga kordust ei saa sel juhul kasutada, sest me ei tea ette, kus esimene tühi lahter on, aga eelkontrolliga kordusega on lahendus üsna lihtne:
Sheet = ThisComponent.CurrentController.ActiveSheet S = 0 : I = 0 WHILE Len(Sheet.getCellByPosition(0, I).Formula) > 0S = S + Sheet.getCellByPosition(0, I).Value
I = I + 1 WEND Sheet.getCellByPosition(0, I).Value = S
Kodutöö
Esimene kodune ülesanne on täiendada keskmiste hinnete programmi nii, et lisaks A-täheliste nimedega õpilaste omale arvutatakse ja väljastatakse eraldi ka kõigi ülejäänute keskmine, et neid oleks mõnusam võrrelda.
Teine ülesanne on kirjutada programm, mis järjestaks selle õpilaste nimekirja ümber nii, et tublimad on kehvematest eespool ja võrdsete hinnetega õpilased on omavahel järjestatud nimede tähestikulises järjekorras. (Vihje: sorteerimiseks on vaja kaks korduslauset üksteise sisse panna.)
AUHINNAD paneb välja MAX 123 — DELLi müügi- ja teeninduskeskus. Seekordseks kuuauhinnaks on DELLi Bluetooth-ühendusega klaviatuur ja hiir. AASTAAUHINNAKS on DELLi sülearvuti.
Rubriigi autor AHTO TRUU (1972) on WM-data AS tarkvaraarendaja. Viimased kümme aastat tegelenud lisaks põhitööle informaatikavõistluste korraldamisega nii üldhariduskoolide õpilastele kui ka Tartu Ülikooli tudengitele. Eesti Informaatikaolümpiaadi žürii esimees, mitme rahvusvahelise võistluse žürii liige.
Siit saate endale laadida programminäited OpenDocument Spreadsheet vormingus. Nende avamiseks kasutage OpenOffice.org versiooni 2.0 või uuemat.
Faili avamisel hoiatab OpenOffice.org, et see sisaldab makrosid, mis võivad teie arvutit kahjustada. Kui te tahate failis olevaid programme ainult vaadata, võite makrode käivitamise keelata (nupp ‘Disable Macros’). Kui aga tahate programme ka käivitada proovida, peate ise otsustama, kas usaldate makrode käivitamist lubada (nupp ‘Enable Macros’) või mitte.
Programmitekstide vaatamiseks valige pärast faili avamist peamenüüst ‘Tools’ → ‘Macros’ → ‘Organize Macros’ → ‘OpenOffice.org Basic’. Avanevas dialoogiaknas valige kastis ‘Macro from’ vastavatud fail, selle all ‘Standard’, selle all omakorda soovitava programmi nimi. Programmi teksti vaatamiseks vajutage seejärel nuppu ‘Edit’, käivitamiseks aga nuppu ‘Run’.
MsgBox("On kolmnurk")
ELSE






