Python-harjoituksia
- Python-asennuspaketti (Anaconda). Jos sinulla ei ole Pythonia sekä numpy-, scipy- ja matplotlib-kirjastoja omalla koneellasi, hae täältä asennuspaketti!
- Pythonin dokumentaatio
Poissaolojen korvaaminen
- Tee seuraavat asiat vain jos et osallistunut harjoituksiin. Jos osallistuit, mitään muita kotitehtäviä ei ole paitsi Pythonin asentaminen omalle koneelle.
- 1. harjoitukset: tee kaikki tehtävät otsikoiden Ohjelman ajaminen, Muuttujat ja laskutoimitukset, Ohjaaminen sekä Moduulit alta.
- 2. harjoitukset: tee kaikki tehtävät otsikoiden Funktiot, Ohjelmointivirheiden korjaaminen sekä Datan käsittely alta.
- 3. harjoitukset: tee kaikki tehtävät otsikoiden Vektorit ja taulukot sekä Kuvaajat alta.
- Koosta tulokset lyhyeksi raportiksi yhteen pdf-tiedostoon. Kerro selkeästi, mitä ohjelma teki tai antoi vastaukseksi. Jos ohjelma piirtää jotakin, raportissa pitää olla kuva toimivasta ohjelmasta. Erottele raportissa selkeästi, mikä ratkaisu liittyy mihinkin tehtävään.
- Lähetä raportti sekä kaikki toimivat ohjelmatiedostot opettajalle sähköpostitse (teemu.hynninen).
- Korvaavien tehtävien viimeinen palautus on 31.5. Palautuksia ei oteta vastaan kesällä.
- Jos et ehdi tehdä korvaavia tehtäviä ajoissa, osallistu puuttuville oppitunneille, kun kurssi opetetaan uudestaan seuraavana vuonna.
Ohjelman ajaminen
- Kirjoita ohjelmakoodi tiedostoon ja tallenna se. Tai hae valmis tiedosto.
- Huom. Python-koodia voi ajaa myös komentotulkissa, mutta se ei tallenna ohjelmaa, joten emme käytä näissä harjoituksissa tätä tapaa. Python-tulkissa lukee yleensä rivin alussa esim.
>>>taiIn[0]. Älä kirjoita ohjelmaasi siihen! - Aja ohjelma. Riippuu ympäristöstä miten se tapahtuu. (Python IDLE, Spyder, Visual Studio)
- Jumiutuneen ohjelman pysäyttäminen: riippuu ympäristöstä, kokeile esim. ctrl+D, ctrl+C tai ctrl+Z
- Jos ohjelma käyttää useita tiedostoja, niiden pitää olla samassa hakemistossa.
- Jos ohjelma kirjoittaa uusia tiedostoja, ne luodaan samaan hakemistoon kuin missä ohjelma on.
- Luo aina jokaiselle ohjelmalle oma hakemistonsa, jotta niiden tiedostot eivät mene sekaisin.
- Jos et osaa käyttää hakemistoja, opettela ja kysy tarvittaessa neuvoa! Niitä on pakko osata käyttää. (Windows-ohje, Mac-ohje)
Tehtäviä
1. Tee ohjelma.
(a) Kirjoita ohjelma print('Hello world!').
(b) Luo ohjelmille oma kansio nimeltä "alkupython".
(c) Tallenna ohjelmasi tähän kansioon python-tiedostona nimeltä "hello.py".
(d) Aja ohjelma. Tarkista että näytölle ilmestyy teksti "Hello world!"
ohje
- Varmista että käytät Python 3:a etkä Python 2:ta. Jossakin pitäisi lukea joko
Python 2.x.xtaiPython 3.x.x. Pitää olla kolmonen. Jos ei ole, olet käynnistänyt vanhan version, joka toimii eri lailla kuin mitä näissä tehtävissä tehdään. - Jos käytät Python IDLE -ympäristöä:
- Etsi valikosta File > New File.
- Kirjoita ohjelma ikkunaan, jossa ei ole tulkin tunnusta
>>>. - Etsi valikosta File > Save As.
- Luo tallennusvalikossa uusi kansio ja anna tiedostolle oikea nimi.
- Valitse valikosta Run > Run Module.
- Tekstin pitäisi ilmestyä siihen toiseen ikkunaan, jossa on
>>>.
- Jos käytät Spyderiä:
- Kirjoita ohjelma vasemmanpuoleiseen ikkunaan, jossa todennäköisesti lukee
Spyder Editor. - Paina disketin kuvaa.
- Luo tallennusvalikossa uusi kansio ja anna tiedostolle oikea nimi.
- Paina play-napin kuvaa.
- Tekstin pitäisi ilmestyä alaoikealla olevaan konsoliin.
- Kirjoita ohjelma vasemmanpuoleiseen ikkunaan, jossa todennäköisesti lukee
- Jos käytät Visual Studio Codea:
- Etsi valikosta File > New File.
- Tarvittaessa valitse kieleksi Python.
- Kirjoita ohjelma ikkunaan.
- Etsi valikosta File > Save As.
- Luo tallennusvalikossa uusi kansio ja anna tiedostolle oikea nimi.
- Paina play-napin kuvaa.
- Tekstin pitäisi ilmestyä alla olevaan terminaaliin.
- Jos käytät mitä tahansa tekstieditoria ja komentotulkkia.
- Etsi valikosta File > New File.
- Kirjoita ohjelma.
- Etsi valikosta File > Save As.
- Luo tallennusvalikossa uusi kansio ja anna tiedostolle oikea nimi.
- Siirry komentotulkissa oikeaan hakemistoon.
- Anna komento
python hello.py. - Tekstin pitäisi ilmestyä komentotulkkiin.
2. Aja valmis ohjelma.
(a) Hae tiedosto kuvio.py.
(b) Tallenna tiedosto äsken tekemääsi hakemistoon "alkupython".
(c) Avaa tiedosto.
(d) Aja ohjelma.
ohje
- Oletusarvoisesti tiedosto menee kansioon nimeltä "Ladatut tiedostot", "Downloads" tms. Ei ole mitään järkeä ajaa ohjelmia siellä. Siispä valitse heti tiedostoa hakiessasi oikea hakemisto ("Save Downloaded File As") tai siirrä se itse oikeaan hakemistoon.
- Etsi valikosta File > Open tai paina kansion kuvaa. Riippuu ympäristöstäsi, mistä tiedosto avataan.
- Etsi oikea hakemisto ja sieltä oikea tiedosto.
- Ohjelmakoodin pitäisi ilmestyä näkyviin. Se alkaa
# Tämä ohjelma .... Ei tarvitse ymmärtää koodia. - Aja ohjelma kuten edellisessä tehtävässä. Ohjelman pitäisi piirtää jotakin.
3. Python fysiikan kurssilla.
(a) Luo tietokoneellesi johonkin sopivaan paikkaan hakemisto "fysiikka". Luo sen sisään hakemisto "mekaniikka". Luo sen sisään hakemisto "tutkimustehtävät" tai "tutkimustehtavat". Luo sen sisään hakemisto "t2".
(b) Mene Mekaniikan perusteiden kotisivulle ja etsi sieltä mekaniikan toisen tutkimustehtävän aineisto. Siihen kuuluu kaksi .py- ja yksi .txt-tiedosto. Lataa kaikki tiedostot ja tallenna ne äsken luomaasi hakemistoon "t2".
(c) Lue tiedostosta readme.txt, mikä ohjelma tämä on ja miten sitä ohjataan.
(d) Luo simulaatio, jossa aluksi 3.0 kg kappale liikkuu y-suuntaan tasaisella nopeudella 1.0 m/s. Räjäytä jollakin sopivalla ajan hetkellä kappale kahteen osaan, joiden massat ovat 2.0 kg ja 1.0 kg.
(e) Etsi simulaation luomat tiedostot. Katso, mitä sait. Lisää jokaisen tiedoston nimen alkuun tunniste "rajahdys_2kg_1kg_".
(f) Luo simulaatio, jossa 3.0 kg kappale heitetään ylöspäin alkunopeudella 10.0 m/s painovoiman vetäsessä sitä alaspäin. Katso, mitä simulaatio nyt loi. Lisää uusien tiedostojen alkuun tunniste "heitto_3kg_10ms_". Varmista, että kummankin simulaation luoma data on tallessa ja tunnistat ne.
ohje
- Tämä on oikea tehtävä, joka tulee fysiikan kurssilla vastaan. Kannattaa siis oikeasti yrittää ymmärtää, mitä ohjelma tekee ja miten sitä käytetään.
- Tämä ei ole ainoa fysiikan tehtävä, johon liittyy simulaatio. Niissä on hyvin usein tiedosto, jonka nimi on parametrit.py. Ohjelmia ei siis voi ajaa samassa hakemistossa, koska hakemistossa ei voi olla useita samannimisiä tiedostoja. Tee jokaiselle tehtävälle aina oma hakemisto!
- Ohjelman toiminta on selitetty readme.txt-tiedostossa. Siellä sanotaan suoraan
- mikä tiedosto pitää ajaa, jotta simulaatio toteutuu
- mitä tiedostoa pitää muuttaa, jotta simulaation sisältö muuttuu
- mitä eri muuttujien arvot merkitsevät.
- Readme-tiedoston lopussa on annettu muutama esimerkki. Ne eivät kuitenkaan ole kattavat vaan aina on syytä miettiä jokaisen muuttujan kohdalla, onko sen arvo järkevä.
- Simulaation pitäisi tallentaa kuvaajia samaan hakemistoon "t2".
- Simulaation pitäisi myös näyttää animaatio. Kuitenkin jos käytät Spyderiä, tämä ei todennäköisesti onnistu suoraan. Jotta näet animaation, sinun pitää mennä Spyderin asetuksiin ja etsiä sieltä kohta IPython console > Graphics > Backend. Kokeile siinä esimerkiksi vaihtoehtoa Automatic.
- Jos et nimeä simulaation luomia tiedostoja uudestaan, uuden simulaation ajaminen tuhoaa vanhat tulokset. Siksi tiedostot pitää aina joko nimetä helposti ymmärrettävillä nimillä tai siirtää johonkin uuteen alihakemistoon.
ratkaisu
- Muokkaa tiedostoa parametrit.py ja tallenna se.
- Aja tiedosto raketti.py. Älä kuitenkaan tee siihen mitään muutoksia.
- Alla esimerkkejä sopivista parametrien arvoista.
(a)
M_ISO = 2.0
M_PIENI = 1.0
N_PIENET = 1
VY_ALKU = 1.0
T_RAJAHDYS = 1.0
G = 0
(b)
M_ISO = 2.0
M_PIENI = 1.0
N_PIENET = 1
VY_ALKU = 10.0
T_RAJAHDYS = -1.0
G = 9.8
Muuttujat ja laskutoimitukset
- muuttujan määrittely:
a = 5 - vertailu (yhtäsuuruus):
a == 5 - vertailu (epäyhtälö):
a < 5 - arvon muuttaminen:
a += 1 - kokonaisluvut (integer, int):
luku = 1 - liukuluvut eli reaaliluvut (floating point number, float):
luku = 1.5 - summa \(5 + 2\):
5+2 - erotus \(5 − 2\):
5-2 - tulo \(5 \times 2\):
5*2 - osamäärä \(\frac{5}{2}\):
5/2(tulos on 2.5) - osamäärän kokonaislukuosa \(\frac{5}{2} = 2, \text{ jää } 1\):
5//2(tulos on 2) - jakojäännös \(\frac{5}{2} = 2, \text{ jää } 1\):
5%2(tulos on 1) - potenssi \(5^2\):
5**2 - tulostaminen ruudulle:
print(a) - kommentti:
# muista kommentoida! - merkkijonot eli teksti (string, str):
testi = 'ok'taitesti = "ok" - totuusarvot (boolean):
on_ok = TruetaiFalse - listat (list):
jutut = [1, 2, 3] - tyhjä lista:
jutut = []taijutut = list() - listojen yhdistäminen:
jutut = [1,2] + ['kolme'] - listaan lisääminen:
jutut += [4]taijutut.append(4) - listan alkioon viittaaminen:
jutut[0] - Huom. indeksointi alkaa nollasta ja negatiiviset indeksit laskevat lopusta alkuun.
- usean alkion poimiminen:
jutut[0:3] - listan alkion muuttaminen:
jutut[0] = 5 - listan alkion poistaminen:
a = jutut.pop(1) - listan pituus (length, len):
len(list) - sanakirjat (dictionary, dict):
tiedot = {'nimi': 'Albert', 'ika': 55} - sanakirjan alkioon viittaminen:
tiedot['nimi'] - joukot (set):
alkiot = {1, 2, 3} - tuplet:
monta = 1, 2, 3 - tyhjä, ei arvoa:
None - muunto kokonaisluvuksi:
int(muuttuja) - muunto reaaliluvuksi:
float(muuttuja) - muunto merkkijonoksi:
str(muuttuja)
Tehtäviä
1. Muuttujia ja laskutoimituksia
Kirjoita ohjelma, joka tekee seuraavat asiat.
(a) Luo muuttujan a, tallentaa siihen laskun \( 2^8 \) tuloksen ja tulostaa sen näytölle.
(b) Luo muuttujan toinen, tallentaa siihen laskun \( 2(a + 5) \) tuloksen ja tulostaa sen näytölle.
(c) Luo muuttujan reaaliluku, tallentaa siihen jakolaskun \( \frac{\mathtt{toinen}}{a} \) ja tulostaa sen näytölle.
(d) Luo muuttujan kokonaisluku, tallentaa siihen jakolaskun \( \frac{\mathtt{toinen}}{a} \) kokonaislukuosan ja tulostaa sen näytölle.
(e) Luo muuttujan jaannos, tallentaa siihen jakolaskun \( \frac{\mathtt{toinen}}{a} \) jakojäännöksen ja tulostaa sen näytölle.
(f) Luo muuttujan summa1, tallentaa siihen muuttujien a ja jaannos summan ja tulostaa sen näytölle.
(f) Luo muuttujan summa2, vaihtaa muuttujien a ja jaannos tyypin luvusta merkkijonoksi ja tallentaa näiden summan uuteen muuttujaan sekä tulostaa sen näytölle.
1. vihje
- Peruslaskut on selitetty yllä kohdassa Muuttujat ja laskutoimitukset.
- Huom. erityisesti potenssi ei ole
2^8kuten monessa kielessä. Tuollainen komento on olemassa, mutta se on bittikohtainen eksklusiivinen tai (bitwise XOR). Jos et tiedä mitä se tarkoittaa, et halua koskaan kirjoittaa tuota merkkiä Pythoniin.
2. vihje
- Kertolasku pitää aina merkitä näkyviin. Ei voi kirjoittaa
2avaan täytyy kirjoittaa2*a. - Muuttujat tallennetaan yhdellä yhtäsuuruusmerkillä:
a = .... - Kolme viimeistä kohtaa menevät muuten ihan samalla tavalla, mutta niissä käytetään erilaista symbolia jakomerkkinä:
/,//tai%. - Muunnos merkkijonoksi onnistuu komennolla
a = str(a).
oikea tulos
(a) 256
(b) 522
(c) 2.0390625
(d) 2
(e) 10
(f) 266
(g) '25610'
ratkaisu
# (a)
a = 2**8
print(a)
# (b)
toinen = 2*(a+5)
print(toinen)
# (c)
reaaliluku = toinen / a
print(reaaliluku)
# (d)
kokonaisluku = toinen // a
print(kokonaisluku)
# (e)
jaannos = toinen % a
print(jaannos)
# (f)
summa1 = a + jaannos
print(summa1)
# (g)
a = str(a)
jaannos = str(jaannos)
summa2 = a + jaannos
print(summa2)
2. Vertailuja
Kirjoita ohjelma, joka tekee seuraavat asiat.
(a) Testaa onko \( 4-1 = 3 \) totta ja tulostaa saadun tuloksen.
(b) Tallentaa laskun \( 0.4 - 0.1 \) muuttujaan tulos,
testaa onko se yhtä suuri kuin, pienempi kuin tai suurempi kuin \( 0.3 \)
ja tulostaa vertailujen tulokset.
(c) Tulostaa muuttujan tulos arvon.
(d) Tapahtuiko jotakin odottamatonta?
1. vihje
- Muuttujan tallennus on yksi on-merkki (
=), ja yhtäsuuruuden vertailu on kaksi merkkiä (==). Ts.a = 1tallentaa muuttujaan arvon 1 kun taasa == 1kysyy ohjelmalta, onko muutujan arvo 1. - Jos kirjoitat vain
4-1 == 3, ohjelma kyllä tekee testin, mutta ei kerro mitä siinä kävi. Jotta näkisit tuloksen, käytä komentoaprint(). - Muuttujiin voi tallentaa melkein mitä vain, myös vertailujen tuloksia. Voit siis kirjoittaa
muuttuja = (1 == 2), jolloin muuttujaan tallentuu totuusarvoFalse.
2. vihje
- Näet vertailun lopputuloksen kirjoittamalla
print( 4-3 == 1 ). - Kohdassa (a) ei pitäisi käydä mitään kummallista, mutta kohdassa (b) pitäisi.
- Kohta (c) ehkä antaa hiukan vihiä, miksi näin käy.
oikea tulos
(a) Ohjelman mukaan \( 4-1 = 3 \) on totta.
(b) Ohjelman mukaan \( 0.4-0.1 > 0.3 \) on totta ja muut tapaukset epätosia. (Tämähän on oikeasti väärin.)
(c) Ohjelman mukaan \( 0.4-0.1 = 0.30000000000000004\). (Tämähän on oikeasti väärin.)
(d) Kyllä. Ohjelma tekee pyöristysvirheen reaalilukujen käsittelyssä.
ratkaisu
# (a)
print(4-1 == 3)
# (b)
tulos = 0.4 - 0.1
print(tulos == 0.3)
print(tulos < 0.3)
print(tulos > 0.3)
# (c)
print(tulos)
3. Listoja
Kirjoita ohjelma, joka tekee seuraavat asiat ja tulostaa joka vaiheessa, mitä muuttujiin on tallennettu.
(a) Luo listan [1,2,3,4,5] ja tallentaa sen muuttujaan asioita.
(b) Lisää listan loppuun alkion 10.
(c) Laskee listan alkioiden lukumäärän ja vaihtaa listan toisen alkion tähän lukuun.
(d) Poimii listan neljä viimeistä alkiota ja tallentaa ne muuttujaan loppu.
(e) Poistaa tämän uuden listan kolmannen alkion.
(f) Laskee listaan loppu jäljelle jääneiden alkioiden summan ja lisää sen listan alkuun.
(g) Yhdistaa listat niin, että listan asioita alkiot tulevat ensin, ja tallentaa tuloksen muuttujaan kimpassa.
1. vihje
- Listojen kanssa käytetään hakasulkeita. Katso ylhäältä mallia.
- Muista, että indeksointi alkaa nollasta! Ensimmäinen alkio on
asioita[0], toinen onasioita[1]jne. - Plus-merkki yhdistää listat laittamalla ne peräkkäin annetussa järjestyksessä.
- Voit tulostaa monta listaa yhdellä komennolla:
print(asioita, loppu).
2. vihje
- Kympin lisääminen loppuun onnistuu esim. näin
asioita += [10]. - Neljä viimeistä alkiota ovat
asioita[-4:]. Indeksi -4 tarkoittaa neljänneksi viimeistä. - Kolmannen alkion poistaa
loppu.pop(2). Indeksi 2 tarkoittaa kolmatta, koska ensimmäinen on indeksillä 0. - Listojen alkioita voi laskea yhteen, jos ne ovat lukuja:
loppu[0] + loppu[1]. - Komento
asioita + [1]lisää loppuun. Komento[1] + asioitalisää alkuun. - Listan alkioiden määrän kertoo komento
len(asioita).
oikea tulos
(a) asioita: [1,2,3,4,5]
(b) asioita: [1,2,3,4,5,10]
(c) asioita: [1,6,3,4,5,10]
(d) asioita: [1,6,3,4,5,10], loppu: [3,4,5,10]
(e) asioita: [1,6,3,4,5,10], loppu: [3,4,10]
(f) asioita: [1,6,3,4,5,10], loppu: [17,3,4,10]
(g) asioita: [1,6,3,4,5,10], loppu: [17,3,4,10], kimpassa: [1,6,3,4,5,10,17,3,4,10]
ratkaisu
# (a)
asioita = [1,2,3,4,5]
print(asioita)
# (b)
asioita += [10]
print(asioita)
# (c)
asioita[1] = len(asioita)
print(asioita)
# (d)
loppu = asioita[-4:]
print(asioita, loppu)
# (e)
loppu.pop(2)
print(asioita, loppu)
# (f)
summa = loppu[0] + loppu[1] + loppu[2]
loppu = [summa] + loppu
print(asioita, loppu)
# (g)
kimpassa = asioita + loppu
print(asioita, loppu, kimpassa)
Ohjaaminen
- Ohjauskomennot päättyvät aina kaksoispisteeseen:
if x == 0: - Lohkot erotellaan sisentämällä.
- Jos niin - muuten jos - muuten:
if x > 0:
print('x on positiivinen')
elif x < 0:
print('x on negatiivinen')
else:
print('x on nolla')
- ei:
not - ja:
and - tai:
or - tyhjä lohko:
pass - toisto (tietyillä arvoilla):
for i in [1,10,100]:
print(i)
for i in range(10):
print(i)
- Huom.
range(N)toimii kuin lista, jossa on alkiot [0,1,...,N-1]. - toisto (ehdon ollessa voimassa):
while i < 100:
i += 1
print(i)
- toiston lopettaminen kesken:
break
Tehtäviä
1. Ehdot
Kirjoita ohjelma, joka tekee seuraavat:
(a) Määrittele muuttuja ika, jolla on jokin numeroarvo. Kirjoita ohjelma, joka tulostaa iästä riippuvan viestin seuraavasti:
- Alle 18: "Olet alaikäinen."
- 18–64: "Olet aikuinen."
- 65 tai enemmän: "Olet eläkelainen."
Testaa ohjelmaa!
(b) Määrittele muuttuja sade, jolla on joko True tai False arvo. Jos sade on totta, ohjelman tulee tulostaa "Muista sateenvarjo!". Muussa tapauksessa tulostetaan "Ei tarvitse sateenvarjoa."
1. vihje
- Ehtolauseet tehdään
if-elif-else-rakenteella. Lisätietoa löydät täältä. - Muista sisentää jokainen ehdollinen lohko.
- Muista myös, että jokaisen samaan ketjuun kuuluvan ohjauskomennon
if,elifjaelsepitää olla sisennetty täsmälleen yhtä paljon.
2. vihje
- Boolean-arvo True tarkoittaa totta ja False epätotta.
- Kun muuttujalla on tällainen arvo, voit toki testata sitä kirjoittamalla
if sade == True:, mutta ei tarvitse vaan voit kirjoittaa lyhyestiif sade:
oikea tulos
(a) Jos ika = 20, tulostus on: "Olet aikuinen."
(b) Jos sade = True, tulostus on: "Muista sateenvarjo!"
ratkaisu
# (a)
ika = 20
if ika < 18:
print("Olet alaikäinen.")
elif ika < 65:
print("Olet aikuinen.")
else:
print("Olet eläkeläinen.")
# (b)
sade = True
if sade:
print("Muista sateenvarjo!")
else:
print("Ei tarvitse sateenvarjoa.")
2. Silmukka
Kirjoita ohjelma, joka tekee seuraavat:
(a) Tulostaa luvut 1–10 käyttäen for-silmukkaa.
(b) Laskee ja tulostaa lukujen 1–10 summan.
1. vihje
- Silmukoita kuten
forkäytetään toistoon. Lisätietoa löydät täältä. - Summaa varten määrittele ensin muuttuja, johon tallennat laskun välivaiheet. Aseta sen arvo aluksi nollaan, esim.
summa = 0.
2. vihje
-
range(A,B)tuottaa luvut väliltä A, ..., B-1.
oikea tulos
(a)
1
2
3
4
5
6
7
8
9
10
(b) 55
ratkaisu
# (a)
for i in range(1, 11):
print(i)
# (b)
summa = 0
for i in range(1, 11):
summa += i
print(summa)
3. Kivi-paperi-sakset
Lataa ja tallenna ohjelma leikki.py.
Kokeile ajaa ohjelma. Se pyytää sinua valitsemaan kiven, paperin tai sakset. Kirjoita siis ohjelman pyynnön perään k, p tai s ja paina enter. Kun haluat lopettaa, kirjoita ohjelmalle jotakin muuta tai sulje ohjelma. Ohjelman lopettaminen tapahtuu eri ympäristöissä hieman eri tavoin. Siihen voi olla esim. stop-nappi, roskakorin kuva tai X-nappi. Myös näppäinyhdistelmä ctrl+C, ctrl+D tai ctrl+Z saattaa toimia.
(a) Ohjelma ei tiedä, kuka voittaa.
Pelaajan valitsema liike on tallennettu muuttujaan pelaajan_valinta,
johon on tallennettu joko "k", "p" tai "s".
Vastaavasti ohjelman valitsema liike on muuttujass ohjelman_valinta.
Lisää ohjelmaan tarvittavat loogiset ehdot, joilla ohjelma pystyy päättelemään,
kumpi voitti vai tuliko tasapeli.
Laita ohjelma tulostamaan jokaisessa tilanteessa oikein
"Minä voitin", "Sinä voitit" tai "Tasapeli".
Oikea paikka näille ehdoille on siellä, missä koodin kommenteissa lukee "TEHTÄVÄ A".
(b) Ohjelmaan on määritelty valmiiksi lista voitot, jossa on kaksi nollaa.
Muokkaa ohjelmaa niin, että aina kun pelaaja voittaa, listan ensimmäinen alkio kasvaa yhdellä,
ja kun ohjelma voittaa, listan toinen alkio kasvaa yhdellä. Laita ohjelma tulostamaan pistetilanne jokaisen pelin jälkeen.
1. vihje
- On olemassa yhteensä 9 erilaista tapaa pelata kivi-paperi-sakset, sillä kumpikin pelaaja voi valita yhden kolmesta vaihtoehdosta.
- Tilanteen, jossa vaikkapa pelaaja valitsi paperin ja ohjelma kiven, tunnistaa komento
if (pelaajan_valinta == 'p') and (ohjelman_valinta == 'k'):. - Voit käydä läpi kaikki 9 tilannetta yksi kerrallaan, mutta ei tarvitse, koska jotkin tilanteet voi hoitaa kerralla esim. sopivalla muuten-komennolla
else:. - Voittolistan ensimmäistä alkiota voi kasvattaa komennolla
voitot[0] += 1. Muista että indeksit lähtevät nollasta.
2. vihje
- Edellisessä vihjeessä mainitun tilanteen voisi hoitaa kokonaan komennolla:
if (pelaajan_valinta == 'p') and (ohjelman_valinta == 'k'):
print("sinä voitit!")
voitot[0] += 1
- Voitot voi tulostaa esimerkiksi näin:
print("Tilanne on: minä ", voitot[1], " - ", voitot[0], " sinä")
ratkaisu
Korvaa rivi 84 esimerkiksi tällä koodilla. Ole tarkkka, että sisennys on sama kuin mitä rivillä 84 oli alunperin!
# käydään ensin läpi tapaukset, joissa
# pelaaja voittaa
if (ohjelman_valinta == "k" and pelaajan_valinta == "p") or \
(ohjelman_valinta == "p" and pelaajan_valinta == "s") or \
(ohjelman_valinta == "s" and pelaajan_valinta == "k"):
print("Sinä voitit!")
voitot[0] += 1
# jos valittiin samalla tavalla, tuli tasapeli
elif ohjelman_valinta == pelaajan_valinta:
print("Tasapeli!")
# muissa tapauksissa ohjelma voittaa, eikä
# niitä tarvitse käydä läpi erikseen
else:
print("Minä voitin!")
voitot[1] += 1
print("Tilanne: minä ", voitot[1], " - ", voitot[0], " sinä")
4. Kertoma
Kirjoita ohjelma, joka tekee seuraavat asiat. Testaa sen toimintaa.
- Määrittelee muuttujan
Nja antaa sille jonkin positiivisen kokonaislukuarvon. - Antaa muuttujalle
isilmukassa arvot 2, ..., N. - Laskee näiden arvojen tulon ja tulostaa lopuksi "kertoma = " sekä saadun tuloksen.
- Lopettaa silmukan kesken, jos tulo ylittää miljoonan.
1. vihje
- Tässä voi käyttää
fortaiwhile-silmukkaa. - Malliratkaisussa käytetään
for-komentoa. Se muuttaa muuttujan arvoa automaattisesti eikä jää vahingossa ikuiseen silmukkaan. - Komento
range(A,B)antaa luvut A, ..., B-1. - Tulostaminen onnistuu erottelemalla asiat pilkulla:
print("muuttuja = ", muuttuja). - Voit myös muuttaa kaiken tekstiksi:
print("muuttuja = "+str(muuttuja)). - Silmukan voi lopettaa kesken laittamalla sen sisään sopivan ehtolauseen ja sen sisään komennon
break.
2. vihje
- Määrittele ennen silmukkaa muuttuja
tulo, aseta se aluksi arvoon 1, ja kerro se silmukassa kullakini:n arvolla. - Toistot menevät oikein komennolla
for i in range(2,N+1): - Kaikki toistettavat asiat pitää sisentää samalle syvyydelle.
- Lopetusehtoon toimii
if tulo > 10**6:. - Kun jos-lause on silmukassa, itse ehto pitää sisentää yhtä paljon kuin kaikki muukin silmukassa oleva, ja sille ehdolliset komennot pitää sisentää vielä syvemmälle.
oikea tulos
Jos esim. N = 5 tulos on 120. Jos N > 9, tulos on aina 3628800.
ratkaisu
tulo = 1
N = 5
for i in range(2,N+1):
tulo *= i
if tulo > 10**6:
break
print("kertoma = ", tulo)
Moduulit
- Pythonin moduulit
- Moduulit ladataan avainsanalla
import - koko moduulin lataaminen:
import math
print(math.pi)
- lataaminen ja nimeäminen
import math as m
print(m.pi)
- valikoitu lataaminen
from math import pi
print(pi)
Tehtäviä
1. Matematiikkaa
Tutustu moduulin math dokumentaatioon.
Kirjoita ohjelma, joka laskee ja tulostaa numeerisen likiarvon näille lausekkeille.
(a) \[ \sqrt{5} \]
(b) \[ \sin \frac{\pi}{3} \]
(c) \[ \cos 40^\circ \]
(d) \[ e^\pi \]
(e) \[ \ln 10 \]
(f) \[ \arctan \frac{2}{5} \]
(g) \[ \binom{8}{3} \]
(h) \[ \sum_{i = 1}^{123} i \]
1. vihje
- Hyödyllisiä komentoja voisivat olla
sqrt,sin,pi,cos,degrees,radians,exp,log,atan,combjafsum. - Numerot 1, ..., 123 saat komennolla
range(1,124).
2. vihje
- Kuten aina, ohjelma ei näytä laskujen tuloksia ellei sitä erikseen pyydetä komennolla
print(). - Ole tarkkana, mihin suuntaan muunnat kulmat. Kuten dokumentaatiossa sanotaan, komento
degreesmuuntaa radiaanit asteiksi. Mutta sitä ei nyt haluta, koska trigonometriset funktiot vaativat nimenomaan radiaaneja, joka on oikea kulman yksikkö.
oikea tulos
(a) 2.23606797749979
(b) 0.8660254037844386
(c) 0.7660444431189781
(d) 23.140692632779267
(e) 2.302585092994046
(f) 0.3805063771123649
(g) 56
(h) 7626
ratkaisu
import math
# (a)
print( math.sqrt( 5 ) )
# (b)
print( math.sin( math.pi/3 ) )
# (c)
print( math.cos( math.radians(40) ) )
# (d)
print( math.exp( math.pi ) )
# (e)
print( math.log( 10 ) )
# (f)
print( math.atan( 2/5 ) )
# (g)
print( math.comb( 8, 3 ) )
# (h)
print( math.fsum( range(1, 124) ) )
2. Peli
Lataa ja tallenna ohjelma peli.py.
Kokeile ajaa ohjelma. Se luo yksinkertaisen pelin graafiseen ikkunaan.
Pelissä ohjaat nuolinäppäimillä mustaa ruutua, joka ei saa osua punaisiin
ruutuihin. Punaiset ruudut kuitenkin ovat kaikki pelialueen vasemmassa reunassa, mikä on aika tylsää.
Tehtävänä on saada ruudut ilmestymään satunnaisesti eri puolille pelialuetta.
Sitä varten on syytä tutustua moduulin random dokumentaatioon.
(a) Muuta esteitä luovaa koodia niin, että esteiden lähtöpisteen x-koordinaatti
on satunnainen. Koordinaatin pitää olla kokonaisluku.
Pienin sallittu arvo on 0 ja suurin on LEVEYS-1.
Oikea paikka tälle on siellä, missä koodin kommenteissa lukee "TEHTÄVÄ A"
(funktion luo_este() sisällä).
(b) Muokkaa ohjelmaa niin, että esteet voivat tulla myös alhaalta ylös.
(c) Testaa ohjelmaa. Voit tehdä siihen muitakin muutoksia ja katsoa, mitä tapahtuu.
1. vihje
- Satunnaisen kokonaisluvun arpomiseen sopii funktio
random.randint. - Kohdassa (a) koodia pitää muuttaa sillä rivillä, jolla lukee
alkupiste_x = 0. Korvaa nolla satunnaisluvulla. - Kohdassa (b) voit arpoa satunnaisesti esimerkiksi jommankumman luvuista 0 ja 1 ja kirjoittaa sitten ehtolauseen, joka nollan tapauksessa luo esteen pelialueen yläreunaan ja ykkösen tapauksessa alareunaan.
2. vihje
- Muista ladata moduuli
random. Sen voi tehdä jo tiedoston alussa. - Sopiva komento on
alkupiste_x = random.randint(0,LEVEYS-1). - Kohdassa (b), jos laitat esteen tulemaan alhaalta, sinun pitää tehdä muutokset
alkupiste_y = KORKEUSsekäysuunta = -1.
ratkaisu
Laita tiedoston alkuun import random.
(a) Korvaa rivi alkupiste_x = 0 komennolla alkupiste_x = random.randint(0,LEVEYS-1).
(b) Ole tarkkka, että sisennys vastaa sitä ympäröivän koodin sisennystä!
# Valitaan satunnainen alkupiste sivusuunnassa.
alkupiste_x = random.randint(0,LEVEYS-1)
xsuunta = 0
# Valitaan satunnainen suunta pystysuunnassa.
valinta = random.randint(1,2)
if valinta == 1: # ylhäältä
alkupiste_y = -1 # yläreunasta
ysuunta = 1 # liike alaspäin
elif valinta == 2: # alhaalta
alkupiste_y = KORKEUS # alareunasta
ysuunta = -1 # liike ylöspäin
3. Monipuolisia moduuleja
Pythonissa on monia valmiita moduuleja, joita voidaan käyttää erilaisiin tehtäviin. Kirjoita ohjelma, joka käyttää moduuleja seuraavasti:
(a) Käytä datetime-moduulia ja tulosta tämänhetkinen päivämäärä.
(b) Käytä os-moduulia ja tulosta nykyinen työhakemisto.
(c) Käytä time-moduulia ja toteuta ohjelma, joka tulostaa ensin "Odota hetki...", odottaa 2 sekuntia ja tulostaa sitten "Jatketaan!".
1. vihje
2. vihje
- Hyödyllisiä komentoja voivat olla
datetime.date.today(),os.getcwd()jatime.sleep().
oikea tulos
(a) Esimerkiksi, jos ohjelma suoritetaan 10. maaliskuuta 2025, tulos voi olla: 2025-03-10
(b) Esimerkki tuloksesta: /Users/käyttäjä/projekti (Riippuu käyttäjän hakemistosta.)
(c) Ohjelman tulisi ensin tulostaa: Odota hetki... (Kahden sekunnin tauko) Jatketaan!
ratkaisu
import datetime
import os
import time
# (a)
print(datetime.date.today())
# (b)
print(os.getcwd())
# (c)
print("Odota hetki...")
time.sleep(2)
print("Jatketaan!")
Funktiot
- Pythonin funktiot.
- Funktiot määritelläään avainsanalla
def. - Tulokset palautetaan avainsanalla
return:
def f(x,y):
return x+y
- funktion kutsuminen:
tulos = f(1,2) - argumentin oletusarvo:
def f(x, y=0):
Tehtäviä
1. Heippa
Kirjoita ohjelma, joka määrittelee ja kutsuu seuraavat funktiot:
(a) Määrittele funktio hei(), joka tulostaa tekstin "Hei, maailma!" ja kutsu sitä.
(b) Määrittele funktio tervehdi(nimi), joka ottaa vastaan nimen ja tulostaa tervehdyksen muodossa "Hei, nimi!" Kutsu sitä usealla eri nimellä.
1. vihje
- Funktio määritellään avainsanalla
def. - Tätä pitää seurata funktion nimi, sulkeet ja kaksoispiste.
- Sulkeet pitää kirjoittaa näkyviin, vaikka funktiolle ei annettaisi yhtäkään argumenttia.
- Funktion toteuttava koodilohko pitää sisentää. Funktion määrittely loppuu, kun sisennys loppuu.
2. vihje
- Muista kutsua funktioita niiden määrittelyn jälkeen. Eivät ne muuten tee mitään.
oikea tulos
(a) Hei, maailma!
(b) Jos kutsut tervehdi("sinä"), ohjelman tulisi tulostaa:
Hei, sinä!
ratkaisu
def hei():
print("Hei, maailma!")
def tervehdi(nimi):
print("Hei "+nimi+"!")
hei()
tervehdi("sinä")
tervehdi("Teemu")
tervehdi("mitä kuuluu")
2. Pinta-ala
Kirjoita ohjelma, joka määrittelee ja kutsuu seuraavat funktiot sekä tulostaa lopputulokset:
(a) Määrittele funktio nelion_ala(sivu), joka ottaa vastaan neliön sivun pituuden ja palauttaa sen pinta-alan.
(b) Määrittele funktio ympyran_ala(r), joka ottaa vastaan ympyrän säteen ja palauttaa sen pinta-alan kaavalla
\( A = \pi r^2 \). Vakion \( \pi \) sait käyttöön moduulista math.
(c) Määrittele funktio suorakulmion_ala(leveys, korkeus), joka ottaa vastaan suorakulmion leveyden ja korkeuden, laskee sen pinta-alan ja palauttaa tuloksen. Tulosta palautettu arvo.
1. vihje
- Funktio voi palauttaa arvon käyttämällä
return-lausetta.
2. vihje
- Muista hakea
math-moduuli ohjelman alussa, jotta voit käyttäämath.pi-arvoa.
oikea tulos
(a) Jos kutsut neliön_ala(4), ohjelman tulisi tulostaa:
16
(b) Jos kutsut ympyrän_ala(3), ohjelman tulisi tulostaa noin:
28.274333882308138
(c) Jos kutsut suorakulmion_ala(5, 3), ohjelman tulisi tulostaa:
15
ratkaisu
import math
def nelion_ala(sivu):
return sivu * sivu
def ympyran_ala(r):
return math.pi * r * r
def suorakulmion_ala(leveys, korkeus):
return leveys * korkeus
print(nelion_ala(4))
print(ympyran_ala(3))
print(suorakulmion_ala(5, 3))
3. Jonot
Lataa ja tallenna tiedosto jonot.py
Aja ohjelma ja katso mitä se tekee.
(a) Lue kommenteista, miten valmiit funktiot aritmeettinen(alku, askel, pituus) sekä summa(jono) toimivat.
Laske niiden avulla artimeettisen jonon 2, 9, 16, ..., 135 summa.
(b) Täydennä funktio nelioluvut(pituus), joka generoi neliölukujen jonon alun.
Testaa, että se toimii.
(c) Täydennä funktio geometrinen(alku, kerroin, pituus), joka generoi geometrisen jonon alun.
Testaa että funktio toimii.
Tutki mitä jonon summalle tapahtuu, kun pidät argumentit alku ja kerroin vakioina mutta lisäät jonon pituutta.
(d) Kirjoita täysin uusi funktio fibonacci(pituus), joka generoi
Fibonaccin jonon alun.
Testaa että funktio toimii.
1. vihje
- Aritmeettinen jono 2, 9, 16, ..., 135 alkaa luvulla 2 ja jokainen luku on aina 7 suurempi kuin edellinen.
- Voit laskea, montako alkiota jonoon tulee. Tai sitten voit vain kokeilla laittaa jonon pituudeksi jotakin ja katsoa mitä tulee.
- Kun kirjoitat uusia funktioita, ota mallia valmiista funktiosta
aritmeettinen. - Jonot on tallennettu listoina, ja alkioiden lisääminen listaan onnistuu komennolla
lista += [uusi]tailista.append(uusi).
2. vihje
- Ensimmäinen pyydetty jono syntyy komennolla
aritmeettinen(2,7,20). - Neliölukujen jonon voi luoda esimerkiksi niin, että luot silmukan
for n in range(1,pituus+1):ja lisäät jokaisella iteraatiolla jonoon luvunn*n. - Geometrinen jono luodaan ihan samalla tavalla kuin aritmeettinen, mutta sen sijaan että uusi alkio olisi summa
edellinen + askel, se on tuloedellinen * kerroin.
oikea tulos
(a) 1370
(b) Esim. pituudella 10 jono on 1, 4, 9, 16, 25, 36, 49, 64, 81, 100.
(c) Esim. parametreillä 3, 0.75, 10 jono on 3, 2.25, 1.6875, 1.265625, 0.94921875, 0.7119140625, 0.533935546875, 0.40045166015625, 0.3003387451171875, 0.22525405883789062 ja sen summa on 11.324237823486328. Parametreillä 3, 0.75, 100 summa on 11.999999999996147. Summa lähestyy arvoa 12, kun jonon pituus kasvaa. Yleisesti summalla on raja-arvo \( a + aq + aq^2 + aq^3 + \ldots + aq^{N-1} = a \frac{a-q^N}{1-q} \to \frac{a}{1-q} \), kun \( |q| < 1\).
(d) Esim. pituudella 10 jono on 0, 1, 1, 2, 3, 5, 8, 13, 21, 34.
ratkaisu
# (a)
a = 2
b = 7
n = 20
jono = aritmeettinen(a, b, n)
print( jono )
# (b)
def nelioluvut(pituus):
jono = []
for n in range(1,pituus+1):
jono.append( n*n )
return jono
# (c)
def geometrinen(alku, kerroin, pituus):
jono = [alku]
for n in range(pituus-1):
# jonon seuraava luku saadaan kertomalla edellinen
edellinen = jono[-1]
seuraava = edellinen * kerroin
jono.append( seuraava )
return jono
# (d)
def fibonacci(pituus):
jono = [0,1]
for n in range(pituus-2):
jono.append( jono[-1]+jono[-2] )
return jono
Ohjelmointivirheiden korjaaminen
- Pythonin virheilmoitukset
-
SyntaxError: kieliopin vastainen koodi (esim.:puuttuu) -
IndentationError: väärä sisennys -
IndexError: listalle annettu indeksi on listan ulkopuolella -
NameError: annetulla nimellä ei ole määritelty muuttujaa -
TypeError: muuttujaa käytetään tavalla, joka ei vastaa sen tyyppiä (esim. listaa käytetään funktiolle kuuluvien kaarisulkeiden kanssa) - Jos et ymmärrä ohjelman toimintaa, voit seurata sitä debuggerilla tai lisätä ohjelmaan
print()-komentoja kertomaan mitä se tekee - Virheilmoitukseen voi reagoida try-except-rakenteella:
try:
print("yritetään tätä")
except:
print("virheen tapahtuessa hypätään tänne")
Tehtäviä
1. Mastermind
Lataa ja tallenna tiedosto mastermind.py
Tämä on mastermind-peli, jossa pelaajan tehtävänä on arvata salainen koodi. Ohjelman pitäisi pyytää pelaajaa arvaamaan koodia ja kertoa montako kirjainta pelaaja arvasi täysin oikein ja montako oli väärällä paikalla.
Ohjelma ei kuitenkaan toimi.
(a) Aja ohjelma. Tapahtuu virhe. Etsi virhe ja korjaa se. Jatka tätä kunnes ohjelma ei enää kaadu. Huomaa että joskus virhe tapahtuu vasta sen jälkeen, kun pelaaja on antanut arvauksensa!
(b) Pelaa peli läpi. Peli ei kuitenkaan huomaa, vaikka löytäisit oikean koodin! Korjaa ohjelma niin, että se toimii oikein. Huom. Jos ohjelma ei lopu, sinun pitää itse katkaista se ennen kuin voit kokeilla uudestaan.
1. vihje
- Ensimmäinen vastaan tuleva virhe on hämäävä, sillä se ei ole rivillä 29 vaikka virheilmoitus niin väittää, vaan jo aikaisemmin rivillä 27.
- Totuusarvot kirjoitetaan isolla kirjaimella.
- Jos funktiokutsu ei toimi, lue funktion määrittelyn yhteen kirjoitettu kuvaus.
- Tarkista oikeinkirjoitus ja sulkeet.
2. vihje
- Sanoja ja numeroita ei voi yhdistää plussalla.
- Jotta saisit testattua lopputilanteen nopeasti, muuta peli väliaikaisesti triviaaliksi asettamalla esim.
PITUUS=1jaKIRJAIMET="a". - Muista palauttaa parametrit lopuksi sopiviin arvoihin, jotta pelissä on järkeä.
oikea tulos
Jos ohjelma toimii, sen pitää kertoa käyttäjälle, kun oikea koodi on löytynyt ja sitten loppua.
ratkaisu
- 1. korjaus:
koodi += [ random.choice(kirjaimet) ] # rivi 27 (huom. sulkeet)
- 2. korjaus
ok = False # rivi 109 (huom. iso kirjain)
- 3. korjaus
oikein, ohi = laske_osumat(arvaus, koodi) # rivi 195 (huom. puuttuva argumentti)
- 4. korjaus
loytymatta += [ yritys[i] ] # rivi 73 (huom. sulkeet)
- 5. korjaus
print("Oikeita kirjaimia väärällä paikalla: "+str(viereiset)) # rivi 163 (huom. sanan ja luvun yhdistäminen)
- 6. korjaus
print("Tämä oli arvaus numero "+str(kierros)) # rivi 165 (huom. oikeinkirjoitus)
- 7. korjaus
if osumat == pituus: # rivi 152 (huom. yhtäsuuruus)
2. Alkuluvut
Lataa ja tallenna tiedosto alkuluvut.py
Tämän ohjelman pitäisi etsiä alkulukuja. Ohjelma ei kuitenkaan toimi.
(a) Aja ohjelma. Tapahtuu virhe. Etsi virhe ja korjaa se. Jatka tätä kunnes ohjelma ei enää kaadu. Huomaa että joskus virhe tapahtuu vasta sen jälkeen, kun pelaaja on antanut arvauksensa!
(b) Aseta tapaus = 2, jolloin ohjelma testaa vain funktiota on_jaollinen(),
jonka pitäisi testata luvun jaollisuutta toisella luvulla. Funktio ei kuitenkaan toimi oikein.
Kortaa funktio ja testaa sitä kunnes olet vakuuttunut, että se toimii oikein.
(c) Aseta tapaus = 3, jolloin ohjelma testaa vain funktiota on_alkuluku(),
jonka pitäisi testata, onko annettu kokonaisluku alkuluku. Funktio ei kuitenkaan toimi oikein.
Kortaa funktio ja testaa sitä kunnes olet vakuuttunut, että se toimii oikein.
(d) Aseta tapaus = 4, jolloin ohjelma testaa vain funktiota laske_alkuluvut(),
jonka pitäisi laskea alkulukujen määrä annettuun ylärajaan asti. Funktio ei kuitenkaan toimi oikein.
Kortaa funktio ja testaa sitä kunnes olet vakuuttunut, että se toimii oikein.
(e) Aseta tapaus = 1. Laske, montako alkulukua on välillä [0, 1999].
1. vihje
- Ensimmäinen virhe tulee siitä, että yksi pakollinen merkki puuttuu.
- Toinen virhe tulee siitä, että halutaan kutsua ohjelmassa määriteltyä funktiota, mutta sen nimi on väärin. Tarkista, minkä nimisiä funktioita on.
- Kolmas virhe tulee siitä, että sanoja ja lukuja ei voi yhdistää plussalla. Voit esim. muuttaa luvun sanaksi funktiolla
str(n_alkuluvut)tai erottaa eri osat toisistaan plussan sijaan pilkuilla. - Kun testaat funktioita, mieti mitä niiden pitäisi tehdä, ja vertaa siihen mitä ne tekevät.
2. vihje
- Jaollisuustestissä on laskutoimitus väärin päin. Siinä jaetaan jakaja luvulla n, kun pitäisi tietenkin jakaa luku n jakajalla.
- Laskun lopputulos on jakojäännös. Esim. 4 on jaollinen 2:lla ja 21 on jaollinen 7:llä. Mikä on jakojäännös, kun lasketaan 4/2 tai 21/7? Mikä on siis oikea ehto jaollisuudelle?
- Luvut 0 ja 1 eivät ole sopimuksen mukaisesti alkulukuja. On syytä testata vain luvusta 2 ylöspäin.
- Kaikissa silmuikoissa pitää tarkistaa, ettei vahingossa lopeteta yhtä kierrosta liian aikaisin.
- Luku ei ole alkuluku, jos sillä on yksikin ykköstä suurempi jakaja. Siispä yhden tällaisen luvun löytyminen riittää kertomaan, että luku ei ole alkuluku. Mutta jos luku on alkuluku, pitää testata kaikki mahdolliset jakajat. Yksi testi ei mitenkään riitä.
- Alkulukuja laskettaessa laskuri pitää laittaa nollaan vain aivan tehtävän alussa, ja tulos pitää palauttaa vasta aivan tehtävän lopussa.
oikea tulos
(e) 303
ratkaisu
- (a) 1. korjaus:
else: # rivi 71 (huom. kaksoipiste)
- 2. korjaus
n_alkuluvut = laske_alkuluvut(maksimi) # rivi 147 (huom. funktion nimi)
- 3. korjaus
print("alkulukuja löytyi ", n_alkuluvut, " kpl") # rivi 150 (huom. merkkijonojen ja lukujen yhdistäminen)
- (b)
def on_jaollinen(n, jakaja):
jakojaannos = n % jakaja
return ( jakojaannos == 0 )
- (c)
def on_alkuluku(n):
if n < 2:
return False
for jakaja in range( 2, suurin_testattava+1 ):
if on_jaollinen(n, jakaja):
return False
return True
- (d)
def laske_alkuluvut(maksimi, kerro_tulokset = False):
n_alkuluvut = 0
for n in range(maksimi+1):
if on_alkuluku(n):
n_alkuluvut += 1
if kerro_tulokset:
print(n, "on alkuluku")
elif kerro_tulokset:
print(n, "ei ole alkuluku")
return n_alkuluvut
Datan käsittely
- Pythonin input ja output
- tiedoston avaaminen lukemista varten:
file = open('data.txt')taiwith open('data.txt') as file: - koko tiedoston lukeminen:
data = file.read() - yhden rivin lukeminen:
data = file.readline() - kaikkien rivien lukeminen listana:
data = file.readlines() - tiedoston sulkeminen
file.close() - tyhjän tiedoston avaaminen kirjoittamista varten:
file = open('data.txt','w')taiwith open('data.txt','w') as file: - kirjoittamisen jatkaminen vanhaan tiedostoon:
file = open('data.txt','a')taiwith open('data.txt','a') as file: - kirjoittaminen:
file.write('hei') - rivinvaihtomerkki:
\n - komentojen kysyminen käyttäjältä:
komento = input('joo/ei?')
Tehtäviä
1. Tiedoston kirjoittaminen
(a) Kirjoita ohjelma, joka luo tiedoston nimeltä tarina.txt ja kirjoittaa siihen kolme riviä tekstiä:
Olipa kerran
jännittävä tarina.
Sen pituinen se.
(b) Tarkista että löydät tiedoston tietokoneeltasi ja että siinä lukee nämä kolme riviä tekstiä.
1. vihje
- Tiedoston voi avata kirjoitustilassa komennolla
open("tarina.txt", "w"). - Avattu tiedosto pitää tallentaa muuttujaan, jolle voi antaa minkä nimen vain - vaikka
tiedosto. - Sen jälkeen tiedostoon kirjoitetaan komennolla
tiedosto.write("tekstiä"). - Rivinvaihdon voi lisätä tekstiin erikoismerkinnällä
\n. - Jos et käytä
with-komentoa, muista myös sulkea kirjoitettava tiedosto lopuksi.
2. vihje
- Tiedoston voi avata ja tallentaa muuttujaan komennolla
tiedosto = open("tarina.txt", "w")taiwith open("tarina.txt", "w") as tiedosto:. - Näistä ensimmäistä käyttäessä pitää tiedosto sulkea lopuksi komennolla
tiedosto.close(). - Tiedosto luodaan siihen hakemistoon, jossa ohjelma ajetaan.
- Aikaisemmin käskettiin luomaan tehtäviä varten oma hakemisto. Tee se nyt jos et ole sitä jo aikaisemmin tehnyt.
- Tallenna ohjelmasi tähän hakemistoon ennen kuin ajat sen. Silloin tiedostokin kirjoitetaan tähän samaan hakemistoon.
oikea tulos
Tiedoston tarina.txt sisällön pitäisi olla
Olipa kerran
jännittävä tarina.
Sen pituinen se.
Tarkista, että löydät tiedoston ja että siellä on tämä teksti kolmella rivillä.
ratkaisu
with open("tarina.txt", "w") as tiedosto:
tiedosto.write("Olipa kerran\n")
tiedosto.write("jännittävä tarina.\n")
tiedosto.write("Sen pituinen se.\n")
tai esimerkiksi
tiedosto = open("tarina.txt", "w"):
tiedosto.write("Olipa kerran\njännittävä tarina.\nSen pituinen se.\n")
tiedosto.close()
2. Tiedoston lukeminen
Kirjoita ohjelma, joka lukee edellisessä tehtävässä luodun tiedoston tarina.txt rivit ja tulostaa ne näytölle.
1. vihje
- Tiedoston voi avata lukutilassa käyttämällä
open("tarina.txt"). - Voit lukea kaikki rivit komennolla
tiedosto.readlines()tai käydä ne läpifor-silmukalla. - Tekstitiedostossa olevat rivinvaihdot saattavat tulostua näytölle erikoismekkinä
\n. Tällaiset merkit samoin kuin tekstin alussa mahdollisesti olevat tyhjät välilyönnit voi poistaa komennollateksti.strip().
2. vihje
- Luettavan tiedoston pitää olla samassa hakemistossa kuin missä ohjelma ajetaan.
- Sinun pitää siis joko tallentaa tässä tehtävässä kirjoittamasi ohjelma samaan hakemistoon kuin edellisen tehtävän ohjelma tai siirtää tiedosto tarina.txt samaan hakemistoon kuin missä ajat tämän tehtävän ohjelman.
oikea tulos
Ohjelma tulostaa
Olipa kerran
jännittävä tarina.
Sen pituinen se.
ratkaisu
with open("tarina.txt") as tiedosto:
for rivi in tiedosto:
print( rivi.strip() )
tai esimerkiksi
tiedosto = open("tarina.txt")
rivit = tiedosto.readlines()
tiedosto.close()
for rivi in rivit:
print( rivi.strip() )
3. Pelin tallentaminen
Jos teit jo tehtävän Moduulit: 2. Peli, etsi uudestaan sen ohjelmakoodi. Jos et tehnyt vielä tätä tehtävää, hae tiedosto peli.py ja tee siihen edellä mainitun tehtävän (a)-kohdan ratkaisussa kerrotut korjaukset, jotta peli toimii.
Peli pitää kirjaa parhaasta saavutetusta tuloksesta, mutta kun ohjelma suljetaan, ennätys unohtuu. Eihän tässä ole mitään järkeä, vaan kyllä ennätys pitää tallentaa.
(a) Muokkaa funktiota game_over() niin, että jos pelaaja
tekee uuden ennätyksen, tämä tulos kirjoitetaan tiedostoon hiscore.txt.
Testaa, että tiedosto todella kirjoitetaan!
(b) Muokkaa funktiota alkuruutu() niin, että se lukee ennätyksen
tiedostosta hiscore.txt.
Testaa, että peli muistaa ennätyksen, vaikka ohjelman sulkisi ja käynnistäisi uudestaan!
(c) Muokkaa funktiota alkuruutu() niin, että jos
tiedostoa hiscore.txt ei ole olemassa tai siinä on jotakin vikaa, ennätykseksi asetetaan nolla.
Testaa! Poista tiedosto ja kokeile, että ohjelma toimii. Kokeile myös kirjoittaa tiedostoon jotakin muuta kuin numeroita.
1. vihje
- Ennätys on muuttujassa nimeltä
self.hiscore. - Tiedoston kirjoittaminen ja lukeminen onnistuu täsmälleen samalla tavalla kuin edellisissä tehtävissä.
- Tiedosto pitää kirjoittaa vain siinä tapauksessa, että uusi ennätys syntyi. Esim. jos ennätys oli 500 ja pisteitä tuli 400, ei missään nimessä pidä kirjoittaa muistiin lukua 400.
- Kun luet tiedoston, ohjelma poimii siinä olevan tekstin tekstinä. Ennätys on kuitenkin kokonaisluku, joten teksti pitää muuttaa luvuksi.
- Jos ohjelma yrittää lukea tiedostoa jota ei ole, joka on väärässä hakemistossa, tai jossa ei ole numeroa, syntyy virhe. Virheen voi napata komennoilla
try:jaexcept:.
2. vihje
- Tekstin lukeminen ja muuttaminen luvuksi onnistuu esimerkiksi koodilla
ennatys = int( tiedosto.read() ). Tässäread()lukee yhden rivin, mutta tiedostossahan ei pitäisi ollakaan kuin yksi rivi. Komentoint()yrittää muuttaa luetun tekstin kokonaisluvuksi. - Lukuja ei ole pakko muuttaa tekstiksi kirjoittamista varten, mutta voi niin varmuuden vuoksi tehdä. Se käy komennolla
str(). - Ennätyksen tallentaminen pitää olla ehdon
if self.t > self.hiscore:sisällä.
oikea tulos
(a) Ohjelman pitää kirjoittaa tiedostoon hiscore.txt saatu tulos kokonaislukuna jos ja vain jos uusi tulos on parempi kuin aikaisempi ennätys. Jos uusi tulos on huonompi, tiedostoon ei kosketa.
(b) Ohjelman pitää näyttää alkuruudussaan aina paras tähän asti saatu tulos (kohdassa ENNÄTYS: ???) ja sen pitää muistaa tämä tulos vaikka ohjelma suljettaisiin ja käynnistettäisiin uudestaan.
(c) Ohjelma ei saa kaatua, jos tiedostoa hiscore.txt ei ole tai siinä ei ole oikeanlaista informaatiota.
ratkaisu
(a) Funktioon game_over():
# Tallennetaan ennätys, jos sellainen tuli
if self.t > self.hiscore:
self.hiscore = self.t
# Tallennetaan ennätys tiedostoon
with open("hiscore.txt","w") as tiedosto:
tiedosto.write( str(self.hiscore) )
tai esimerkiksi
# Tallennetaan ennätys, jos sellainen tuli
if self.t > self.hiscore:
self.hiscore = self.t
# Tallennetaan ennätys tiedostoon
tiedosto = open("hiscore.txt","w")
tiedosto.write( str(self.hiscore) )
tiedosto.close()
(b,c) Funktioon alkuruutu():
# Yritetään lukea ennätys tiedostosta
try:
with open("hiscore.txt") as tiedosto:
self.hiscore = int( tiedosto.read() )
# Jos tiedostossa oli jotakin vikaa
except:
self.hiscore = 0
tai esimerkiksi
# Yritetään lukea ennätys tiedostosta
try:
tiedosto = open("hiscore.txt")
self.hiscore = int( tiedosto.read() )
tiedosto.close()
# Jos tiedostossa oli jotakin vikaa
except:
self.hiscore = 0
4. Simulaatiodata
Hae tiedosto pallot.py. Se on yksinkertainen simulaatio biljardipallojen liikkeestä. Voit lyödä valkoista palloa klikkaamalla hiirellä tai painamalla välilyöntiä. Kokeile, miten se toimii!
(a) Täydennä funktio kirjoita_tiedostoon(). Aja simulaatio, ja tarkista että
löydät kaksi tiedostoa, joihin on tallennettu simulaatiosta kertynyttä dataa.
1. vihje
- Pallojen väri vastaa suunnilleen snooker-pallojen väriä. Jos et erota punaista ja vihreää, muuta parameterin
VARIarvoa. - Ohjelmaa pitää muuttaa kohdasta, jossa lukee "TEHTÄVÄ A".
- Nyt pitää lisätä dataa jo olevassaolevaan tiedostoon, joten käytä komentoa
open(tiedoston_nimi,"a"). - Tiedoston avaaminen pitää olla ennen
for-silmukkaa. Kirjoittamisen pitää olla silmukan sisällä. - Jos käytät
with-rakennetta, muista sisentääfor-silmukka oikein.
oikea tulos
Ohjelman tulee kirjoittaa tiedostot "aika_energia.txt" ja "liikerata.txt". Kummassakin tiedostossa tulee olla monta riviä numeroita niin, että jokaisella rivillä on kaksi lukua. Nämä ovat aikakoordinaatti ja pallojen liike-energioiden summa sekä x- ja y-koordinaatit.
ratkaisu
with open(tiedoston_nimi, 'a') as f:
for i in range(n):
x = str(x_lista[i])
y = str(y_lista[i])
data = x+" "+y+rivinvaihto
f.write(data)
tai
f = open(tiedoston_nimi, 'a')
for i in range(n):
x = str(x_lista[i])
y = str(y_lista[i])
data = x+" "+y+rivinvaihto
f.write(data)
f.close()
Vektorit ja taulukot
- Numpyn dokumentaatio
- numpyn lataaminen:
import numpy as np - vektori:
v = np.array( [1,2] ) - taulukko:
m = np.array( [[11, 12], [21, 22]] ) - vektorisumma:
v+u - skalaarilla kertominen:
2*v - pistetulo:
v@u - tasavälinen jono:
np.linspace(1,5,3) - nollavektori:
v = np.zeros(3) - ykkösvektori:
v = np.ones(3) - taulukon koko:
m.shape() - taulukon kääntäminen (transpoosi):
m.T - taulukon lukeminen tiedostosta:
np.loadtxt('data.csv', delimiter=',') - taulukon kirjoittaminen tiedostoon:
np.savetxt('data.csv', taulukko) - maksimi:
np.max(data) - minimi:
np.min(data) - keskiarvo:
np.mean(data) - keskihajonta:
np.std(data)
Tehtäviä
1. Vektoreita
Kirjoita ohjelma, joka tekee seuraavat asiat. Tulosta jokaisessa vaiheessa lopputulos näytölle.
(a) Luo vektorin \( \bar{v}_1 = [ 0.0, 0.1, 0.2, \ldots, 10.0 ] \).
(b) Luo vektorin \( \bar{v}_2 = [ e^{0.0}, e^{0.1}, e^{0.2}, \ldots, e^{10.0} ] \).
(c) Laskee näiden pistetulon \( \bar{v}_1 \cdot \bar{v}_2 \).
(d) Laskee vektorin \( \bar{v}_2 \) alkioiden keskiarvon.
(e) Kirjoittaa vektorin \( \bar{v}_2 \) alkiot tiedostoon. Tarkista, että löydät tiedoston ja että sen sisältö on oikein.
1. vihje
- Muista ensin ladata numpy-moduuli!
- Vektori, jonka alkiot muodostavat tasavälisen jonon, on helppo luoda komennolla
np.linspace(). - Lukujen määrä jonossa 0.0, 0.1, ... 10.0 ei ole sata.
- Jos sinulla on vektori ja haluat syöttää vektorin jokaisen alkion jollekin funktiolle, se onnistuu käyttämällä numpyn funktioita.
- Esim.
np.sin( np.array( [0, np.pi/2] ) )tuottaa vektorin \( [\sin(0), \sin(\pi/2)] = [0,1] \). - Pistetulo ei ole
*! - Luo tehtävää varten jokin hyvä hakemisto ja tallenna ohjelmasi sinne. Näin tiedostokin luodaan samaan hakemistoon eikä minne sattuu.
2. vihje
- Kohdassa (b) voit ottaa a-kohdassa luomasi vektorin ja syöttää sen suoraan eksponenttifunktiolle,
v2 = np.exp( v1 ). - Pistetulo on
@. - Keskiarvon saat komennolla
np.mean( v2 ). - Tiedoston voi kirjoittaa itse, mutta se onnistuu helposti myös komennolla
np.savetxt( 'dataa.txt', v2 ).
oikea tulos
(a) [ 0.0 0.1 0.2 ... 10.0 ]
(b) [ 1.00000000e+00 1.10517092e+00 ... 2.20264658e+04 ] Huom. 2.20264658e+04 tarkoittaa \( 2.20264658 \cdot 10^4 = 22026.4658\).
(c) 2094542.9372844785
(d) 2291.6030278229473
(e) Tiedostossa pitää olla samat lukuarvot kuin kohdassa (b) saatiin. Tarkista, että löydät tiedoston.
ratkaisu
import numpy as np
# (a)
v1 = np.linspace(0,10,101)
print(v1)
# (b)
v2 = np.exp( v1 )
print(v2)
# (c)
print(v1 @ v2)
# (d)
print( np.mean(v2) )
# (e)
np.savetxt( 'data.txt', v2 )
2. Dynamiikkaa
Numeerisia taulukoita eli matriiseja käytetään matematiikassa ja fysiikassa hyvin monenlaisissa tarkoituksissa. Erityisti jos vektoreita muunnetaan toisiksi vektoreiksi (esim. venyttämällä tai kääntämällä), vektoreiden komponentit muuttuvat, ja tällaiset muunnokset voidaan tehdä kertomalla vektorin alkuperäiset komponentit sopivilla luvuilla ja laskemalla näitä tuloja yhteen. Nämä "sopivat luvut" voidaan tallentaa näppärästi yhteen taulukkoon, jolloin tällainen taulukko riittää kertomaan, millaisesta operaatiosta on kyse.
Fysiikassa voimme toteuttaa simulaation tällä idealla. Ajatellaanpa, että meillä on vektoriin tallennettuna jonkin suureen arvoja - esimerkiksi systeemin lämpötila tietyissä havaintopisteissä. Kun aika kuluu, nämä arvot tietysti muuttuvat, eli vektorin komponentit muuntuvat. Riippuu tietysti systeemistä, miten ne muuttuvat, mutta jos systeemi tunnetaan, tämäkin muunnos voidaan kuvata keräämällä "sopivat luvut" taulukkkoon.
Esimerkiksi lämpötilan simulaatio rakennetaan siis niin, että ensin selvitetään taulukko, jonka avulla saadaan selville lämpötilat vaikkapa 0.1 s kuluttua. Soveltamalla taulukkoa uudestaan ja uudestaan, saamme lämpötilat 0.2 s, 0.3 s, 0.4 s, jne. kuluttua. Näin saamme selville lämpötilan kehityksen ajan kuluessa.
Hae tiedostot
- dynamiikka.py,
- ei_dynamiikkaa.txt,
- virtaus_poistavilla_reunoilla.txt,
- virtaus_jaksollisilla_reunoilla.txt,
- diffuusio_poistavilla_reunoilla.txt,
- diffuusio_jaksollisilla_reunoilla.txt,
- aalto_heijastavilla_reunoilla.txt ja
- aalto_jaksollisilla_reunoilla.txt.
Python-tiedosto määrittelee simulaation ja kukin muista tiedostoista määrittelee simulaatiota ohjaavan numerotaulukon eli matriisin. Itse simulaatio on kaikissa tilanteissa sama, mutta vaihtamalla matriisia systeemin fysikaalinen käytös muuttuu.
Aja ohjelma, klikkaa sen luomaa ikkunaa ja katso mitä tapahtuu. Vaihda sitten tiedosto, josta ohjelma lukee matriisin, ja kokeile uudestaan.
Jos sinua kiinnostaa, miten itse simulaatio toimii, katso funktiota simuloi().
Varsinainen fysiikka tapahtuu yhdellä ainoalla rivillä koodia!
vihje
- Ohjelma itse toimii, sitä ei tarvitse muuttaa.
- Kaikki tiedostot pitää tallentaa samaan hakemistoon! Ei ohjelma muuten löydä niitä.
- Ohjelma lukee tiedoston, jonka nimi on tallennettu muuttujaan
DYNAMIIKKA. Voit vaihtaa sitä ohjelman alussa. - Klikkaus hiiren ykkösnapilla luo simulaatioon positiivisen poikkeaman, joka piirretään punaisena läiskänä.
- Klikkaus hiiren kakkosnapilla luo simulaatioon negatiivisen poikkeaman, joka piirretään sinisenä läiskänä.
3. Sähkö- ja magneettikenttä
Hae tiedosto sahkomagnetismi.py. Se on ohjelma, johon voi hiirellä klikkaamalla luoda sähkövarauksia ja siirtää niitä. (Välilyöntinapin painaminen vaihtaa, mitä hiiri tekee.)
(a) Funktion sahkokentta() pitäisi laskea pistevarauksen sähkökenttä
lain \( \bar{E} = \frac{k_\varepsilon q}{r^2} \hat{r} \)
mukaisesti. Täydennä funktio niin, että se toimii! Testaa!
(b) Funktion magneettikentta() pitäisi laskea pistevarauksen magneettikenttä
lain \( \bar{B} = \frac{k_\mu q}{r^2} \bar{v} \times \hat{r} \)
mukaisesti. Täydennä funktio niin, että se toimii! Testaa!
1. vihje
- Aluksi hiiri luo positiivisia varauksia. Kun painat kerran välilyöntiä, se alkaa luoda negatiivisia varauksia.
- Kun painat välilyöntiä vielä kerran, pääset siirtämään varauksia. Tämä toimii niin, että kun klikkaat varausta, se alkaa seurata hiirtä.
- Tiedostossa on annettu ohjeet laskulausekkeiden toteuttamiseen.
- Tarvittavat suureet on tallennettu muuttujiin
k_eps, k_mu, q, r_pituus, r_vektori, v_vektori. Näistä muut ovat skalaareja muttar_vektorijav_vektoriovat vektorit. - Magneettikentän lausekkeessa on vektoreiden ristitulo. Katso numpyn dokumentaatiosta, miten se toimii.
2. vihje
- Yksikkövektorille pätee \( \hat{r} = \bar{r} / r \). Sen voi siis laskea ohjelmassa komennolla
r_vektori / r_pituus. - Edelleen \( \hat{r}/r^2 = \bar{r} / r^3 \), jonka voi laskea komennolla
r_vektori / r_pituus**3. - Ristitulon \( \bar{v} \times \bar{r} \) saa laskettua komennolla
np.cross(v_vektori, r_vektori)
oikea tulos
Sähkökentän pitää osoittaa poispäin positiivisista varauksista ja kohti negatiivisia varauksia.
Magneettikenttä syntyy vain varausten liikkuessa. Se on ohjelman piirtämää tasoa vastaan kohtisuorassa, joten se esitetään ympyröinä (kenttä kohti katsojaa) sekä rasteina (kenttä poispäin katsojasta).
ratkaisu
- (a)
return k_eps * q / r_pituus**3 * r_vektori
- (b)
return k_mu * q * np.cross(v_vektori, r_vektori) / r_pituus**3
Kuvaajat
- Matplotlibin dokumentaatio
- Scipyn dokumentaatio
- matplotlibin lataaminen:
import matplotlib.pyplot as p - datapisteiden kuvaaja (data vektoreissa
xtjayt:p.plot(xt, yt) - funktion kuvaaja (välillä [-2, 2]):
x = np.linspace(-2,2,1000)
y = np.sin(x)
p.plot(x,y)
- tyyli:
p.plot(xt,yt,'ro') - näytä kuvaaja:
p.show() - tallenna kuvaaja:
p.savefig('kuva.pdf') - piirtoalue:
p.axis( [0,10,-2,2] )taip.xlim([0,10]) - vaaka-akselin nimi:
p.xlabel('t (s)') - pystyakselin nimi:
p.ylabel('x (m)') - logaritminen asteikko:
p.yscale('log') - viivasto:
p.grid(True) - viivojen paikat:
p.xticks([0,1,2]) - käyrien nimeäminen:
p.plot(xt,yt,label='A')
p.legend()
- histogrammi:
p.hist(data,50) - käyrän sovitus:
import scipy.optimize as so
def f(x,a,b):
return a*x+b
parametrit, kovarianssi = so.curve_fit(f, xy, yt)
tihea_x = np.linspace(0,5,1000)
sovitettu_y = f(tihea_x, *parametrit)
p.plot(xt,yt,'o')
p.plot(tihea_x, sovitettu_y,'-')
p.show()
Tehtäviä
1. Matplotlib
Kirjoita seuraava ohjelma:
import matplotlib.pyplot as plt
X = [20, 40, 60, 80, 100, 120, 140]
Y = [0.020, 0.14, 0.98, 3.0, 6.9, 14, 30]
plt.plot(X, Y)
plt.savefig('kuvaaja.pdf')
plt.show()
Tallenna ohjelma sopivaan hakemistoon ja aja se. Ohjelman pitäisi sekä tallentaa kuvaaja tiedostoon että näyttää se. Tarkista, että löydät tiedoston ja siellä on kuva.
2. Kuvaajia
(a) Hae tiedosto data.txt.
Kirjoita ohjelma, joka lukee tiedoston kaksi ensimmäistä saraketta ja tallentaa ne vektoreihin X ja Y komennolla
import numpy as np
m = np.loadtxt('data.txt')
X = m[:,0]
Y = m[:,1]
Tarkista että tiedoston lukeminen onnistui tulostamalla nämä vektorit.
(b) Piirrä luettujen datapisteiden kuvaaja.
(c) Muokkaa kuvaajaa seuraavilla tavoilla:
- Piirrä data pieninä mustina pisteinä.
- Nimeä akselit "vaaka-akseli" ja "pystyakseli".
- Rajaa kuva vaaka-akselilla välille [10,100] ja pystyakselilla välille [270, 340].
- Lisää kuvaan taustaviivoitus.
(d) Lisää kuvaan funktion \( f(x) = 300 - 30 \cos( 3 + 0.3 x ) e^{-0.03 x }\) kuvaaja.
(e) Anna datapisteiden kuvaajalle nimi 'pisteet' ja funktion kuvaajalla 'käyrä'. Tallenna kuva tiedostoon 'hieno_kuva.pdf'.
1. vihje
- Tallenna datatiedosto ja ohjelmasi samaan hakemistoon! Muuten ohjelma ei löydä dataa.
- Muista ladata matplotllib-moduuli.
- Muista näyttää kuva komennolla
p.show(). - Kuvaajan saa muutettua pisteiksi antamalla
p.plot()-komennolle kolmanneksi argumentiksi'o'. - Pisteistä saa mustia antamalla komennolle argumentin
c='black'(ctarkoittaa 'color'). - Pisteistä saa pieniä antamalla komennolle argumentin
ms=0.5(mstarkoittaa 'markersize'). - Piirrettävän funktion arvot saat laskettua käyttämällä numpyn funktioita ja antamalla niille argumentiksi vektorin, jossa on x-arvot.
2. vihje
- Akseli nimetään komennolla
p.xlabel(). - Akselit rajataan komennolla
p.axis()taip.xlim(). - Taustaviivoitus lisätään komennolla
p.grid(). - Kuvaajat nimetään lisäämällä
p.plot()-komennolle argumenttilabel='nimi'ja lisäämällä komentop.legend(). - Kuva tallennetaan komennolla
p.savefig(). Huom. jos annat ensin komennonp.show(), se poistaa kuvat ohjelman muistista. Jos yrität sen jälkeen tallentaa, saat vain tyhjän kuvan.
oikea tulos
(a) [0.0000e+00 9.0000e-02 ... 1.8000e+02]
[347.264 347.524 ... 294.249]
ratkaisu
# (a)
import numpy as np
m = np.loadtxt('data.txt')
X = m[:,0]
Y = m[:,1]
print(X)
print(Y)
# (b,c)
import matplotlib.pyplot as p
p.plot(X,Y,'o',c='black',ms=0.5,label='pisteet')
p.xlabel('vaaka-akseli')
p.ylabel('pysty-akseli')
p.axis([10,100,270,340])
p.grid()
# (d)
tihea_x = np.linspace(10,100,1000)
f = 300 - 30 * np.cos( 3 + 0.3*tihea_x ) * np.exp( -0.03*tihea_x )
p.plot(tihea_x, f, label='käyrä')
# (e)
p.legend()
p.savefig('hieno_kuva.pdf')
3. Interferenssi
Hae tiedosto interferenssi.py.
Se simuloi valon kulkua erilaisten aukkojen lävitse ja siitä seuraavia diffraktio- ja interferenssi-ilmiöitä.
Kokeile, millaisia kuvioita saat aikaan, kun muutat parametrejä
tapaus (millaisista aukoista valo kulkee), w (aukkojen leveys) ja d (aukkojen välinen etäisyys).
(a) Toteuta funktio piirra_intensiteettijakauma(), jonka pitäisi piirtää intensiteettijakauman kuvaaja.
Piirrettävä data on vektoreissa kulmat ja intensiteetti.
(b) Muokkaa kuvaajaa seuraavilla tavoilla:
- rajaa x-akseli välille
[-MAX_KULMA, MAX_KULMA] - rajaa y-akseli välille
[0, y_maksimi] - anna x-akselille nimeksi "havaintokulma, $\\\\theta$ ($^\\\\circ$)"
- anna y-akselille nimeksi "suhteellinen intensiteetti, $I$"
- piirrä kuvaaja paksuna mustana viivana
- lisää taustaviivoitus
(c) Toteuta funktio piirra_fotonikuvio(), jonka pitäisi piirtää fotoneista koostuva kuva.
Piirrettävä data on vektoreissa X ja Y.
Muokkaa kuvaa seuraavilla tavoilla:
- piirrä kuvaaja pieninä valkeina pisteinä mustalla taustalla
- rajaa x-akseli välille
[-MAX_KULMA, MAX_KULMA] - rajaa y-akseli välille
[0, y_maksimi] - anna x-akselille nimeksi "havaintokulma, $\\\\theta$ ($^\\\\circ$)"
1. vihje
- Matplotlib-moduuli on haettu jo valmiiksi nimellä
plt. - Muista näyttää kuva komennolla
plt.show(). - Kuvaajan saa muutettua pisteiksi antamalla
plt.plot()-komennolle kolmanneksi argumentiksi'o'. - Pisteistä saa valkeita antamalla komennolle argumentin
c='white'(ctarkoittaa 'color'). - Pisteistä saa pieniä antamalla komennolle argumentin
ms=0.5(mstarkoittaa 'markersize'). - Taustavärin saa muutettua mustaksi komennoilla
akselit = plt.gca() (gca tarkoittaa 'get current axes')
akselit.set_facecolor("black")
2. vihje
- Akseli nimetään komennolla
plt.xlabel(). - Akselit rajataan komennolla
plt.axis()taiplt.xlim(). - Taustaviivoitus lisätään komennolla
p.grid().
ratkaisu
- (a,b)
def piirra_intensiteettijakauman_kuvaaja(kulmat, intensiteetti):
plt.clf()
y_maksimi = 1.1*np.max(intensiteetti)
plt.xlim(-MAX_KULMA,MAX_KULMA)
plt.ylim(0, y_maksimi)
plt.plot(kulmat, intensiteetti, c="black", lw=2)
plt.xlabel("havaintokulma, $\\theta$ ($^\\circ$)")
plt.ylabel("suhteellinen intensiteetti, $I$")
plt.grid()
plt.show()
- (c)
def piirra_fotonikuvio(intensiteetti):
...
plt.plot(X,Y,'o', c=pisteen_vari, ms=pisteen_koko)
plt.xlim(-MAX_KULMA,MAX_KULMA)
plt.ylim(0,1)
plt.xlabel("havaintokulma, $\\theta$ ($^\\circ$)")
akselit = plt.gca()
akselit.set_facecolor('black')
plt.show()
4. Ideaalikaasu
Hae tiedosto pallot.py.
(a) Se on aikaisemmasta harjoituksesta tuttu biljardisimulaatio, mutta jos muutat tiedoston alussa olevien parametrien arvoja näin:
-
R = 1 * SKAALA -
KITKA = 0 -
KERROKSIA = 15 -
ERO = 2 * SKAALA -
KARKI = 0.5
ja lyöt valkoisen pallon liikkeelle, siitä tulee kaksiulotteisen kaasun simulaatio. Kokeile, miten simulaatio toimii!
(b) Jos painat nappia 'p' simulaation aikana, ohjelma piirtää pallojen vauhtien jakauman histogrammina.
Ideaalikaasulle termodynamiikan teoria sanoo, että tämän jakauman pitäisi
suurella hiukkasmäärällä noudattaa funktiota
\( f(v) = ave^{-\frac{1}{2}av^2}. \)
Lisää funktioon piirra_nopeusjakauma() tämän funktion piirtäminen.
Piirrettävä data on tallennettu muuttujiin x_arvot ja teoreettinen_jakauma.
Testaa, että piirtäminen toimii!
(c) Muokkaa kuvaajaa seuraavilla tavoilla:
- Paranna kuvaajan resoluutiota.
- Lisää vaaka-akselille nimi "suhteellinen nopeus ($v/v_{max}$)".
- Lisää pystyakselille nimi "todennäköisyystiheys".
- Rajaa kuvaaja vaakasuunnassa välille [0,0.3].
- Lisää laatikko, jossa histogrammille annetaan nimi "simulaatio" ja käyrälle "teoria".
- Lisää kuvaan taustaviivoitus.
- Tallenna kuva myös tiedostoon.
1. vihje
- Matplotlib-moduuli on haettu jo valmiiksi nimellä
plt. - Muista näyttää kuva komennolla
plt.show()tai tallentaa se komennollaplt.savefig(). - Resoluution parantaminen tarkoittaa tässä sitä, että vektorissa
x_arvoton liian vähän pisteitä. Tee vektorista suurempi.
2. vihje
- Paremman resoluution saat esimerkiksi muutoksella
x_arvot = np.linspace(0,0.5,1001). - Akseli nimetään komennolla
plt.xlabel(). - Akselit rajataan komennolla
plt.axis()taiplt.xlim(). - Taustaviivoitus lisätään komennolla
p.grid(). - Kuvaajat nimetään lisäämällä
plt.plot()-komennolle argumenttilabel='nimi'ja lisäämällä komentoplt.legend().
ratkaisu
def piirra_nopeusjakauma(self,event):
...
x_arvot = np.linspace(0,0.5,1001)
plt.hist(vauhdit, bins=np.linspace(0,0.5,26), density=True, label="simulaatio")
plt.plot(x_arvot, teoreettinen_jakauma, label="teoria")
plt.xlabel("suhteellinen nopeus ($v/v_{max}$)")
plt.ylabel("todennäköisyystiheys")
plt.xlim(0,0.3)
plt.legend()
plt.grid()
plt.savefig("vauhtijakauma.pdf")
plt.show()
5. Käyrän sovitus
Kirjoita seuraava ohjelma:
import matplotlib.pyplot as plt
import scipy.optimize as so
import numpy as np
def potenssi(x, a, b):
return a*x**b
X = [20, 40, 60, 80, 100, 120, 140]
Y = [0.020, 0.14, 0.98, 3.0, 6.9, 14, 30]
parametrit, kovarianssi = so.curve_fit(potenssi, X, Y)
sovitettu_funktio = potenssi(X, *parametrit)
plt.plot(X, sovitettu_funktio, 'r-')
plt.plot(X, Y, 'ro')
plt.savefig('sovitus.pdf')
plt.show()
(a) Tallenna ohjelma sopivaan hakemistoon ja aja se. Ohjelman pitäisi sekä tallentaa kuvaaja tiedostoon että näyttää se. Tarkista, että löydät tiedoston ja siellä on kuva.
(b) Tulosta sovituksen parametreille \( a, b \) löytämät lukuarvot.
(c) Muokkaa ohjelmaa niin, että sovitettua funktiota ei piirretä karkeana murtoviivana vaan sileänä käyränä.
(d) Vaihda sovitettavaksi funktioksi potenssifunktion \( y = ax^b \) tilalle eksponenttifunktio \( y = a e^{b x} \).
1. vihje
- Parametrien arvot tallentuvat vektoriin
parametrit. - Funktio piirtyy murtoviivana, koska vektorissa
Xon vain seitsemän pistettä ja ohjelma piirtää funktion näiden pisteiden kautta. Määrittele uusi vektori, jossa on \(x\)-arvoja tiheässä ja käytä sitä funktion piirtämisessä. - Kohdassa (d) pitää määritellä uusi funktio.
- Voisit tietysti käyttää valmista funktiota
potenssija vain muuttaa sen määrittelyä, mutta se olisi vähän hassua, koska uusi funktio ei ole potenssifunktio. Siksi olisi parempi kirjoittaa kokonaan uusi funktio. - Silloin pitää myös muistaa vaihtaa funktion nimi sovituskomennon
so.curve_fit()sisällä ja vektorinFlaskussa. - Lisää alkuarvaus sovitukseen antamalla komennolle
so.curve_fit()lisäargumenttip0 = [arvaus_a, arvaus_b], missäarvaus_aon arvauksesi sille, mikä \( a \):n arvo voisi olla, jaarvaus_bvastaavasti \( b \):lle. Jos sovitus ei onnistu, muuta arvauksiasi.
2. vihje
- Parametrien arvot tallentuvat vektoriin
parametritsiinä järjestyksessä jossa ne funktiossa esiintyvät. Siispä \( a \) on ensin ja sen arvo löytyy muuttujastaparametrit[0]. - Saat sileän käyrän, kun määrittelet uuden vektorin, esim.
X_tihea = np.linspace(1,150,1501), jossa on paljon pisteitä, ja käytät sitä vektorinsovitettu_funktiolaskussa. - Määrittele eksponenttifunktio käyttämällä numpyn funktiota
np.exp(). Et voi käyttää moduuliamath, koska funktion pitää osata käsitellä vektoreita. - Kokeile antaa parametreille alkuarvauksena lukuarvot 1 ja 0.1.
oikea tulos
- (b) \( a = 6.05 \cdot 10^{-9}, b = 4.52 \).
- (d) \( a = 0.143, b = 0.0382 \).
ratkaisu
import matplotlib.pyplot as plt
import scipy.optimize as so
import numpy as np
def eksponentti(x, a, b):
return a*np.exp(b*x)
X = [20, 40, 60, 80, 100, 120, 140]
X_tihea = np.linspace(1,150,1501)
Y = [0.020, 0.14, 0.98, 3.0, 6.9, 14, 30]
parametrit, kovarianssi = so.curve_fit(eksponentti, X, Y, p0=[1,0.01])
print("a = ",parametrit[0])
print("b = ",parametrit[1])
sovitettu_funktio = eksponentti(X_tihea, *parametrit)
plt.plot(X_tihea, sovitettu_funktio, 'r-')
plt.plot(X, Y, 'ro')
plt.savefig('sovitus.pdf')
plt.show()
6. Gaussin funktioita
Hae ohjelma sovitus.py. Jos et jo hakenut tehtävässä 2 tiedostoa data.txt, hae myös se.
Ohjelma lukee datatiedoston ensimmäisen ja viimeisen sarakkeen ja tallentaa ne vektoreihin X ja Y.
Data esittää hyvin tyypillistä fysikaalista mittasarjaa. Monessa paikassa \(y\)-arvot ovat likimain nollassa, mutta
on alueita, joissa arvot selkeästi poikkeavat nollasta. Tällaista dataa saadaan usein mittaamalla yhta suuretta \( y \) samalla kun
jotakin toista suuretta \(x \) muutetaan. Jos \(y\):n pitäisi poiketa nollasta vain joillakin tietyillä \(x\):n arvoilla,
mittaustulos on laajalti likimain nollaa ja nousee nollasta poikkeavaksi vain näiden kriittisten \(x\)-arvojen lähellä.
Mittaustarkkuudesta ja satunnaistekijöistä johtuen datassa ei kuitenkaan nähdä näissä pisteissä täysin teräviä piikkejä
vaan jonkinlaisia leveitä huippuja. Tällaisen datan analyysissä tärkein kysymys yleensä onkin, missä näiden huippujen kärkipisteet
ovat ja kuinka korkeita ne ovat.
Jos emme tiedä muuta, voimme olettaa näiden huippujen olevan normaalijakautuneita, jolloin ne noudattavat Gaussin funktiota \[ y(x) = a e^{- \frac{(x-b)^2}{c^2} }, \] missä parametri \(a \) liittyy huipun korkeuteen, \( b \) huipun keskipisteen paikkaan ja \( c \) huipun leveyteen. Tämä ohjelma pyrkii sovittamaan dataan funktion, joka on tällaisten Gaussin funktioiden summa. Ohjelma ei kuitenkaan tiedä, montako huippua sen pitäisi etsiä tai mistä niitä kannattaisi hakea. Siksi käyttäjän pitää auttaa ohjelmaa.
(a) Kokeile ajaa ohjelma. Sen pitäisi piirtää kuva datasta. Arvioi silmämääräisesti, montako huippua datassa on ja missä ovat niiden keskipisteet (vaaka-akselilla) sekä mitkä ovat niiden korkeudet (pystyakselilla).
(b) Etsi datassa olevien huippujen paikat ja korkeudet muuttamalla vektoria ALKUARVAUS_PARAMETREILLE.
Vektorissa pitää olla kolmella jaollinen lukumäärä parametrejä, sillä jokainen kolmikko
edustaa yhden Gaussin funktion parametrejä \( a, b, c \).
Ohjelma piirtää punaisella jokaisen Gaussin funktion erikseen ja oranssilla niiden summan.
Sovitus on hyvä, jos oranssi käyrä seuraa sinisellä piirrettyä dataa.
(c) Vertaa silmämääräistä arviotasi ohjelman löytämiin arvoihin. Oliko niissä eroa? Oliko ohjelman käyttämisestä siis mitään hyötyä verrattuna vain kuvan katsomiseen?
1. vihje
- Parametri \( a \) on huipun korkeus. Katso kuvasta, kuinka korkeita huiput mielestäsi ovat.
- Parametri \( b \) on huipun keskikohdan paikka. Katso kuvasta, missä huippujen keskipisteet mielestäsi ovat.
- Parametri \( c \) on huipun leveys (jollakin mittarilla), mutta tätä ei ole helppo lukea kuvasta. Kokeile sille jotakin järkevää alkuarvoa.
2. vihje
- Datassa on kolme huippua, joten alkuarvausvektoriin pitää tulla 9 numeroa.
- Ensimmäisen huipun korkeus on kuvan perusteella hieman alle 4 ja sen keskipisteen paikka on noin 60 (\(^\circ\)). Laita nämä arvaukseksi parametreille \(a\) ja \(b\).
- Kokeile huipun leveydelle vaikkapa alkuarvausta 10.
- Siispä tämän arvauksen pitäisi saada ensimmäinen huippu oikein mutta kaksi muuta väärin:
ALKUARVAUS_PARAMETREILLE = [4,60,10,1,1,1,1,1,1].
oikea tulos
(b) Datassa on kolme huippua:
- \( a_1 = 3.73 \pm 0.02, b_1 = 57.95 \pm 0.05, c_1 = 11.25 \pm 0.07 \)
- \( a_2 = 5.21 \pm 0.02, b_2 = 121.0 \pm 0.1, c_2 = 14.6 \pm 0.01 \)
- \( a_3 = 6.35 \pm 0.04, b_3 = 142.97 \pm 0.08, c_3 = 11.16 \pm 0.08 \)
(c) Ensimmäisen huipun pystyi lukemaan kuvasta, mutta koska kaksi seuraavaa ovat päällekäin, huippujen korkeudet ja paikat eivät täsmälleen vastaa kuvaajassa näkyviä huippuja. Ilman tietokoneella tehtyä sovitusta data olisi siis tulkittu väärin.
ratkaisu
Alkuarvaus toimii, kunhan se on tarpeeksi lähellä parametrien oikeita arvoja.
Esim. ALKUARVAUS_PARAMETREILLE = [4,60,10,5,120,10,6,140,10].