Python-harjoituksia

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

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.x tai Python 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.
  • 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

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^8 kuten 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 2a vaan täytyy kirjoittaa 2*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 = 1 tallentaa muuttujaan arvon 1 kun taas a == 1 kysyy 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ä komentoa print().
  • Muuttujiin voi tallentaa melkein mitä vain, myös vertailujen tuloksia. Voit siis kirjoittaa muuttuja = (1 == 2), jolloin muuttujaan tallentuu totuusarvo False.
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 on asioita[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] + asioita lisää 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

if x > 0:
    print('x on positiivinen')
elif x < 0:
    print('x on negatiivinen')
else:
    print('x on nolla')
for i in [1,10,100]:
    print(i)
for i in range(10):
    print(i)
while i < 100:
    i += 1
    print(i)
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, elif ja else pitää 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 lyhyesti if 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 for kä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 N ja antaa sille jonkin positiivisen kokonaislukuarvon.
  • Antaa muuttujalle i silmukassa 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ää for tai while-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 kullakin i: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

import math
print(math.pi)
import math as m
print(m.pi)
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, comb ja fsum.
  • 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 degrees muuntaa 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 = KORKEUS sekä 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
  • Moduulit tuodaan ohjelmaan avainsanalla import. Voit tutustua niiden dokumentaatioon täällä:
2. vihje
  • Hyödyllisiä komentoja voivat olla datetime.date.today(), os.getcwd() ja time.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

def f(x,y):
    return x+y
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] tai lista.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 luvun n*n.
  • Geometrinen jono luodaan ihan samalla tavalla kuin aritmeettinen, mutta sen sijaan että uusi alkio olisi summa edellinen + askel, se on tulo edellinen * 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

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=1 ja KIRJAIMET="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

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") tai with 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äpi for-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 komennolla teksti.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: ja except:.
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. Komento int() 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 VARI arvoa.
  • 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

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

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 mutta r_vektori ja v_vektori ovat 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

x = np.linspace(-2,2,1000)
y = np.sin(x)
p.plot(x,y)
p.plot(xt,yt,label='A')
p.legend()
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' (c tarkoittaa 'color').
  • Pisteistä saa pieniä antamalla komennolle argumentin ms=0.5 (ms tarkoittaa '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() tai p.xlim().
  • Taustaviivoitus lisätään komennolla p.grid().
  • Kuvaajat nimetään lisäämällä p.plot()-komennolle argumentti label='nimi' ja lisäämällä komento p.legend().
  • Kuva tallennetaan komennolla p.savefig(). Huom. jos annat ensin komennon p.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' (c tarkoittaa 'color').
  • Pisteistä saa pieniä antamalla komennolle argumentin ms=0.5 (ms tarkoittaa '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() tai plt.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 komennolla plt.savefig().
  • Resoluution parantaminen tarkoittaa tässä sitä, että vektorissa x_arvot on 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() tai plt.xlim().
  • Taustaviivoitus lisätään komennolla p.grid().
  • Kuvaajat nimetään lisäämällä plt.plot()-komennolle argumentti label='nimi' ja lisäämällä komento plt.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 X on 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 potenssi ja 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 vektorin F laskussa.
  • Lisää alkuarvaus sovitukseen antamalla komennolle so.curve_fit() lisäargumentti p0 = [arvaus_a, arvaus_b], missä arvaus_a on arvauksesi sille, mikä \( a \):n arvo voisi olla, ja arvaus_b vastaavasti \( b \):lle. Jos sovitus ei onnistu, muuta arvauksiasi.
2. vihje
  • Parametrien arvot tallentuvat vektoriin parametrit siinä järjestyksessä jossa ne funktiossa esiintyvät. Siispä \( a \) on ensin ja sen arvo löytyy muuttujasta parametrit[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ä vektorin sovitettu_funktio laskussa.
  • Määrittele eksponenttifunktio käyttämällä numpyn funktiota np.exp(). Et voi käyttää moduulia math, 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].

valid html | updated on 2026-08-13