1.3 Verzweigungen und Schleifen Die bisher betrachteten Programme bestanden aus Anweisungen, die der Reihe nach von der ersten bis zur letzten ausgeführt werden. Nun werden wir sehen, wie man diese Reihenfolge beeinflussen kann. Abhängig von Bedingungen können Anweisungs-Blöcke ausgeführt oder nicht ausgeführt werden (Verzweigungen), oder Anweisungs-Blöcke können mehrfach ausgeführt werden (Schleifen). Mittels Verzweigungen und Schleifen werden wir bereits viel mächtigere Programme schreiben können als bisher. 1.3.1 Was wir bisher hatten . . . Die bisherigen Programme waren feste Folgen von Anweisungen. Hoehe = int(sys.argv[1]) Breite = int(sys.argv[2]) Laenge = int(sys.argv[3]) Volumen = Hoehe * Breite * Laenge Oberflaeche = 2*(Hoehe*Breite + Hoehe*Laenge + Breite*Laenge) stdio.writeln(str(Volumen) + ’ ’ + str(Oberflaeche)) 1.3.2 Was heute dazukommt sind Verzweigungen . . . x = int(sys.argv[1]) y = int(sys.argv[2]) ja y < x ? x = temp nein x = y y = temp stdio.writeln(str(x) + ’ ’ + str(y)) Der Algorithmus gibt die Werte von x und y aufsteigend aus. 1.3.3 . . . Verzweigungen . . . a = int(sys.argv[1]) b = int(sys.argv[2]) ja nein b==0 ? quotient = a//b text=’Durch 0 kann man nicht teilen.’ rest = a%b text=str(quotient)+’ ’+str(rest) stdio.writeln(text) Der Algorithmus gibt das Ergebnis der ganzzahligen Division von a durch b aus. 1.3.4 . . . und Schleifen schulden = int(sys.argv[1]) zinssatz = float(sys.argv[2]) jahresrate = int(sys.argv[3]) jahrezaehler = 0 nein schulden > 0 ? ja schulden = schulden*(1+zinssatz)-jahresrate jahrezaehler = jahrezaehler+1 stdio.writeln(’Die Rückzahlung dauert ’ + str(jahrezaehler) + ’ Jahre.’) Wieviele Jahre dauert die Rückzahlung der Schulden bei der Jahresrate und dem Zinssatz? 1.3.5 if-Anweisungen Viele Programme sollen bei verschiedenen Eingaben unterschiedlich arbeiten. Z.B. könnte das Programm teilen v2.py, das bei Eingabe zweier Werte a und b den Quotient und den Rest beim Teilen von a durch b berechnet, entweder 'Durch Null kann man nicht teilen!' ausgeben (falls b “ 0 ist) oder die gesuchten Werte ausgeben (falls b ‰ 0 ist). 1.3.6 Teilbarkeit überprüfen #------------------------------------------------------------------------# teilen_v3.py #------------------------------------------------------------------------import stdio, sys # Lies zwei int-Argumente a und b von der Kommandozeile. # Gib den (ganzzahligen) Quotienten und den Rest bei der Division von a durch b aus. a = int( sys.argv[1] ) b = int( sys.argv[2] ) if b == 0: text = ’Durch Null kann man nicht teilen!’ else: quotient = a//b rest = a%b text=str(a)+’ geteilt durch ’+str(b)+’ ist ’+str(quotient)+’ Rest ’+str(rest)+’.’ stdio.writeln(text) #------------------------------------------------------------------------# python teilen_v3.py 1234 23 # 1234 geteilt durch 23 ist 53 Rest 15. # 1.3.7 Geschachtelte if-Anweisungen Bei der Lösung der quadratischen Gleichung a ¨ x 2 ` b ¨ x ` c “ 0 mittels der Formel ? ´b ˘ b 2 ´ 4 ¨ a ¨ c x1,2 “ 2¨a kann es 1. keine Lösung geben, da b 2 ´ 4 ¨ a ¨ c ă 0 oder a “ 0, 2. eine Lösung geben, da b 2 ´ 4 ¨ a ¨ c “ 0 und a ‰ 0, oder 3. zwei Lösungen geben, da b 2 ´ 4 ¨ a ¨ c ą 0 und a ‰ 0. Mit einer if-Anweisung kann man zwei Fälle unterscheiden. Um drei Fälle zu unterscheiden, muss man if-Anweisungen ineinander schachteln. 1.3.8 # Das Programm midnight.py liest float-Werte a, b und c von der Kommandozeile ein # und gibt die beiden durch die Mitternachtsformel bestimmten Lösungen aus, # falls sie existieren. import stdio, sys, math a = float( sys.argv[1] ) b = float( sys.argv[2] ) c = float( sys.argv[3] ) z = b**2 - 4 * a * c if z<0 or a==0: stdio.writeln('Die Gleichung hat keine Loesung!') else: if z==0: stdio.writeln( -b / (2*a) ) else: diskriminante = math.sqrt(b**2 - 4 * a * c) stdio.writeln( (-b + diskriminante) / (2*a) ) stdio.writeln( (-b - diskriminante) / (2*a) ) #-------------------------------------#-------------------------------------# python midnight.py 3 4 5 # python midnight.py 2 4 2 # Die Gleichung hat keine Loesung! # -1.0 # # # python midnight.py 3 8 5 # python midnight.py 0 8 5 # -1.0 # Die Gleichung hat keine Loesung! # -1.66666666667 # # Das Programm midnight.py liest float-Werte a, b und c von der Kommandozeile ein # und gibt die beiden durch die Mitternachtsformel bestimmten Lösungen aus, # falls sie existieren. import stdio, sys, math a = float( sys.argv[1] ) b = float( sys.argv[2] ) c = float( sys.argv[3] ) z = b**2 - 4 * a * c if z<0 or a==0: stdio.writeln('Die Gleichung hat keine Loesung!') elif z==0: stdio.writeln( -b / (2*a) ) else: diskriminante = math.sqrt(b**2 - 4 * a * c) stdio.writeln( (-b + diskriminante) / (2*a) ) stdio.writeln( (-b - diskriminante) / (2*a) ) #-------------------------------------#-------------------------------------# python midnight.py 3 4 5 # python midnight.py 2 4 2 # Die Gleichung hat keine Loesung! # -1.0 # # # python midnight.py 3 8 5 # python midnight.py 0 8 5 # -1.0 # Die Gleichung hat keine Loesung! # -1.66666666667 # # Das Programm midnight.py liest float-Werte a, b und c von der Kommandozeile ein # und gibt die beiden durch die Mitternachtsformel bestimmten Lösungen aus, # falls sie existieren. import stdio, sys, math a = float( sys.argv[1] ) b = float( sys.argv[2] ) c = float( sys.argv[3] ) z = b**2 - 4 * a * c if z<0 or a==0: stdio.writeln('Die Gleichung hat keine Loesung!') else: diskriminante = math.sqrt(z) if diskrimante > 0: stdio.writeln( (-b + diskriminante) / (2*a) ) stdio.writeln( (-b - diskriminante) / (2*a) ) #-------------------------------------#-------------------------------------# python midnight.py 3 4 5 # python midnight.py 2 4 2 # Die Gleichung hat keine Loesung! # -1.0 # # # python midnight.py 3 8 5 # python midnight.py 0 8 5 # -1.0 # Die Gleichung hat keine Loesung! # -1.66666666667 # 1.3.11 while-Schleifen Üblicherweise bestehen Programme aus Anweisungen, die häufig wiederholt werden. Die while-Schleife erlaubt die Wiederholung eines Anweisungs-Blocks, solange eine vorgegebene Bedingung erfüllt ist. 1.3.12 # Das Programm while-zaehler.py liest int-Wert a von der Kommandozeile ein # und gibt die Zahlen von 0 bis a aus. import stdio, sys a = int( sys.argv[1] ) zaehler = 0 # wird in der folgenden while-Schleife bis a hochgezählt while zaehler <= a: stdio.writeln(str(zaehler)) zaehler = zaehler + 1 #----------------------------# python while-zaehler.py 4 # 0 # 1 # 2 # 3 # 4 # 5 #----------------------------# python while-zaehler.py 9 # 0 # 1 # 2 # 3 # 4 # 5 # 6 # 7 # 8 # 9 1.3.13 # Das Programm alleteiler.py liest int-Wert a von der Kommandozeile ein # und gibt alle Teiler von a aus. import stdio, sys a = int( sys.argv[1] ) zaehler = 1 # damit werden alle möglichn Teiler von 1 bis a durchprobiert while zaehler <= a: if a%zaehler == 0: stdio.writeln(str(zaehler)) zaehler = zaehler + 1 #-----------------------------------------------------------------------------------# python alleteiler.py 8 # 1 # 2 # 4 # 8 1.3.14 # Das Programm ganzlog.py liest int-Wert n von der Kommandozeile ein # und gibt den ganzzahligen Logarithmus von n zur Basis 2 aus. import stdio, sys n = int( sys.argv[1] ) ergebnis = 0 # damit wird gezählt, wie oft durch 2 geteilt werden kann while n > 1: ergebnis = ergebnis + 1 n = n//2 stdio.writeln(str(ergebnis)) #-----------------------------------------------------------------------------------# python ganzlog.py 2016 # 10 # # python ganzlog.py 2048 # 11 # # python ganzlog.py 2047 # 10 # 1.3.15 # Das Programm ganzlog-trace.py liest int-Wert n von der Kommandozeile ein # und gibt den ganzzahligen Logarithmus von n zur Basis 2 aus. import stdio, sys n = int( sys.argv[1] ) ergebnis = 0 # damit wird gezählt, wie oft durch 2 geteilt werden kann while n > 1: stdio.writeln('n ist ' + str(n) + ', ergebnis ist ' + str(ergebnis)) ergebnis = ergebnis + 1 n = n//2 stdio.writeln(str(ergebnis)) #-----------------------------------------------------------------------------------# python ganzlog-trace.py 538 # n ist 538, ergebnis ist 0 # n ist 269, ergebnis ist 1 # n ist 134, ergebnis ist 2 # n ist 67, ergebnis ist 3 # n ist 33, ergebnis ist 4 # n ist 16, ergebnis ist 5 # n ist 8, ergebnis ist 6 # n ist 4, ergebnis ist 7 # n ist 2, ergebnis ist 8 # 9 # Das Programm zweierpotenz-w.py liest int-Werte n von der Kommandozeile ein # und gibt die 2erPotenzen 1,2,...,2**n aus. # falls sie existieren. import stdio, sys n = int( sys.argv[1] ) i = 0 potenz = 1 # der Zähler für die Potenzen # die erste 2erPotenz ist 2**0 while i <= n: stdio.writeln(' 2 hoch ' + str(i) + ' ist ' + str(potenz) + '.') i = i + 1 potenz = potenz * 2 #--------------------------------------------------------------------------------# python zweierpotenz-w.py 5 # 2 hoch 0 ist 1. # 2 hoch 1 ist 2. # 2 hoch 2 ist 4. # 2 hoch 3 ist 8. # 2 hoch 4 ist 16. # 2 hoch 5 ist 32. 1.3.17 #----------------------------------------------------------------------# rueckzahlungsdauer.py #----------------------------------------------------------------------# Das Programm liest von der Kommandozeile die Werte # schulden (int), zinssatz (float) und jahresrate (int). # Es wird berechnet, wieviele Jahre die jahresrate bezahlt werden muss, # bis die schulden beim angebebenen zinssatz beglichen sind. #----------------------------------------------------------------------import stdio, sys schulden = int(sys.argv[1]) zinssatz = float(sys.argv[2]) jahresrate = int(sys.argv[3]) jahrezaehler = 0 # Zähler für die Jahre mit Ratenzahlungen while schulden > 0 : # der Schuldenstand nach einem Jahr und Rückzahlung einer Jahresrate schulden = schulden*(1 + zinssatz/100) - jahresrate jahrezaehler += 1 stdio.writeln(jahrezaehler) #-----------------------------------------------------------------------# python rueckzahlungsdauer.py 200000 3.5 12000 # 26 #-----------------------------------------------------------# while_hochzaehlen.py # Gibt * mit größer werdendem Abstand zum linken Rand aus. #-----------------------------------------------------------import stdio wiederholungen = 12 zaehler = 0 # die Anzahl der auszugebenden Zeilen # Zähler für die bereits ausgegebenen Zeilen while zaehler<wiederholungen: stdio.writeln(' '*zaehler + '*') zaehler = zaehler+1 #-----------------------------------------------------------# python while_hochzaehlen.py # * # * # * # * # * # * # * # * # * # * # * # * #------------------------------------------------------# zufallspfad.py #------------------------------------------------------# Gibt wiederholt * aus, dessen Abstand zum linken # Rand von Zeile zu Zeile # zufällig um -1,0,+1 verändert wird. #------------------------------------------------------- # python zufallspfad.py # * # * # * # * # * # * # * import stdio, random # * # * wiederholungen = 20 # die Anzahl der auszugebenden Zeilen # * i = 0 # Zähler für die bereits ausgegebenen Zeilen # * abstand = 5 # der Abstand vom linken Rand (Startwert ist 5) # * # * while i<wiederholungen: # * abstand = abstand + random.randrange(-1,2) # * stdio.writeln(' '*abstand + '*') # * i = i+1 # * #-------------------------------------------------------# * Standardfunktionen aus Pythons Modul random: randrange(a,b) ein zufällig gewählter int-Wert aus [a,b) für int-Werte a und b random() ein zufällig gewählter float-Wert aus dem Intervall r0, 1q 1.3.20 for-Schleifen Häufig wird in einer Schleife u.a. eine Variable hochgezählt und die Schleifen-Wiederholung endet, wenn ein bestimmter Wert erreicht wurde. Die for-Schleife erleichtert das Aufschreiben solcher Schleifen. 1.3.21 # Das Programm zweierpotenz-f.py liest int-Werte n von der Kommandozeile ein # und gibt die 2erPotenzen von 2**0, 2**1,...,2**n aus. import stdio, sys n = int( sys.argv[1] ) potenz = 1 # die erste 2erPotenz ist 2**0 for i in range(0,n+1): stdio.writeln(' 2 hoch ' + str(i) + ' ist ' + str(potenz) + '.') potenz = potenz * 2 #--------------------------------------------------------------------------------# python zweierpotenz-f.py 6 # 2 hoch 0 ist 1. # 2 hoch 1 ist 2. # 2 hoch 2 ist 4. # 2 hoch 3 ist 8. # 2 hoch 4 ist 16. # 2 hoch 5 ist 32. # 2 hoch 5 ist 64. 1.3.22 Simulation von Zufallsexperimenten Zwei Würfel werden 24mal geworfen. Wie wahrscheinlich ist es, dass mindestens einmal dabei zwei 6en geworfen werden? Statt die Wahrscheinlichkeit exakt auszurechnen, simulieren wir das Experiment mit einem Programm. 1.3.23 #----------------------------------------------------------# zweiwuerfel.py #----------------------------------------------------------import stdio, sys, random erfolgszaehler = 0 # zählt die erfolgreichen Experimente for i in range(0,100000): # es werden 100000 Experimente durchgeführt # Zwei Würfel werden 24mal geworfen. # Das Spiel ist erfolgreich, wenn dabei ein Wurf aus zwei 6en gelingt. for i in range(24): if random.randrange(1,7)==6 and random.randrange(1,7)==6: erfolgszaehler +=1 break # Auswertung stdio.writeln(float(erfolg)/versuchszahl) #-----------------------------------------------------------# python zweiwuerfel.py # python zweiwuerfel.py # 0.49203 # 0.49133 # # # python zweiwuerfel.py # python zweiwuerfel.py # 0.49023 # 0.49068 # #----------------------------------------------------------------------------# wuerfelsummen.py #----------------------------------------------------------------------------# Ermittle die Wahrscheinlichkeit, dass mit zwei Würfeln # eine bestimmte Zahl gewürfelt wird, mittels Simulation. import stdio, sys, random versuchszahl = 100000 # die Anzahl der Versuche in jedem Experiment # Für jede Würfelsumme von 2 bis 12 wird das Experiment durchgeführt for summe in range(2,13): erfolg = 0 # Zähler für die erfolgreichen Experimente # Das Experiment für summe wird versuchszahl mal durchgeführt. for i in range(0,versuchszahl): # Zwei Würfel werden geworfen. # DerWurf ist erfolgreich, wenn er Summe summe hat. if random.randrange(1,7) + random.randrange(1,7) == summe: erfolg += 1 # Ausgabe der Erfolgswahrscheinlichkeit (mit gut lesbarer Darstellung). stdio.writeln('Summe ' + ' '*(summe<10) + str(summe) + ': Wkeit. 1/' + str(round(1/(float(erfolg)/versuchszahl)))) 1.3.25 # # # # # # # # # # # # python wuerfelsummen.py Summe 2: Wkeit. 1/36 Summe 3: Wkeit. 1/18 Summe 4: Wkeit. 1/12 Summe 5: Wkeit. 1/9 Summe 6: Wkeit. 1/7 Summe 7: Wkeit. 1/6 Summe 8: Wkeit. 1/7 Summe 9: Wkeit. 1/9 Summe 10: Wkeit. 1/12 Summe 11: Wkeit. 1/18 Summe 12: Wkeit. 1/36 1.3.26 17 und 4 Wir spielen 17+4 mit Würfeln. Zwei Spieler spielen. Jeder würfelt, ohne dass es der andere sehen kann. Ziel des Spiels ist es, den Wert 21 zu erreichen. Dazu würfelt der Spieler mit seinem Würfel und summiert die gewürfelten Zahlen. Man kann jederzeit aufhören zu würfeln. Das Ergebnis des Spielers ist seine Summe der gewürfelten Zahlen. Ein Spieler mit einem Ergebnis ą 21 hat verloren. Haben beide Spieler ein Ergebnis ď 21, dann gewinnt der Spieler mit dem höheren Ergebnis. Wir wollen ein Programm entwickeln, mit dem man eine gute Strategie für das Spiel finden kann. Zuerst schreiben wir ein Programm, das einen Spieler simuliert, der solange würfelt, bis er mindestens 21 erreicht hat. #----------------------------------------------------------------------------------# siebzehnundvier_1.py #----------------------------------------------------------------------------------import stdio, sys, random Wuerfelsumme = 0 # die bisher erreichte Summe von Würfen while Wuerfelsumme<21: Wuerfelsumme = Wuerfelsumme + random.randrange(1,7) stdio.writeln('Wuerfelsumme ist ' + str(Wuerfelsumme)) stdio.writeln('Ergebnis: ' + str(Wuerfelsumme)) #-----------------------------------------------------------------------------------# python siebzehnundvier_1.py # Wuerfelsumme ist 5 # Wuerfelsumme ist 8 # Wuerfelsumme ist 10 # Wuerfelsumme ist 11 # Wuerfelsumme ist 15 # Wuerfelsumme ist 20 # Wuerfelsumme ist 21 # Ergebnis: 21 1.3.28 Eine Strategie ist es, nicht weiterzuwürfeln, wenn man 16 oder mehr erreicht hat. Dann hat man garantiert ein Ergebnis ď 21. #----------------------------------------------------------------------------------# siebzehnundvier_2.py #----------------------------------------------------------------------------------import stdio, sys, random Wuerfelsumme = 0 while Wuerfelsumme<=15: Wuerfelsumme = Wuerfelsumme + random.randrange(1,7) stdio.writeln('Wuerfelsumme ist ' + str(Wuerfelsumme)) stdio.writeln('Ergebnis: ' + str(Wuerfelsumme)) #-----------------------------------------------------------------------------------# python siebzehnundvier_2.py # Wuerfelsumme ist 6 # Wuerfelsumme ist 8 # Wuerfelsumme ist 10 # Wuerfelsumme ist 12 # Wuerfelsumme ist 16 1.3.29 Eine andere Strategie ist es, nicht weiterzuwürfeln, wenn man 17 oder mehr erreicht. Wenn man 16 erreicht hat, geht man ein kleines Risiko ein . . . #----------------------------------------------------------------------------------# siebzehnundvier_3.py #----------------------------------------------------------------------------------import stdio, sys, random Wuerfelsumme = 0 while Wuerfelsumme<=16: Wuerfelsumme = Wuerfelsumme + random.randrange(1,7) stdio.writeln('Wuerfelsumme ist ' + str(Wuerfelsumme)) stdio.writeln('Ergebnis: ' + str(Wuerfelsumme)) #-----------------------------------------------------------------------------------# python siebzehnundvier_3.py # Wuerfelsumme ist 2 # Wuerfelsumme ist 4 # Wuerfelsumme ist 7 # Wuerfelsumme ist 10 # Wuerfelsumme ist 14 # Wuerfelsumme ist 16 # Wuerfelsumme ist 22 # Ergebnis: 22 1.3.30 Welche der beiden Strategien ist besser? Wir wollen das experimentell überprüfen. Dafür lassen wir zwei Spieler mit den beiden Strategien gegeneinander spielen und schauen nach, wer gewinnt. #----------------------------------------------------------------------------------# siebzehnundvier_4.py #----------------------------------------------------------------------------------import stdio, sys, random # Spieler 1 spielt mit seiner Strategie. Wuerfelsumme1 = 0 while Wuerfelsumme1<=15: Wuerfelsumme1 = Wuerfelsumme1 + random.randrange(1,7) # Spieler 2 spielt mit seiner Strategie. Wuerfelsumme2 = 0 while Wuerfelsumme2<=16: Wuerfelsumme2 = Wuerfelsumme2 + random.randrange(1,7) # Der Gewinner wird bestimmt. if Wuerfelsumme1<=21 and ( Wuerfelsumme2>21 or Wuerfelsumme1>Wuerfelsumme2): stdio.writeln('Spieler 1 gewinnt.') elif Wuerfelsumme2<=21 and ( Wuerfelsumme1>21 or Wuerfelsumme2>Wuerfelsumme1): stdio.writeln('Spieler 2 gewinnt.') 1.3.31 Schließlich lassen wir die Spieler 100000mal gegeneinander spielen, und zählen, wie oft jeder gewinnt. 1.3.32 # Wir benutzen zwei Zähler für die Gewinne jedes Spielers. gewinne1 = 0 gewinne2 = 0 # Wir lassen die beiden Spieler 1000000 Spiele spielen. for i in range(100000): # Spieler 1 spielt mit seiner Strategie. Wuerfelsumme1 = 0 while Wuerfelsumme1<=15: Wuerfelsumme1 = Wuerfelsumme1 + random.randrange(1,7) # Spieler 2 spielt mit seiner Strategie. Wuerfelsumme2 = 0 while Wuerfelsumme2<=16: Wuerfelsumme2 = Wuerfelsumme2 + random.randrange(1,7) # Der Gewinner wird bestimmt und sein Gewinn-Zähler wird um 1 erhöht. if Wuerfelsumme1<=21 and ( Wuerfelsumme2>21 or Wuerfelsumme1>Wuerfelsumme2): gewinne1 = gewinne1 + 1 elif Wuerfelsumme2<=21 and ( Wuerfelsumme1>21 or Wuerfelsumme2>Wuerfelsumme1): gewinne2 = gewinne2 + 1 # Gib aus, wer öfter gewonnen hat. if gewinne1>gewinne2: stdio.writeln('Spieler 1 hat ' + str(gewinne1-gewinne2) + 'mal oefter gewonnen als Spieler 2.') else: stdio.writeln('Spieler 2 hat ' + str(gewinne2-gewinne1) + 'mal oefter gewonnen als Spieler 1.') #----------------------------------------------------------------------------------------------# python siebzehnundvier_5.py # Spieler 2 hat 26584mal oefter gewonnen als Spieler 1. 1.3.33 Zusammenfassung § Wir haben if-Anweisungen, while-Schleifen und for-Schleifen kennengelernt. § Wir kennen die Strukturierung von Programmen in Anweisungs-Blöcke. § Wir können einfache Programme mit Eingabe von Argumenten Abarbeitung von Anweisungs-Blöcken, die in Schleifen wiederholt oder durch if-Anweisungen ausgeführt oder übersprungen werden Ausgabe von Ergebnissen schreiben und deren Ausführung nachvollziehen.