CUBE.CODES: Schleifen mit for: Unterschied zwischen den Versionen

Aus MINT.lentner.net
Zur Navigation springen Zur Suche springen
 
(32 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
 
__NOTOC__
 
__NOTOC__
 
[https://ide.cube.codes CUBE.CODES blank]
 
[https://ide.cube.codes CUBE.CODES blank]
===Programm 1: für(... ) tue ... ===
+
==Programm 1: für(... ) tue ... ==
   for(i=1; i<1000; i=i+1) UI.log(i);
+
   for(i=1; i<10; i=i+1) UI.log(i);
  
Das Sprachkonstrukt '''for(<Anfangsbefehl>; <Wiederholungsbedingung>; <Veränderung>)''' vor dem Befehl '''UI.log(i)''' steuert ähnlich dem while-Konstrukt, wie der Befehl '''UI.log(i)''' wiederholt wird. Man kann aber alle typischen Wünsche einer einzelnen Zeile unterbringen:
+
führt zur Ausgabe ...
#Der '''<Anfangsbefehl>''' wird ausgeführt bevor alles losgeht. Dabei setzt man meistens die Zählervariable auf einen gewünschten Anfangszustand. Man kann aber auch beliebige andere Befehle anfangs ausführen lassen.
+
[08:26:54] Program starting ...
#Die '''<Wiederholungsbedingung>'''
+
[08:27:00] Program running ...
#Die '''<Veränderung>'''
+
1
 +
2
 +
3
 +
4
 +
5
 +
6
 +
7
 +
8
 +
9
 +
[08:27:00] Program finished successfully
 +
 +
Das Sprachkonstrukt '''for(<Anfangsbefehl>; <Wiederholungsbedingung>; <Veränderung>)''' vor dem Befehl '''UI.log(i)''' steuert ähnlich dem while-Konstrukt, '''wie''' der nachfolgende Befehl (hier: UI.log(i)) '''wiederholt wird'''. Man kann aber (anders als bei while) alle typischen Wünsche einer einzigen Zeile unterbringen:
 +
#Der '''<Anfangsbefehl>''' wird ausgeführt, bevor alles losgeht. Dabei setzt man meistens die Zählervariable auf einen gewünschten Anfangszustand. Man kann aber auch beliebige andere Befehle anfangs ausführen lassen.
 +
#Die '''<Wiederholungsbedingung>''' wird immer überprüft, bevor der nachfolgende Befehl ausgeführt wird. Trifft die Bedingung zu, wird er (nochmal) ausgeführt, trifft er nicht (mehr) zu, wird der nachfolgende Befehl nicht mehr ausgeführt, also die Serie unterbrochen.
 +
#Die '''<Veränderung>''' ist ein Befehl, der nach jeder Durchführung ausgeführt wird. Wir benutzen ihn meist, um die Zählervariable zu verändern. Würden wir die Situation nicht verändern, wäre die Wiederholungsbedingung ja immer richtig und wir hätten eine '''Endlosschleife'''.
  
===Programm 1a: Was tut sich während der Wiederholung? - Wiederhole ganze Programmblöcke===
+
==Übungsprogramme 2: Teste die folgenden Schleifen==
  //Wiederholungen ganzer Blöcke
+
  for(i=0; i<100; i=i+2) UI.log(i);
  x=1;
+
  for(i=1; i<100; i=i+2) UI.log(i);
  while(x<101)  
+
  for(i=1; i<1000; i=i*2) UI.log(i);
    {
+
for(i=100; i>-1; i=i-1) UI.log(i);
    x=x+1;
+
for(i=1; i<10; i=i+1) UI.log("1/"+i);
    UI.log(x);
+
for(i=1; i>0; i=i/2) UI.log(i);
    }
 
  
Man kann also ganz offensichtlich durch Schleifen in einem Programm Berechnungen beliebig oft - auch variiert - wiederholen und dadurch viel mächtigere Berechnungen realisieren als in einer Tabellenkalkulation, in der wir immer nur '''einen Term''' für eine Berechnung formulieren konnten.
+
==Übungsprogramme 3: Man kann damit in einer Zeile auch einfach Wertetabellen ausgeben, die beliebig skaliert sind==
 +
for(i=0; i<100; i=i+1) UI.log(i+" - "+i*i);
 +
for(i=-10; i<=10; i=i+1) UI.log(i+" | "+i*i);
 +
for(i=0; i<1000; ++i) UI.log(i+" | "+(3*i+11));
 +
for(i=-10; i<=10; i=i+0.5) UI.log(i+" | "+(2*i*i-i+2.5));
  
[[Datei: 10dm.jpg | thumb | links]]
+
==Programm 4: Teiler ermitteln==
 +
Auch unser Teilerprogramm können wir jetzt '''in einer einzigen Zeile''' verwirklichen
 +
for(i=1; i<=2000; ++i) if(2000%i==0) UI.log(i);
  
===Das Gaußsche Kinderwunder===
+
... führt zur Ausgabe:
Von [https://de.wikipedia.org/wiki/Carl_Friedrich_Gau%C3%9F Carl Friedrich Gauß] (* 30. April 1777 in Braunschweig, † 23. Februar 1855 in Göttingen) geht die Geschichte um, dass er in der 1. Klasse Grundschule schon seine erste Mathematische Erfindung tätigte, als sein Lehrer der Klasse die Übungsaufgabe aufgab: '''Addiert alle Zahlen von 1 bis 100!'''
+
[07:57:54] Program starting ...
 +
[07:58:00] Program running ...
 +
1
 +
2
 +
4
 +
5
 +
8
 +
10
 +
16
 +
20
 +
25
 +
40
 +
50
 +
80
 +
100
 +
125
 +
200
 +
250
 +
400
 +
500
 +
1000
 +
2000
 +
[07:58:00] Program finished successfully
  
Der kleine Carl Friedrich soll sich sogleich gemeldet haben mit der Antwort '''5050'''. Wie hat er das wohl gemacht? Schließlich ist ...
+
==Übungsprogramme 5: Wir wiederholen mehrere Befehle ==
 +
Dass die Folge dreier Sprachelemente in '''for(i=1; i<=2000; ++i) if(2000%i==0) UI.log(i);''' (Programm 4) so unproblematisch funktioniert, verwundert Euch vielleicht und ist auch nicht selbstverständlich. Vergleiche dazu die vier Programme:
  
'''1 + 2 + 3 + 4 + 5 + ...      + 98 + 99 + 100 ='''
+
'''Programm5a:'''
 +
for(i=1; i<=10; ++i) y=i*2; UI.log(y);
  
... ja für Erstklässler keine '''"Aufgabe auf einen Blick"'''. Tja hängt wohl vom persönlichen Blick ab! JavaSkript kann da etwas hölzerner vorgehen ...:
+
und ...
<br style="clear:left; ">
 
  
===Programm 2: Das Gaußsche Kinderwunder===
+
'''Programm5b:'''
  //Das Gaußsche Kinderwunder
+
  for(i=1; i<=10; ++i) {y=i*2; UI.log(y);}
x=1;
 
summe=0;
 
while(x<=100)  
 
  {
 
    summe=summe+x;
 
    UI.log(summe);
 
    x=x+1;
 
  }
 
  
===Programm 2a: JavaScript hat als Ableger der Abkürzungsfanatikersprache '''C''' einige solche Tipps für uns parat ...===
+
sowie
//Das Gaußsche Kinderwunder
 
x=0; summe=0;
 
while(++x<=100) summe+=x;
 
UI.log(summe);
 
  
===Programm 3: Den Zauberwürfel bewegen===
+
'''Programm5c:'''
  //Was passiert, wenn ich einen MOVE immer wieder mache?
+
  for(i=1; i<=2000; ++i) if(2000%i==0) UI.log(i);
    await CUBE.move(" E R ");
 
    while(!CUBE.isSolved()) await CUBE.move(" E R ");
 
//Probier's mal mit dem MOVE RBLF! :-) Viel Spaß!
 
  
Lässt man die erste Codezeile weg, klingt das Programm auch umgangssprachlich vernünftig, "funktioniert aber nicht"! Probier's! Natürlich funktioniert die Schleife. Sie macht, was sie soll, nämlich: Den Zug ausführen, '''solange der Würfel ungelöst ist'''. Aber der Würfel ist ja am Anfang gelöst. Also alles richtig! Die Schleife wird nicht mal ein einziges Mal ausgeführt, weil die Wiederholungsbedingung ja schon beim ersten Mal nicht erfüllt ist.
+
und ...
  
Gibt es nicht eine einfachere Möglichkeit, zu sagen, dass '''der PC die Schleife auf jeden Fall einmal macht''' und erst vor '''der wirklichen Wiederholung''' die Bedingung abfragt? Sonst müsste man (auch bei längeren Wiederholungsblöcken) immer den Befehlsblock nochmal extra vor die Schleife kopieren, damit der PC den Block einmal ausführt und dann erst über die Wiederholung berät!
+
'''Programm5d:'''
 +
for(i=1; i<=2000; ++i) {if(2000%i==0) UI.log(i);}
  
===Die Lösung ist Programm 3a: Mach {... } solange(... ) ===
+
=== Was hat es mit den vier Varianten auf sich? ===
do await CUBE.move(" E R "); while(!CUBE.isSolved())
 
  
===Programm 3b: Ich möchte mitzählen===
+
'''Programm5a:'''
  i=0;
+
for(i=1; i<=10; ++i) y=i*2; UI.log(y);
  do
+
Führt zur Ausgabe ...
    {
+
[08:09:54] Program starting ...
      await CUBE.move(" E R ");  
+
[08:10:00] Program running ...
      ++i;
+
20
    } while(!CUBE.isSolved())
+
[08:10:01] Program finished successfully
  UI.log(i);
+
# ... gibt es nur eine (!) Ausgabe mit UI.log(y). Der Wiederholungsoperator gilt also '''nur für den nachfolgenden''' Befehl y=i*2; . UI.log(y) wird also erst ausgeführt, nachdem die komplette Schleife beendet ist. Die Ausgabe ist aber nicht 22, obwohl am Ende der Schleife i==11 ist! Der Befehl y=i*2; wurde ja als letztes (in der Schleife) ausgeführt, als i noch 10 war. Daher wurde als letztes y=i*2; für i=10 berechnet. Also die Ausgabe 20!
 +
# Die Formulierung {for(i=1; i<=10; ++i) y=i*2;} UI.log(y); wäre vielleicht klarer und ist auch korrekt. Die Vorrangregel aus 1. macht aber die Klammerung überflüssig.
 +
# Programme sollen aber nicht nur mystifying korrekt sein sondern auch leicht verständlich, daher würde wohl jeder Programmierer Programm 5a folgendermaßen notieren:
 +
'''Programm5a':'''
 +
for(i=1; i<=10; ++i) y=i*2;
 +
UI.log(y);
  
CUBE muss also den Zug (E R) acht mal ausführen, damit der CUBE wieder so aussieht, wie am Anfang. Das ist übrigens bei jedem Zug so, dass er irgendwann zum gelösten Zustand zurückkehrt. Man nennt diese Zahl die Ordnung(E R)!
+
'''Programm5b:''' Klammert nun die hinteren beiden Befehle und fasst sich somit zu einem einzigen '''Befehlsblock''' zusammen. Die Zeile
 +
 +
for(i=1; i<=10; ++i) {y=i*2; UI.log(y);}
  
Bestimme die Ordnungen der folgenden Züge:
+
führt also jetzt zur Ausgabe ...
* '''F2 R2 U2 F' B D2 L2 F B''' (Ordnung 6)
 
* '''R' y''' (Ordnung 1206)
 
* '''M' S' M S''' (Ordnung 3)
 
* '''L M R D E U B S F''' (Ordnung 4)
 
  
Finde Züge mit möglichst großer Ordnung!<p>
+
[08:35:19] Program starting ...
[https://ide.cube.codes/?init=loadFromUrl&url=https://share-repository.cube.codes/v1/appStates/7d280477-8a4a-4d06-9fb6-deb3244c7e0f Ordnung von Zügen ausprobieren!]
+
[08:35:26] Program running ...
 +
2
 +
4
 +
6
 +
8
 +
10
 +
12
 +
14
 +
16
 +
18
 +
20
 +
[08:35:26] Program finished successfully
 +
 
 +
Anders ist die Situation bei Programm 5c und 5d:

Aktuelle Version vom 21. Januar 2022, 09:36 Uhr

CUBE.CODES blank

Programm 1: für(... ) tue ...

 for(i=1; i<10; i=i+1) UI.log(i);

führt zur Ausgabe ...

[08:26:54] Program starting ...
[08:27:00] Program running ...
1
2
3
4
5
6
7
8
9
[08:27:00] Program finished successfully

Das Sprachkonstrukt for(<Anfangsbefehl>; <Wiederholungsbedingung>; <Veränderung>) vor dem Befehl UI.log(i) steuert ähnlich dem while-Konstrukt, wie der nachfolgende Befehl (hier: UI.log(i)) wiederholt wird. Man kann aber (anders als bei while) alle typischen Wünsche einer einzigen Zeile unterbringen:

  1. Der <Anfangsbefehl> wird ausgeführt, bevor alles losgeht. Dabei setzt man meistens die Zählervariable auf einen gewünschten Anfangszustand. Man kann aber auch beliebige andere Befehle anfangs ausführen lassen.
  2. Die <Wiederholungsbedingung> wird immer überprüft, bevor der nachfolgende Befehl ausgeführt wird. Trifft die Bedingung zu, wird er (nochmal) ausgeführt, trifft er nicht (mehr) zu, wird der nachfolgende Befehl nicht mehr ausgeführt, also die Serie unterbrochen.
  3. Die <Veränderung> ist ein Befehl, der nach jeder Durchführung ausgeführt wird. Wir benutzen ihn meist, um die Zählervariable zu verändern. Würden wir die Situation nicht verändern, wäre die Wiederholungsbedingung ja immer richtig und wir hätten eine Endlosschleife.

Übungsprogramme 2: Teste die folgenden Schleifen

for(i=0; i<100; i=i+2) UI.log(i);
for(i=1; i<100; i=i+2) UI.log(i);
for(i=1; i<1000; i=i*2) UI.log(i);
for(i=100; i>-1; i=i-1) UI.log(i);
for(i=1; i<10; i=i+1) UI.log("1/"+i);
for(i=1; i>0; i=i/2) UI.log(i);

Übungsprogramme 3: Man kann damit in einer Zeile auch einfach Wertetabellen ausgeben, die beliebig skaliert sind

for(i=0; i<100; i=i+1) UI.log(i+" - "+i*i);
for(i=-10; i<=10; i=i+1) UI.log(i+" | "+i*i);
for(i=0; i<1000; ++i) UI.log(i+" | "+(3*i+11));
for(i=-10; i<=10; i=i+0.5) UI.log(i+" | "+(2*i*i-i+2.5));

Programm 4: Teiler ermitteln

Auch unser Teilerprogramm können wir jetzt in einer einzigen Zeile verwirklichen

for(i=1; i<=2000; ++i) if(2000%i==0) UI.log(i);

... führt zur Ausgabe:

[07:57:54] Program starting ...
[07:58:00] Program running ...
1
2
4
5
8
10
16
20
25
40
50
80
100
125
200
250
400
500
1000
2000
[07:58:00] Program finished successfully

Übungsprogramme 5: Wir wiederholen mehrere Befehle

Dass die Folge dreier Sprachelemente in for(i=1; i<=2000; ++i) if(2000%i==0) UI.log(i); (Programm 4) so unproblematisch funktioniert, verwundert Euch vielleicht und ist auch nicht selbstverständlich. Vergleiche dazu die vier Programme:

Programm5a:

for(i=1; i<=10; ++i) y=i*2; UI.log(y);

und ...

Programm5b:

for(i=1; i<=10; ++i) {y=i*2; UI.log(y);}

sowie

Programm5c:

for(i=1; i<=2000; ++i) if(2000%i==0) UI.log(i);

und ...

Programm5d:

for(i=1; i<=2000; ++i) {if(2000%i==0) UI.log(i);}

Was hat es mit den vier Varianten auf sich?

Programm5a:

for(i=1; i<=10; ++i) y=i*2; UI.log(y);

Führt zur Ausgabe ...

[08:09:54] Program starting ...
[08:10:00] Program running ...
20
[08:10:01] Program finished successfully
  1. ... gibt es nur eine (!) Ausgabe mit UI.log(y). Der Wiederholungsoperator gilt also nur für den nachfolgenden Befehl y=i*2; . UI.log(y) wird also erst ausgeführt, nachdem die komplette Schleife beendet ist. Die Ausgabe ist aber nicht 22, obwohl am Ende der Schleife i==11 ist! Der Befehl y=i*2; wurde ja als letztes (in der Schleife) ausgeführt, als i noch 10 war. Daher wurde als letztes y=i*2; für i=10 berechnet. Also die Ausgabe 20!
  2. Die Formulierung {for(i=1; i<=10; ++i) y=i*2;} UI.log(y); wäre vielleicht klarer und ist auch korrekt. Die Vorrangregel aus 1. macht aber die Klammerung überflüssig.
  3. Programme sollen aber nicht nur mystifying korrekt sein sondern auch leicht verständlich, daher würde wohl jeder Programmierer Programm 5a folgendermaßen notieren:

Programm5a':

for(i=1; i<=10; ++i) y=i*2;
UI.log(y);

Programm5b: Klammert nun die hinteren beiden Befehle und fasst sich somit zu einem einzigen Befehlsblock zusammen. Die Zeile

for(i=1; i<=10; ++i) {y=i*2; UI.log(y);}

führt also jetzt zur Ausgabe ...

[08:35:19] Program starting ...
[08:35:26] Program running ...
2 
4 
6
8
10
12
14
16
18
20
[08:35:26] Program finished successfully

Anders ist die Situation bei Programm 5c und 5d: