7.4 Arvon palauttava funktio

Yhteenveto

Tehdään kaksi aliohjelmaa. Toinen laskee suorakulmion pinta-ala ja toinen laskee suorakulmion piirin. Kun aliohjelmaa kutsutaan pääohjelmassa komennolla: piiri(3,4), niin aliohjelma palauttaa laskemansa suorakulmion piirin arvon takaisin eli 14.0, joka sijoitetaan pääohjelmassa muuttujalle p. Vastaavasti kun aliohjelmaa kutsutaan pääohjelmassa komennolla: pinta_ala(3,4), niin aliohjelma palauttaa laskemansa suorakulmion pinta-alan arvon takaisin eli 12, joka sijoitetaan pääohjelmassa muuttujalle A.


Funktio, joka palauttaa arvon

Jos aliohjelma laskee laskuja, niin voisiko aliohjelma palauttaa laskemansa arvon takaisin pääohjelmaan? Kyllä voi. Tämä johtaa funktioon eli aliohjelmaan, joka palauttaa jonkin arvon. Palautetun arvon voimme sijoittaa esimerkiksi muuttujalle pääohjelmassa. Arvon palauttaminen aliohjelmassa tapahtuu return komennolla. Funktio, joka palauttaa jonkin arvon voidaan määritellä yleisesti.

tietotyyppi aliohjelman nimi (aliohjelmaan välitettävät muuttujat) {
Komennot;
return muuttuja;
}


Huomaa, että palauttavassa funktiossa ei käytetä void määrettä, vaan funktion eteen lisätään tietotyyppi. Käytännössä funktion tietotyyppi on sama kuin palautettavan muuttujan tietotyyppi. Esimerkiksi funktio, joka laskee suorakulmion pinta-alan, voidaan kirjoittaa seuraavasti.




Ohjelma toimii seuraavasti.
  1. Pääohjelmassa kutsutaan aliohjelmaa nimeltä: pinta_ala(6,8);
  2. Aliohjelmassa muuttuja a saa arvon 6 ja muuttuja b saa arvon 8.
  3. Aliohjelma laskee paikalliselle muuttujalle: ala, arvon 6*8 = 48.
  4. Aliohjelma palauttaa takaisin pääohjelmalle aliohjelman ala-muuttujan arvon, joka on 48.
  5. Pääohjelmassa on oma paikallinen muuttuja ala, joka saa arvokseen aliohjelman palauttaman arvon eli 48. Huomaa, että voit käyttää aliohjelmassa ja pääohjelmassa samannimisiä muuttujia, koska muuttujat ovat paikallisia.
  6. Tämän jälkeen pääohjelman suoritus jatkuu ja voit vaikka tulostaa muuttujien arvot.

Kokonainen ohjelma voisi olla esimerkiksi seuraavanlainen

SANALLINEN ALGORITMI
  1. Aseta ikkunan kooksi 400 px vaakaan ja 400 px pystyyn.
  2. Aseta ikkunan taustaväriksi valkea.
  3. Aseta tekstin kooksi 30.
  4. Aseta täyttöväriksi musta.
  5. Määrittele kokonaislukumuuttuja kanta ja anna sille arvo 6.
  6. Määrittele kokonaislukumuuttuja korkeus ja anna sille arvo 8.
  7. Määrittele kokonaislukumuuttuja ala sijoita siihen arvo, joka palautuu aliohjelmasta pinta_ala. Kutsu ja välitä aliohjelmalle pinta_ala muuttujien kanta ja korkeus arvot.
  8. Tulosta muuttujan kanta arvo paikkaan (10,50).
  9. Tulosta muuttujan korkeus arvo paikkaan (10,100).
  10. Tulosta muuttujan ala arvo paikkaan (10,150).
  11. Aloita kokonaislukuarvon palauttava aliohjelma pinta_ala (Määrittele kokonaislukumuuttujat a ja b).
    1. Määrittele kokonaislukumuuttuja ala ja sijoita siihen laskutoimituksen a*b tulos.
    2. Palauta muuttujan ala arvo takaisin pääohjelmaan.

// Ohjelman tehnyt e-Oppi Oy
// 30.8.2017
void setup () {
size(600,200); // ikkunan koko
background(255); // Taustaväri valkoinen
textSize(30); // Tekstin koko
fill(0); // Tekstin väri
}

