summaryrefslogtreecommitdiff
path: root/python/problems/while_and_if/loops_sl.html
blob: 17d89c4032fb0206c5874eb2413e7810f6ccae88 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
<!DOCTYPE html>
<html lang="sl">
<head>
  <meta charset="utf-8" />
  <title></title>
  <link rel="stylesheet" type="text/css" href="/css/codeq.css" />
  <link rel="stylesheet" type="text/css" href="../../style.css" />
</head>
<body>

<h1>Zanka <code>while</code></h1>

<h2>Naša prva zanka</h2>

<p>Najprej malo refleksije. Kaj znamo narediti doslej: znamo napisati program,
    ki kaj vpraša, kaj računa in kaj izpiše. Naši programi se izvajajo od
    začetka do konca, s tem da lahko vmes preskočijo kak blok ukazov, ki se
    nahajajo znotraj kakega <code>if</code>, <code>else</code> ali
    <code>elif</code>. Večino časa pa smo preživeli ob tem, kako napisati
    pogoj, se pravi, izraz, katerega vrednost je lahko resnično ali neresnično,
    <code>True</code> ali <code>False</code>. Zdaj pa se bomo naučili napisati
    programe, v katerih se del programa ponavlja.</p>

<p>V večini programskih jezikov to naredimo z nečim, čemur mi rečemo zanka,
    Avstralci (razen aboriginov) pa <em>loop</em>. Jeziki imajo navadno več
    vrst zank, navadno tri. Python premore samo dve in danes bomo spoznali prvo
    od njiju: zanko <em>while</em>.</p>

<p>Tisočletna tradicija veleva, da mora biti začetnikov prvi program z zanko
    program, ki šteje do deset. V Pythonu je videti takole
<pre>x = 1
while x <= 10:
    print(x)
    x = x + 1
print('Pa sva preštela')</pre>

<p>Zanka <code>while</code> je po svoje podobna stavku <code>if</code>. Medtem
    ko se stavki znotraj <code><b>if</b></code> izvedejo, <b>če</b> je pogoj
    resničen, se stavki znotraj <code><b>while</b></code> ponavljajo,
    <b>dokler</b> je pogoj resničen. "If" je "če" in "while" je "dokler", to
    vedo celo učiteljice angleščine. (Mimogrede, če že štejemo,
    <code>while</code> je zadnja, enajsta rezervirana beseda danes. Smo že na
    tretjini!) Gornji program lahko torej kar dobesedno prevedemo iz Pythona v
    slovenščino:

<pre>
postavi x na 1
dokler je x manjši ali enak 10:
    izpiši vrednost x
    povečaj x za 1
izpiši 'Pa sva preštela'
</pre>

<p>K temu ni potrebna več nobena razlaga, ne?</p>

<p>Trenutek je tako dober kot katerikoli drugi, morda pa še boljši: tale
    <code>x = x + 1</code> smo "prevedli" v "povečaj x za 1". V resnici nismo
    napisali tega, računalniku smo naročili, naj izračuna, koliko je
    <code>x + 1</code> in to shrani nazaj v <code>x</code>. Ker pa to reč
    tolikokrat potrebujemo in ker je lepo, da se stvar napiše tako, kot se
    misli - misli pa se "povečaj x za 1" -, obstaja tudi praktičnejši zapis:
    <code>x += 1</code>. Točneje, napisali smo "k x prištej 1". Rečemo lahko
    tudi, <code>x += 6</code> ali <code>x += 1.13</code>; kaj to pomeni, je
    menda jasno. Podobno moremo pisati tudi <code>x -= 1</code> (zmanjšaj
    <code>x</code> za 1) ali, recimo <code>x *= 2</code>, podvoji
    <code>x</code> in <code>x /= 10</code>, zdesetkaj <code>x</code>.
    Pazite: <code>+=</code> (in vse druge kombinacije) se štejejo kot ena
    beseda in med znaka <code>+</code> in <code>=</code> ne smemo napisati
    presledka.</p>

<p>Tisti, ki veste še kaj več: <code>x++</code> boste v Pythonu zaman iskali.
    Nima ga, iz več razlogov, ki pa so malo pregloboki za nas tule.</p>

<h2>Kaj je domneval Collatz</h2>

<p>Vzemimo poljubno število in z njim počnimo tole: če je sodo, ga delimo z 2,
če je liho, pa ga pomnožimo s 3 in prištejmo 1. To ponavljamo, dokler ne dobimo
1.</p>

<p>Za primer vzemimo 12. Ker je sodo, ga delimo z 2 in dobimo 6. 6 je sodo,
torej ga delimo z 2 in dobimo 3. 3 je liho, torej ga množimo s 3 in prištejemo
1 - rezultat je 10. 10 je sodo, zato ga delimo z 2 in dobimo 5... Celotno
zaporedje je 12, 6, 3, 10, 5, 16, 8, 4, 2, 1. Ko pridemo do 1, se ustavimo.</p>

<p>Matematiki, ki vedno radi počnejo koristne reči, si belijo glavo z
vprašanjem, ali se reč vedno izteče ali pa se lahko kdaj tudi zacikla tako, da
se zaporedje ponavlja in ponavlja v nedogled. Lothar Collatz, konkretno je že od
leta 1937
<a href="https://en.wikipedia.org/wiki/Collatz_conjecture">domneval</a>, da se
zaporedje vedno izteče. Kot pravi njegov
<a href="https://en.wikipedia.org/wiki/Lothar_Collatz">življenjepis</a>, se je
njegovo domnevanje končalo leta 1990, matematiki pa domnevajo domnevo še naprej.
Eden sicer najbolj neustrašnih matematikov 20. stoletja,
<a href="https://en.wikipedia.org/wiki/Paul_Erd%C5%91s#Personality">couch
    surfer Erdos</a>, je na to temo rekel, da matematika za takšna vprašanja še
    ni zrela.</p>

<p>Naši cilji bodo skromnejši: napisali bomo program, ki mu bo uporabnik vpisal
število in program bo izpisal zaporedje, kot je bilo gornje.</p>

<p>Najprej povejmo kar po slovensko:</p>

<pre>stevilo = kar vpiše uporabnik
dokler stevilo != 1:
    če je število sodo:
        deli število z 2
    sicer:
        pomnoži število s 3 in prištej 1</pre>

<p>Tole skoraj že znamo prevesti v Python (prevod bo pravzaprav dobeseden),
    odkriti moramo le, kako preveriti, ali je število sodo. Če kdo misli, da
    tudi za to obstaja funkcija, se, izjemoma, moti. Pač pa znamo izračunati
    ostanek po deljenju, konkretno, ostanek po deljenju z 2. Če je enak 0, je
    število sodo.</p>

<p>Prevedimo torej one slovenske besede v pythonovske.</p>

<pre>n = int(input("Vnesi število: "))
while n != 1:
    print(n)
    if n % 2 == 0:
        n //= 2
    else:
        n = n * 3 + 1
print(1)</pre>

<p>Ne spreglejte, da smo uporabili celoštevilsko deljenje. Če bi uporabili
navadnega, <code>n /= 2</code>, bi se <code>n</code> spremenil v necelo število
(<code>float</code>) in v izpisu bi se pojavile zoprne decimalke (za vsakim
številom bi pisalo še .0).</p>

<p>Popaziti je potrebno, da izpišemo tako prvo kot zadnje število, zato bomo
potrebovali še en <code>print</code> izven zanke: po zanki izpišemo še zadnji
člen zaporedja, 1. Namesto <code>print(1)</code> bi lahko napisali tudi
<code>print(n)</code> - tako ali tako vemo, da je <code>n</code> enak 1, saj
program sicer ne bi prišel do tam, do koder je prišel, namreč onstran zanke, ki
teče, dokler je <code>n</code> različen od 1.</p>

<p>Dodajmo še nekaj: na koncu naj se izpiše, koliko členov ima zaporedje.</p>

<pre>n = int(input("Vnesi število: "))
clenov = 1
while n != 1:
    clenov += 1
    print(n)
    if n % 2 == 0:
        n //= 2
    else:
        n = n * 3 + 1
print(1)
print("Zaporedje, ki se začne z", n, "ima", clenov, "členov")</pre>

<p>Ups. V zanki smo pokvarili <code>n</code>, spremenil smo ga v 1. To bomo
rešili tako, da shranimo začetno število v še eno spremenljivko.</p>

<pre>zac = n = int(input("Vnesi število: "))
clenov = 1
while n != 1:
    clenov += 1
    print(n)
    if n % 2 == 0:
        n //= 2
    else:
        n = n * 3 + 1
print(1)
print("Zaporedje, ki se začne z", zac, "ima", clenov, "členov")</pre>

<p>Število smo si zapomnili v prvi vrstici, shranili smo ga v
<code>zac</code>. (V tem programu tudi prvič vidimo, da lahko prirejanja kar
nizamo - pisati smemo <code>a = b = c = 42</code>.) Ustrezno popravimo še
izpis v zadnji vrsti.</p>

<script type="text/javascript">
     SyntaxHighlighter.config.tagName = "xmp";
     SyntaxHighlighter.defaults["gutter"] = false;
     SyntaxHighlighter.all()
</script>
</body>
</html>