Ohjelmointi 1/2009, demo t091 vastauksia
1. Java-koodin toiminta, tehtävän pisteytys
Matti Välimäki
1a)
Ohjelma tulostaa rivin
1 1 2 3 5 8 13 21 34 55 89
Näin käy, koska ensin tulostetaan merkkijono "1"
ja aina muuttujan a arvo välilyönnin jälkeen.
Jokaisen kierroksen tulostuksen jälkeen lasketaan
kaksi edellistä lukua yhteen ja päivitetään niiden
summa a:n arvoksi. Näin syntyy niin sanottu Fibonaccin
lukusarja. Muuttuja d toimii säiliömuuttujana,
johon a: vanha arvo laitetaan talteen siksi aikaa, kun
sen uusi arvo lasketaan. Tämä tehdään siksi, ettei
a:n vanhempi arvo katoaisi, vaan se voidaan
laskutoimituksen jälkeen sijoittaa muuttujaan b.
// in English
The program prints the line
1 1 2 3 5 8 13 21 34 55 89
The first "1" is printed before the loop and
on every iteration thereafter the value of the
variable a is printed. After the printing on each
iteration the value of a is updated to a = a+b
meaning the previous two numbers are added together
to form the next. This creates the so called Fibonacci
sequence. The variable d works as a container
variable in which the old value of a is stored so it
isn't lost when a is updated but can be set as the
value of the variable b.
1b) Arvosteluperusteet
Lähtöpisteet = 3
Yritetty sijoittaa String = char -0.5p
Ei käsitelty erikoistapausta (pituus < 7) -0.75p
Ei käsitelty erikoismerkkejä -0.75p
Käsitelty Stringiä tai StringBuilderia taulukkona -0.5p
Yritetty käyttää primitiivimuuttujalla metodeja -0.5p
Luodaan paljon olioita -0.25p
Pienistä virheistä -0.25p/tapaus
Muista virheistä tapauskohtaisesti
1. Java-koodi
1 package tentti09;
2
3
8 public class Kayttajatunnus {
9
10
29 public static char muutaKirjain(char c) {
30 final String mitka = "åäö";
31 final String miksi = "aao";
32 char lc = Character.toLowerCase(c);
33 int i = mitka.indexOf(lc);
34 if ( i >= 0 ) return miksi.charAt(i);
35 if ( lc < 'a' ) return '1';
36 if ( lc > 'z' ) return '1';
37 return lc;
38 }
39
40
59 public static String teeTunnus(String etunimi, String sukunimi) {
60 String alku = "";
61 if ( etunimi.length() > 0 ) alku = ""+muutaKirjain(etunimi.charAt(0));
62 int pituus = Math.min(8-alku.length(),sukunimi.length());
63 StringBuilder tunnus = new StringBuilder(alku);
64 for (int i=0; i<pituus; i++)
65 tunnus.append(muutaKirjain(sukunimi.charAt(i)));
66 return tunnus.toString();
67 }
68
69
70
71
74 public static void main(String[] args) {
75
77 }
78
79 }
80
2. Matriisin transpoosi
1 package tentti09;
2
3
18 public class Transpoosi {
19
20
35 public static double[][] transpoosi(double a[][]) {
36 double[][] at = new double[a[0].length][a.length];
37 for (int ir=0; ir < a.length; ir++)
38 for (int is=0; is<a[0].length; is++)
39 at[is][ir] = a[ir][is];
40 return at;
41 }
42 }
43
2. tehtävän pisteytys
Irene Venäläinen:
Tehtävä 2
a. kohta
Vastauksessa tuli esittää yksiselitteisesti mihin kohtaan
mikäkin matriisin alkio sijoitetaan transpoosissa. Erityisesti
oli tärkeä mainita, että rivin i sarakkeen j alkio sijoitetaan
transpoosissa riville j sarakkeeseen i ja operaatio suoritetaan
kaikille matriisin alkioille.
Tehtävässä ei vähennetty pisteitä, jos ei ollut maininnut, että
n x m -matriisin alkiot tallennetaan m x n -matriisiin, jos
algoritmi oli esitelty muuten selkeästi. Tästä maininnasta sai
kuitenkin pisteitä, jos muu algoritmi ei ollut tarpeeksi selkeä.
Yleisiä virheitä:
Liian ympäripyöreä kuvaus:
"Muutetaan rivi sarakkeeksi." ei riitä, täytyy käydä läpi alkiotasolla.
"Jne." ei auta mikäli ei ole selkeästi esitetty mitä pitää tehdä.
"Esim." esimerkit oli annettu jo tehtävänannossa.
Oletettu, että matriisi on tietyn kokoinen.
Algoritmin käsite hukassa.
Oli käytetty indeksejä, muttei esitelty niitä.
b. kohta
Oikeasta esittelyrivistä 1 p
Taulukon luonti 1 p
Taulukon läpikäynti 1 p
Alkion sijoitus 0.5 p
Taulukon palautus 0.5 p
Puuttuva sulku -0.25 p
Indeksit väärin -0.5 p
taulukko.length() -0.25 p
taulukko[].length -0.25 p
Toistuvista virheistä vähennettiin vain kerran. Puuttuvista
puolipisteistä ei vähennetty pisteitä.
3. Java-kielen rakenteesta
Martti Hyvönen:
Tehtävä 3: Mallivastaukset ja arviointiperusteet
=================================================
Yleistä
Mun mielestä tehtävä meni hyvin. Kuitenkin vain yksi sai täydet
6 pistettä. Toisaalta kukaan ei jäänyt nollille, vaan huonoin
tulos oli 1 piste.
Monet olivat selittäneet asioita aivan liian laajasti.
Riittiköhän aika muihin tehtäviin? Kysymykset olivat kyllä
sellaisia, että niistä pystyi selittämään laajastikin, mutta
olisi pitänyt pystyä tiivistämään vastaus ja löytämään
oleellinen. Pitkistä vastauksista ei kuitenkaan tullut miinusta,
mutta lyhyestä ja ytimekkäästä saattoi saada plussaa :)
Tärkeintä oli osata selittää asiat. Vastausten ei siis tarvinnut
juuri alla olevien "mallivastausten" kaltaisia. Monella oli
paljon parempia vastauksia kuin alla olevat :)
a) Parametrit viedään ohjelman käynnistyskäskyn jälkeen
välilyönnillä erotettuina. Esimerkiksi ohjelmalla HelloWorld
voitaisiin antaa parametrit käynnistyksen yhteydessä
seuraavasti:
java HelloWorld parametri1 parametri2 jne...
Parametrit saadaan selville pääohjelman args-taulukosta.
Jokainen parametri on siinä oma alkionsa.
Pisteytyksestä:
0,5 pistettä sai kun osasi selittää, joko esimerkin avulla tai
ilman, että Java-ohjelmalle viedään parametreja komentorivillä
käynnistyksen yhteydessä. Parametreja voidaan syöttää useita ja
ne erotellaan toisistaan välilyönneillä.
Vähennyksiä tuli, jos sain kuvan, että parametrit tarvitsevat
edellään "-"-merkin. Näin ei siis ole.
Toiset 0,5 pistettä sai kun osasi selittää, että käyttäjän
antamat parametrit saadaan selvillä ohjelmakoodissa pääohjelman
parametrina olevasta merkkijonotaulukosta (String[]), jonka nimi
on usein args.
Yleisin vähennys taisi olla jos ei ollut muistanut mainita tuota
pääohjelmaa (main-aliohjelmaa). Niitä ei siis saada selville
mistä tahansa ohjelmakoodissa, vaan nimenomaan pääohjelman
parametrina olevasta String-taulukosta.
b) Oliotietotyyppisessä muuttujassa sijaitsee ainoastaan viite
siihen kohtaan tietokoneen muistia jossa varsinanen olion arvo/
arvot (data) sijaitsee. Alkeistietotyyppiset muuttujat
sisältävät itse arvon. (0,75p)
Erovaisuuksiahan on vaikka kuinka, joten täytyi osata löytää
oleellisin, joka on mielestäni tuo. Jos osasi selittää tuon
hyvin sai siis heti 0,75 pistettä. Jos selityksessä oli jotain
hämminkiä saattoi saada vain 0,5 pistettä tai jos oli kunnolla
hämminkiä niin saattoi tulla vain 0,25 pistettä.
Jos oli selittänyt viitteiden sijaan jostain muusta
erovaisuudesta/eroavaisuuksista sai 0,25 pistettä.
Erittäin hyvin selitetyt eroavaisuudet, mutta viiteasiaa ei
ollut kuitenkaan mainittu niin saattoi saada jopa 0,5 pistettä.
Yhtäläisyyksien keksiminen oli yllättävän vaikeaa. Yrittäneet
kuitenkin palkittiin! Paitsi jos sanoi jotain tyyliin "molemmat
ovat tietotyyppejä". Kun oli luetellut jotain järkeviä ja
oikeita yhtäläisyyksiä sai siis 0,25p. Hyväksyin mm. seuraavia:
"Molempia voi viedä aliohjelmille parametreiksi."
"Molemmat ovat tiedon väliaikaiseen tallentamiseen tarkoitettuja
ohjelmointikielen rakenteita."
"Molempia voidaan käyttää samalla tavalla muuttujan nimen avulla."
jne.
c) Täytyy muistaa, että olioita vertailtaessa ==-operaattorilla
verrataan olioiden viitteitä, eikä niiden olioiden arvoja
joihin viitteet osoittavat. Kun halutaan vertailla siis kahta
merkkijonoa, täytyy käyttää equals-metodia. (0,5p)
Että käyttää kahta ==-merkkiä, eikä =-merkkiä joka on
sijoitusoperaattori. (0,5p)
Liukulukuja vertailtaessa kannattaa ottaa huomioon, että
luvut ovat samoja tietyllä tarkkuudella. Ei saisi siis
käyttää ==-operaattoria ollenkaan. (0,25p)
Kokonaislukuja ja desimaalilukuja verrattaessa Java muuttaa
arvot samaksi tyypiksi (autoboxing) ja tämä voi aiheuttaa
ongelmia kun vertailee liuku- ja kokonaislukuja keskenään.
(0,25p)
Kaikki alkeistietotyypit eivät ole keskenään vertailtavissa
(esim boolean ja int). Huom! Lukuarvoja voi kuitenkin
vertailla keskenään. (0,25p)
Pisteitä saa kuten yllä on merkattu, mutta kuitenkin maksimissaan yhden pisteen.
d) Ylivuoto tarkoittaa muuttujan muistialueen ylittymistä (0,5p).
Ylivuoto pitää ottaa huomioon valitsemalla riittävän suuri
tietotyyppi haluamamme tiedon talletukseen. (0,5p)
Hyväksyin tietenkin myös matemaattisemman ja tarkemman
selityksen ylivuodosta, jossa selitettiin ylivuotoa
binäärilukujen yhteenlaskun avulla.
e)
i. double (tai float) mansikoidenMaaraKiloina
täytyy olla liukuluku, koska mansikoitahan voi olla vaikka
1,5kg
ii. String henkiloTunnus
täytyy olla merkkijono, sillä henkilötunnus sisältää myös
merkkejä
iii. int (short) vuosiluku
kokonaisluku ja int riittää vallanmainiosti
iv. boolean onkoKurssillaTilaa
koska kurssilla joko on tilaa tai ei ole (vaihtoehtoja
siis vain kaksi) on luentevinta käyttää boolean-tietotyyppiä
Jos oli unohtanut muuttujien nimet menetti heti 0,25 pistettä.
Jos oli unohtanut perustelut menetti 0,25 pistettä. Hyvin
perustellen hyväksyin joitakin muitaikin tietotyyppejä, kuin
ylläolevia. Jos ei kuitenkaan ollut perustellut mitään oli aika
heikoilla muissa kuin yllämainituissa tietotyypeissä. Onko
kurssilla tilaa tuli kuitenkin olla boolean, vaikka perusteli
mitä. Suurin osa olikin osannut tuon oikein.
Kaikki olivat osannut nimetä muuttujat oikein. Muutamia huonoja
nimiä oli, mutta yksittäinen huono nimi ei vaikuttanut
pisteisiin, jos tehtävä oli muuten oikein. Ääkkösten
käyttämisestä en sakottanut, vaikka sitä ei suositellakkaan.
iii-kohdassa hyväksyin myös long:n, vaikka perustelut olivatkin
vääriä :). Intin lukualue on -2147483648 - 2147483647, joten
eiköhän tuo riitä vuosilukuihin ihan hyvin. Itseasiassa short
riittäisi myös hyvin, mutta eipä sitä juurikaan taideta käyttää
kuitenkaan. short-hyväksyttiin siis tietenkin myös.
f) String on muuttumaton ja StringBuilder muuttuva merkkijono.
String:n arvoa ei siis voi muuttaa luomisen jälkeen, vaan
muuttaminen onnistuu ainoastaan luomalla uusi olio.
StringBuilderia-oliolla on sen sijaan monipuoliset metodit
merkkijonon muuttelua varten. StringBuilderia sanotaan joskus
myös dynaamiseksi merkkijonoksi.
Yhden pisteen vastaukseen riitti tällä kertaa jos osasi,
jotenkin selittää, että String:ä ei voi muuttaa ja
StringBuilderia voi. Tämä tehtävä olikin osattu erinomaisesti.
Moni oli jopa tainnut aavistaa ja laittaa vastauksen
lunttilappuunsa :)
4. Yleistä Java-tietoa
Markus Pohjola
Tehtävä 4:
==========
Tehtävässä neljä pyydettiin vastaamaan lyhyesti kolmeen
kysymykseen, jotka sisälsivät tarkentavia alakysymyksiä.
A (2p):
Hyvien koodauskäytäntöjen, muuttujien, aliohjelmien yms.
tarkoituksenmukaisen nimeämisen ja ohjelman fiksun paloittelun
lisäksi koodia on syytä kommentoida. Alla on lueteltu hyvässä
vastauksessa esiintyviä seikkoja. Täysiä pisteitä varten kaikkia
seikkoja ei ollut tarkoitus mainita, vaan vastauksen
kokonaisuudella oli merkitystä.
Mitä on kommentointi ja miksi koodia kannattaa kommentoida:
- kommentointi on koodin sekaan kirjoitettua tekstiä,
jota kääntäjä ei huomioi
- koodia on helpompi ymmärtää
- myös muut kuin ohjelman kirjoittaja ymmärtävät koodia
- koodin pariin on helpompi palata myöhemmin, koska ajan
myötä koodin toiminta mahdollisesti unohtuu
- koodia on helpompi päivittää ja käyttää uudelleen
- JavaDoc-tyylisten kommentien avulla voidaan luoda koko luokan
ja sen osien toiminnan kuvaava standardoitu API-dokumentaatio
- on olemassa erikseen yksi- ja moniriviset kommentit:
// Tämä on yksirivinen kommentti
ja
/* Tämä on kommentti,
joka on useammalla rivillä.
*/
Ei vaadittu vastaukseen, mutta on hyvä tiedostaa myös seuraavat seikat:
- kommentointi pakottaa ohjelmoijan ajattelemaan koodia uudella tavalla,
koska koodin toiminta täytyy selittää omin sanoin
- koodin toimintaa selittäessä täytyy ajatella muita kehittäjiä,
koska kommentien pitää olla hyödyllisiä ja ymmärrettäviä
Anna esimerkki Javadoc-tyylisestä kommentista aliohjelmaan, joka
tutkisi onko sana palindromi (sama sana luki sen kumminkin päin
tahansa) vai ei:
Vastauksessa täytyy tulla ilmi, että aliohjelma vastaanottaa
parametrina (@param-määre) tutkittavan sanan ja sanan
"palindromisuus" tulee jollain tavalla ilmi. Vastauksessa
odotettiin aliohjelman paluuarvon, joka kertoo sanan
palindromisuuden, esittelyä @return-määreen avulla. Vastaukseksi
hyväksyttiin kuitenkin myös tilanne, jossa aliohjelma ei
palauttanut tietoa sanan palindromisuudesta, mutta jossa
aliohjelman kommentissa oli kerrottu tuloksen tulostamisesta
ruudulle.
Alla esimerkki:
/**
* Tutkii onko parametrina annettu sana palindromi eli
* sama sana luki sen kumminpäin tahansa.
*
* @param sana tutkittava sana
* @return palauttaa true, jos tutkittava sana on palindromi. Muulloin false.
*/
Yleisiä virheitä:
- vastattu ranskalaisilla viivoilla
- sama asia kerrottu useamman kerran
- liian ylimalkainen vastaus
- aliohjelman javadoc-kommentti puuttuu tai on virheellinen
- aliohjelman sijaan annettu esimerkki luokan javadoc-kommentista
B (2p):
Mitä toistorakenteita Java-kielessä on ja miten ne eroavat
toisistaan? Anna jokaiseen mielekäs käyttökohde.
Toistorakenteen eli silmukan avulla voidaan toistaa samaa
ohjelman lohkoa useamman kerran. Javassa on kolme erilaista
silmukkaa, jotka ovat määrämuotoinen toisto eli for-silmukka,
alkuehtoinen toisto eli while-silmukka ja loppuehtoinen toisto
eli do-while-silmukka. Alla kunkin silmukan syntaksi:
for (laskurin alustus; ehto; laskurin päivitys) {
lause 1;
...
lause n;
}
while (ehto) {
lause 1;
...
lause n;
}
do {
lause 1;
...
lause n;
} while (ehto)
Silmukoiden erot toisiinsa nähden ja käyttökohteet:
for:
- käytetään kun tiedetään kuinka monta kertaa silmukka täytyy suorittaa
- esimerkiksi taulukon läpikäynti
while:
- käytetään kun ei olla varmoja tarviiko silmukkaa suorittaa kertaakaan
- esimerkiksi: while (talon sisällä on kylmä) { lämmitäTaloa(); }
do-while:
- vastaa while-silmukkaa, mutta käytetään kun tiedetään,
että silmukka suoritetaan ainakin yhden kerran
- esimerkiksi käyttäjän antaman syötteen validointi ja
syötteen antamisen toistaminen, jos syöte oli virheellinen
Yleisiä virheitä:
- toistorakenteet sekoitettu ehto-lauseisiin
- switch-case-valintarakenne esitelty toistorakenteena
- vastauksesta puuttuu mielekäs käyttökohde
- vain osa toistorakenteista esitelty
- saman aliohjelman käyttäminen useamman kerran esitelty toistorakenteena
C (2p):
Kuinka Java-koodi muuttuu suoritettavaksi ohjelmaksi? Mikä on
Java-virtuaalikoneen tehtävä? Mitä hyötyä Javan
virtuaalikoneesta on?
Tehtävän ratkaisu löytyy luentomonisteen viidennestä kappaleesta
(http://kurssit.it.jyu.fi/ITKP102/moniste/html/moniste.html#o5Lahdekoodista_prosessorille).
Täydet pisteet saa kun mainitsee seuraavat seikat:
- ensiksi luodaan java-päätteinen lähdekooditiedosto, joka on tekstidokumentti
- lähdekooditiedosto käännetään java-kääntäjällä tavukoodiksi
- kääntämisen yhteydessä tarkistetaan lähdekoodin syntaksi
Virtuaalikoneen tehtävä:
- kääntämisen yhteydessä syntynyt class-päätteinen
tavukooditiedosto suoritetaan virtuaalikoneella (JVM)
- virtuaalikone tulkkaa tavukoodia ja suorittaa sen
kohdekoneen prosessorilla
Mitä hyötyä virtuaalikoneesta on:
- sama Java-ohjelma toimii kaikissa käyttöjärjestelmissä,
joihin on asennettu virtuaalikone
- Java-ohjelmasta ei tarvitse tehdä omaa versiota kullekin
käyttöjärjestelmälle
Yleisiä virheitä:
- lähdekoodin syntaksin tarkistamista ei ole kerrottu
- virtuaalikone ja java-kääntäjä sekoitettu keskenään
- ylimalkainen vastaus; esimerkiksi: "Tehdään eka java-tiedosto,
joka muuttuu class-tiedostoksi, joka sitten käynnistetään."
5. Java-koodi
1 package tentti09;
2
3
4 import java.util.Scanner;
5
6
29 public class Rakkauslaskuri {
30
31
32 public static final String RAKKAUSSANA = "LOVES";
33
34
35
47 public static int summaaNumerot(int luku) {
48 int summa = 0;
49 int n = luku;
50 while ( n > 0 ) {
51 summa += n % 10;
52 n = n / 10;
53 }
54 return summa;
55 }
56
57
70 public static int yksiNumeroinenSumma(int luku) {
71 int tulos = luku;
72 while ( tulos > 9 ) tulos = summaaNumerot(tulos);
73 return tulos;
74 }
75
76
90 public static int[] laskeVierekkaisetYhteen(int[] a) {
91 int[] a2 = new int[a.length - 1]; for (int i = 0, j = 1; j < a.length; i++, j++) {
95 a2[i] = yksiNumeroinenSumma(a[i] + a[j]);
96 }
97 return a2;
98 }
99
100
113 public static int[] laskeKirjaimet(String sana,String jono) {
114 int[] a = new int[sana.length()];
115 for (int si = 0; si < a.length; si++) {
116 char c = sana.charAt(si);
117
118 int lkm = 0;
119 for (int ji=0; ji<jono.length(); ji++)
120 if ( jono.charAt(ji) == c ) lkm++;
121
122 a[si] = lkm;
123 }
124 return a;
125 }
126
127
140 public static int laskeRakkausprosentti(String nimi1, String nimi2) {
141 int[] luvut = laskeKirjaimet(RAKKAUSSANA, (nimi1 + nimi2).toUpperCase());
142
143 while (luvut.length > 2) {
144 luvut = laskeVierekkaisetYhteen(luvut);
145 }
146 return luvut[0]*10 + luvut[1];
147 }
148
149
153 public static void main(String[] args) {
154 System.out.println("Ohjelma laskee kahdesta nimestä rakkausprosentin.");
155 Scanner scan = new Scanner(System.in);
156 System.out.print("Anna ensimmäinen nimi: ");
157 String nimi1 = scan.nextLine();
158 System.out.print("Anna toinen nimi: ");
159 String nimi2 = scan.nextLine();
160 System.out.printf("Rakkausprosenttinne on %d!%n",
161 laskeRakkausprosentti(nimi1, nimi2));
162 }
163
164 }
165
5. tehtävän pisteytys
Ville Lahtinen
MALLIVASTAUKSET
T1: summa
T2: tulos
T3: a[i] + a[j]
T4: a2
T5: if (jono.charAt(ji) == c) lkm++;
T6: public static int laskeRakkausprosentti(String nimi1, String nimi2) {
int[] luvut = laskeKirjaimet(RAKKAUSSANA, (nimi1 + nimi2).toUpperCase());
while (luvut.length > 2) {
luvut = laskeVierekkaisetYhteen(luvut);
}
return luvut[0]*10 + luvut[1];
}
Bonustehtävä
Maksimiprosenttiin tarvittavat kirjaimet voi laskea nurinpäin
esimerkiksi seuraavasti.
9 9
/ \ / \
5 4 5
/ \ / \ / \
3 2 2 3
/ \ / \ / \ / \
2 1 1 1 2
L O V E S
Oikea määrä kirjaimia on esimerkiksi nimissä "Lasse" ja "Viola".
PISTEYTYSPERUSTEET
T1 - T5: Maksimissaan 0,4 pistettä/kohta
- Kohdissa T1, T2 ja T4 ei hyväksytty kuin täsmälleen oikea
vastaus.
- Kohdassa T3 hyväksyttiin myös vastaukset a[i] + a[i+1] ja
a[j-1] + a[j].
- Kohdassa T5 hyväksyttiin vertailuoperaattorin sijaan myös
equals-metodien käyttö, vaikka niitä ei char-muuttujille voi
käyttääkään.
T6: Maksimissaan 4 pistettä.
- Aliohjelman esittely oikein 0,5 pistettä
- Kirjaimien lukumäärän laskenta oikein 0,5 pistettä. Jos pien-
ja suuraakkosia ei huomioitu, vähennettiin 0,25 pistettä.
- laskeVierekkaisetYhteen-metodia kutsuttiin silmukassa 0,5 pistettä
- laskeVierekkaisetYhteen-metodia kutsuttiin oikea määrä (eli
silmukkaa käytiin läpi oikea määrä) 0,5 pistettä
- Silmukan ehto muodostettiin RAKKAUSSANA-vakion kirjaimien
lukumäärän perusteella 0,5 pistettä
- laskeVierekkaisetYhteen-metodin kutsu ja paluuarvon sijoitus
oikein 0,5 pistettä
- Aliohjelman palautusarvon tyyppi oikein 0,5 pistettä
- Aliohjelman palauttama arvo laskettiin oikein 0,5 pistettä.
Kohtien T1 - T6 pisteet laskettiin yhteen ja pyöristettiin 0,25
pisteen tarkkuuteen.
Bonustehtävässä hyväksyttiin kaikki vastaukset, joilla
rakkausprosentiksi tuli 99.