void draw() {
int kanta = 6;
int korkeus = 8;
int ala = pinta_ala(kanta,korkeus);
text("Suorakulmion kanta = "+kanta,10,50);
text("Suorakulmion korkeus = "+korkeus,10,100);
text("Suorakulmion pinta-ala = "+ala,10,150);
}

int pinta_ala(int a, int b) {
int ala = a*b;
return ala;
}

Kun ajat ohjelman, niin se näyttää tältä.



Ohjelman suoritusta voidaan havainnollistaa seuraavasti:



Aliohjelma pinta_ala(a,b) saa syötteenä arvot 6 ja 8 ja aliohjelma tulostaa tulosteena arvon 48, joka sijoitetaan pääohjelmassa muuttujalle ala.

Esimerkki: Desimaaliluvuilla laskeminen

Tehdään ohjelma, joka laskee suorakulmio piirin. Piiri lasketaan kaavalla: piiri = 2*kanta + 2*korkeus. Haluamme, että aliohjelma laskee desimaalilukuja. Kokonainen ohjelma on seuraava.

SANALLINEN ALGORITMI
  1. Aseta ikkunan kooksi 600 px vaakaan ja 200 px pystyyn.
  2. Aseta ikkunan taustaväriksi valkea.
  3. Aseta tekstin kooksi 30.
  4. Aseta täyttöväriksi musta.
  5. Määrittele desimaalilukumuuttuja kanta ja anna sille arvo 2.5.
  6. Määrittele desimaaliukumuuttuja korkeus ja anna sille arvo 3.2.
  7. Määrittele desimaalilukumuuttuja p sijoita siihen arvo, joka palautuu aliohjelmasta piiri. Kutsu ja välitä aliohjelmalle piiri muuttujien kanta ja korkeus arvot.
  8. Tulosta muuttujan kanta arvo paikkaan (10, 50).
  9. Tulosta muuttujan korkeus arvo paikkaan (10, 100).
  10. Tulosta muuttujan p arvo paikkaan (10, 150).
  11. Aloita desimaalilukuarvon palauttava aliohjelma piiri (Määrittele desimaalilukumuuttujat a ja b).
    1. Määrittele desimaalilukumuuttuja p ja sijoita siihen laskutoimituksen 2*a+2*b tulos.
    2. Palauta muuttujan p arvo takaisin pääohjelmaan.

// Ohjelman tehnyt e-Oppi Oy
// 30.8.2017
void setup () {
size(600,200); // ikkunan koko
background(255); // Taustaväri valkoinen
textSize(30); // Tekstin koko
fill(0); // Tekstin väri
}

void draw() {
float kanta = 2.5;
float korkeus = 3.2;
float p = piiri(kanta,korkeus);
text("Suorakulmion kanta = "+kanta,10,50);
text("Suorakulmion korkeus = "+korkeus,10,100);
text("Suorakulmion piiri = "+p,10,150);
}

float piiri(float a, float b) {
float p = 2*a+2*b;
return p;
}

Kun katsotaan aliohjelmaa, huomataan, että aliohjelma alkaa sanalla float eli aliohjelma palauttaa desimaalilukuarvon pääohjelmalle. Myös kaikki muuttujat on määritelty desimaalilukumuuttujiksi. Ohjelma tulostaa seuraavaa.



Aliohjelman toimintaa voidaan havainnollistaa seuraavasti.



Funktio eli aliohjelma piiri(a,b) on kuin kone, johon syötetään kannan ja korkeuden arvot, jonka jälkeen funktiokone tulostaa ulos piirin arvon, joka sitten voidaan sijoittaa pääohjelmassa muuttujalle p.

Tärkeintä on huomata, että palautettavan arvon tietotyyppi eli aliohjelman tietotyyppi on oltava sama kuin pääohjelmassa olevan muuttujan tietotyyppi, johon arvo sijoitetaan. Eli seuraava määrittely ei toimi, koska tietotyyppi on eri.

void draw() {
int kanta = 2;
int korkeus = 3;
int p = piiri(kanta,korkeus);
}

float piiri(int a, int b) {
int p = 2*a+2*b;
return p;
}

Mutta seuraava sitä vastoin toimii, koska tietotyypit ovat samat.

void draw() {
int kanta = 2;
int korkeus = 3;
float p = piiri(kanta,korkeus);
}

float piiri(int a, int b) {
int p = 2*a+2*b;
return float(p);
}

Vaikka alkuarvot ovat kokonaislukuja, niin aliohjelma voi palauttaa toisen tietotyypin muuttujan. Palautettava desimaaliluku pitää pääohjelmassa myös sijoittaa float-tyyppiselle muuttujalle.

Esimerkki: Viikonpäivä

Tee funktio nimeltään viikonpaiva(”paiva”); joka tutkii mikä viikonpäivä. Funktio antaa palautteena kommentin seuraavasti:

VIIKONPÄIVÄTULOSTUS
maanantai Maanantaina makkaraa
tiistai Tiistaina tikkaria
keskiviikko Keskiviikkona keksejä
torstai Torstaina torttuja
perjantai Perjantaina pekonia
lauantai Lauantaina lakritsia
sunnuntai Sunnuntaina suklaata

Ohjelman ratkaisu on seuraavanlainen.

SANALLINEN ALGORITMI
  1. Aseta ikkunan kooksi 600 px vaakaan ja 300 px pystyyn.
  2. Aseta ikkunan taustaväriksi valkea.
  3. Aseta täyttöväriksi musta.
  4. Aseta tekstin kooksi 30.
  5. Määrittele merkkijonomuuttuja nyt ja anna sille arvo "Lauantai".
  6. Määrittele merkkijonomuuttuja kommentti ja sijoita siihen arvo, joka palautuu aliohjelmasta viikonpaiva. Kutsu ja välitä aliohjelmalle viikonpaiva muuttujan nyt arvo.
  7. Tulosta muuttujan nyt arvo paikkaan (10,50).
  8. Tulosta muuttujan kommentti arvo paikkaan (10,100).
  9. Aloita merkkijono arvon palauttava aliohjelma viikonpaiva (Määrittele merkkijonomuuttuja paiva).
    1. Määrittele merkkijonomuuttuja vastaus.
    2. Jos muuttuja: paiva on yhtä suuri kuin "maanantai", niin silloin sijoita muuttujalle vastaus arvo "Maanantaina makkaraa".
    3. Muutoin jos muuttuja: paiva on yhtä suuri kuin "tiistai", niin silloin sijoita muuttujalle vastaus arvo "Tiistaina tikkaria".
    4. Muutoin jos muuttuja: paiva on yhtä suuri kuin "keskiviikko", niin silloin sijoita muuttujalle vastaus arvo "Keskiviikkona keksejä".
    5. Muutoin jos muuttuja: paiva on yhtä suuri kuin "torstai", niin silloin sijoita muuttujalle vastaus arvo "Torstaina torttuja".
    6. Muutoin jos muuttuja: paiva on yhtä suuri kuin "perjantai", niin silloin sijoita muuttujalle vastaus arvo "Perjantaina pekonia".
    7. Muutoin jos muuttuja: paiva on yhtä suuri kuin "lauantai", niin silloin sijoita muuttujalle vastaus arvo "Launantaina lakritsia".
    8. Muutoin jos muuttuja: paiva on yhtä suuri kuin "sunnuntai", niin silloin sijoita muuttujalle vastaus arvo "Sunnuntaina suklaata".
    9. Muutoin sijoita muuttujalle vastaus arvo "Ei ole viikonpäivä".
    10. Palauta muuttujan vastaus arvo takaisin pääohjelmaan.

// Ohjelman tehnyt e-Oppi Oy
// 30.8.2017
void setup () {
size(600,300); // Ikkunan koko
background(255); // Taustaväri valkoinen
fill(0); // Tekstin väri musta
textSize(30); // Tekstin koko 30
}

void draw () {
String nyt= "lauantai";
String kommentti = viikonpaiva(nyt);
text("Tänään on: "+nyt,10,50);
text(kommentti,10,100);
}

String viikonpaiva(String paiva){
String vastaus;
if (paiva == "maanantai") {
vastaus = "Maanantaina makkaraa";
} else if (paiva == "tiistai") {
vastaus = "Tiistaina tikkaria";
} else if (paiva == "keskiviikko") {
vastaus = "Keskiviikkona keksejä";
} else if (paiva == "torstai") {
vastaus = "Torstaina torttuja";
} else if (paiva == "perjantai") {
vastaus = "Perjantaina pekonia";
} else if (paiva == "lauantai") {
vastaus = "Lauantaina lakritsia";
} else if (paiva == "sunnuntai") {
vastaus = "Sunnuntaina suklaata";
} else {
vastaus = "Ei ole viikonpäivä";
}
return vastaus;
}


Ohjelma tulostaa seuraavaa:




Ohjelman suoritusta voidaan havainnollistaa seuraavasti.



Funktio eli aliohjelma viikonpaiva saa syötteenä arvon "lauantai" ja tulostaa ulos kommentin: "Lauantaina lakritsia". Tämä arvo sijoitetaan pääohjelmassa muuttujalle kommentti.

Toimintaperiaate samanlainen kuin aikaisemmin. Koska nyt tietona välitetään merkkijonoja, niin välitettävä tieto on laitettava lainausmerkkien (" ") sisään. Aliohjelman tietotyyppi on myös String, joka pitää laittaa heti aliohjelman alkuun. Palautettava vastaus-muuttujan arvo sijoitetaan pääohjelmassa kommentti-muuttujalle, jossa pitää olla sama tietotyyppi, kuin aliohjelmassa eli String.

Esimerkki: Arvo kirjain

Tehdään funktio arvo_kirjain(a,b); joka arpoo numeron esimerkiksi väliltä 97...122 ja muuttaa numeron sitä vastaavaksi kirjaimeksi. Numeroa 97 vastaa kirjain a, numeroa 98 vastaa kirjain b, numeroa 99 vastaa kirjain c, numeroa 100 vastaa kirjain d jne. Tehdään vain yksi arpominen eli laitetaan komento noLoop().

Ohjelman koodi on seuraava.

SANALLINEN ALGORITMI
  1. Aseta ikkunan kooksi 600 px vaakaan ja 200 px pystyyn.
  2. Aseta tekstin väriksi eli täyttöväriksi musta.
  3. Aseta tekstin kooksi 30.
  4. Laita asetus, joka toistaa void draw ()-lohkoa vain kerran.
  5. Määrittele merkki-muuttuja mika_merkki ja sijoita siihen aliohjelman arvo_kirjain palauttama arvo. Välitä aliohjelmalle pienin ja suurin numero, jonka väliseltä alueelta arvotaan kokonaisluku.
  6. Tulosta muuttujan mika_merkki arvo paikkaan (10,100).
  7. Aloita merkin palauttava aliohjelma arvo_kirjain (Määrittele kokonaislukumuuttujat a ja b).
    1. Määrittele kokonaislukumuuttuja numero ja sijoita siihen kokonaisluku, joka saadaan kun arvotaan luku väliltä [a,b]. Lukuväli tarkoittaa numeroita ASCII-taulukossa.
    2. Määrittele merkki-muuttuja nimeltään: merkki ja sijoita siihen arvo, joka tulee konversiosta, joka muuttaa arvotun numeron merkiksi.
    3. Palauta merkki-muuttujan arvo takaisin pääohjelmaan.

// Ohjelman tehnyt e-Oppi Oy
// 30.8.2017
void setup () {
size(600,200); // Ikkunan koko
fill(0); // Tekstin väri musta
textSize(30); // Tekstin koko 32
noLoop(); // Vain yksi toisto
}

void draw () {
background(255); // Tyhjennä tausta
char mika_merkki = arvo_kirjain(97,122); // Kutsutaan aliohjelmaa
text("Arvottu merkki on "+mika_merkki,10,100); // Tulostetaan merkki
}

char arvo_kirjain(int a, int b) {
int numero = round(random(a,b)); // Arvotaan kokonaisluku väliltä a…b
char merkki = char(numero); // Muuttaa numeron merkiksi
return merkki; // Palautetaan merkki
}


Kun ajat ohjelman, niin ensin pääohjelma kutsuu aliohjelmaa: arvo_kirjain(a,b), missä a:lle ja b:lle välitetään kokonaislukuarvo. Aliohjelma arpoo kokonaisluvun väliltä [a,b] ja muuttaa arvotun luvun merkiksi. Tämä merkki palautetaan takaisin pääohjelmaan, siksi aliohjelman tietotyyppi on char. Sama tietotyyppi on pääohjelmassa mika_merkki-muuttujalla. Ohjelman tulostus näyttää esimerkiksi tältä.




Ohjelman suoritusta voidaan havainnollistaa seuraavasti.



Aliohjelma arvo_kirjain(a,b) saa syötteenä luvut 97 ja 122, jonka jälkeen aliohjelma arpoo luvun tältä väliltä ja muuttaa luvun sitä vastaavaksi merkiksi ascii-taulukossa. Aliohjelma tulostaa esimerkiksi merkin 'k' ulos, joka sijoitetaan pääohjelmassa mika_merkki-nimiselle muuttujalle.

Rekursio

Aliohjelma voi kutsua myös itseään. Tehdään aluksi aliohjelma, joka piirtää ympyrän. Aliohjelmaan välitetään ympyrän keskipiste ja säde, jonka jälkeen ohjelma piirtää ympyrän ikkunan keskelle.

SANALLINEN ALGORITMI
  1. Aseta ikkunan kooksi 400 px vaakaan ja 400 px pystyyn.
  2. Aseta ikkunan taustaväriksi valkea.
  3. Aseta asetus, joka poistaa piirroskuvioista täytön.
  4. Aseta asetus, joka toistaa pääohjelmaa eli void draw ()-lohkoa vain kerran.
  5. Kutsu aliohjelmaa: ympyra. Välitä aliohjelmalle ympyrän keskipiste (200,200) ja säde 200.
  6. Aloita aliohjelma ympyra (Määrittele kokonaislukumuuttujat x, y ja r).
    1. Piirrä ympyra komennolla: ellipse(x,y,2*r,2*r);, missä ympyrän keskipiste on (x,y) ja ympyrän leveys on 2*r ja ympyrän korkeus on 2*r.

// Ohjelman tehnyt e-Oppi Oy
// 30.8.2017
void setup() {
size(400, 400); // Ikkunan koko
background(255); // Taustaväri valkoinen
noFill(); // Ei täyttöä
noLoop(); // Pääohjelma toisetaan vain kerran
}
void draw() {
ympyra(200,200,200); // Kutsutaan aliohjelmaa
}
void ympyra(float x, float y, float r) {
ellipse(x, y, r*2, r*2);
}

Ohjelma tulostaa nyt yhden ympyrän. Ympyrän keskipiste on (200, 200) ja säde on 200.



Lisätään aliohjelmaan kutsu, joka kutsuu itseään. Jotta ohjelma ei joudu ikuiseen silmukkaan, niin lisätään ohjelmaan laskuri, jonka avulla voimme määrätä kutsujen määrän.

SANALLINEN ALGORITMI
  1. Määritellään kokonaislukumuuttuja a ja annetaan sille alkuarvo 1.
  2. Aseta ikkunan kooksi 400 px vaakaan ja 400 px pystyyn.
  3. Aseta ikkunan taustaväriksi valkea.
  4. Aseta asetus, joka poistaa piirroskuvioista täytön.
  5. Aseta asetus, joka toistaa pääohjelmaa eli void draw ()-lohkoa vain kerran.
  6. Kutsu aliohjelmaa: ympyra. Välitä aliohjelmalle ympyrän keskipiste (200, 200) ja säde 200.
  7. Aloita aliohjelma ympyra (Määrittele kokonaislukumuuttujat x, y ja r).
    1. Kasvata muuttujan a arvoa yhdellä.
    2. Piirrä ympyra komennolla: ellipse(x,y,2*r,2*r);, missä ympyrän keskipiste on (x,y) ja ympyrän leveys on 2*r ja ympyrän korkeus on 2*r.
    3. Jos muuttujan a arvo on pienempi tai yhtä suuri kuin 100, niin silloin
    4. kutsu aliohjelmaa ympyra. Välitä aliohjelmalle ympyrän keskipiste (x, y) ja säde r*0.9. Nyt aliohjelma kutsuu itseään, niin että samalla säteen arvo pienenee 10 % eli menee 0.9-kertaiseksi.

// Ohjelman tehnyt e-Oppi Oy
// 30.8.2017
int a = 1;
void setup() {
size(400, 400); // Ikkunan koko
background(255); // Taustaväri valkea
noFill(); // Ei täyttöä
noLoop(); // Ei toistoa
}
void draw() {
ympyra(200, 200, 200);
}
void ympyra(float x, float y, float r) {
a++;
ellipse(x, y, r*2, r*2);
if (a <= 100) { // Sata toistoa
ympyra(x, y,r*0.9); // Aliohjelma kutsuu itseään
}
}



Koska aliohjelman kutsussa on r*0.9, kutsuttavan ympyrän säde kutistuu 10 % eli menee 0,9-kertaiseksi. Laskuri pitää huolen siitä, että piirrettäviä ympyröitä on 100 kappaletta. Jos laskuria ei olisi, niin todennäköisesti ohjelma joutuisi ikuiseen silmukkaan ja ohjelman suoritustilan jumittumiseen.