Lazarus/Computer-Mathematik und Lazarus/Schleifen: Unterschied zwischen den Seiten

Aus ZUM-Unterrichten
< Lazarus(Unterschied zwischen Seiten)
main>Peterdauscher
Keine Bearbeitungszusammenfassung
 
main>Peterdauscher
 
Zeile 1: Zeile 1:
"Computer" heißt wörtlich übersetzt "Rechner" und deshalb wäre es ja jetzt auch Zeit, ein Programm auch einmal etwas ausrechnen zu lassen.
{{Lazarus-Buch}}


Dafür muss das Programm drei Dinge tun:
== Zählschleifen ==
Mit Hilfe von Alternativen (if-then-else) konnten wir Programme so steuern, dass bestimmte Anweisungen nur unter ganz bestimmten Bedingungen ausgeführt wurden, andernfalls nicht. Allerdings wurde die gleiche Anweisung (bei ein und demselben Knopfdruck) immer nur ein einziges Mal ausgeführt.


*Die Zahlen, die verrechnet werden müssen, müssen von der Benutzeroberfläche eingelesen werden.
Bei vielen Dingen ist es jedoch sinnvoll, wenn Dinge mehrfach ausgeführt werden. Nicht umsonst heißt es: "Ein Computer ist unglaublich dumm, aber sehr sehr fleißig". So könnte eine sehr einfache Aufgabe an den Computer lauten, er solle die Zahlen von 1 bis 10 nacheinander in das Memo-Feld <tt>Memo1</tt> schreiben. Natürlich könnten wir den Befehl <tt>WriteLnTo(Memo1,1)</tt> zehn mal untereinander kopieren und dann die Zahlen zwischen den Klammern verändern. Aber das wäre sehr sehr lästige -- und schlimmer noch -- langweilige Arbeit.
*Die Zahlen müssen zu einem Ergebnis verrechnet werden.
*Das Ergebnis der Verrechnung muss auf der Benutzeroberfläche ausgegeben werden.


== Arbeiten von Integer-Variablen ==
Viel bequemer ist es dagegen, wenn wir dem Computer sagen:
=== Einlesen von Integer-Variablen ===


Gibt ein Benutzer eine Zahl ein, steht sie in der Eigenschaft <tt>Text</tt>. Jedenfalls stehen die einzelnen Ziffern als Zeichenkette in der Eigenschaft <tt>Text</tt>. Aus der Zeichenkette z.B. in <tt>Edit1.Text</tt> muss jetzt eine "richtige" Zahl (z.B. vom Typ <tt>integer</tt>) werden.
"Es gibt eine Variable <tt>zaehler</tt>. Setze diese Variable zunächst auf 1 und zähle sie dann schrittweise auf 10 hoch. Nach jedem Zählschritt schreibe den Wert der Variable in das Memo-Feld." Genau dies tut das folgende Programm. (Es ist nur die entscheidende Prozedur vermerkt, den Rest kennst Du mittlerweile).


Das besorgt der Befehl <tt>StrToInt</tt>:
<source lang="pascal">
a:=StrToInt(Edit1.Text);
</source>


Diese Zeile sorgt dafür, dass der Integer-Variablen <tt>a</tt> die Wert zugewiesen wird, die der Benutzer in das Edit-Feld <tt>Edit1</tt> geschrieben hat.
{{kasten_blau|<source  line start="30" highlight="5-6" lang="pascal">
procedure TForm1.Button1Click(Sender: TObject);
var zaehler : integer;
begin
Clear(Memo1);
for zaehler := 1 to 10
do WriteLnTo(Memo1,zaehler);
end;                     
</source>}}


Bevor man jedoch der Variable <tt>a</tt> einen Wert zuweisen kann, muss der Computer wissen, dass es überhaupt eine Integer-Variable mit Namen <tt>a</tt> gibt.
Auch hier können bei jedem Zählschritt auch mehrere Anweisungen ausgeführt werden; die muss man hier wieder mit <tt>begin</tt> und <tt>end</tt> zu einem Anweisungsblock gruppieren:  
 
{{kasten_blau|<source  line start="30" highlight="5-9" lang="pascal">
Dies geschieht mit Hilfe einer so genannten Variablendeklaration:
procedure TForm1.Button1Click(Sender: TObject);
<source lang="pascal">
var zaehler : integer;
var a : integer;
begin
</source>
Clear(Memo1);
 
for zaehler := 1 to 10
Wichtig: Dieser Befehl steht noch vor dem <tt>Begin</tt>.
do begin
 
  WriteTo(Memo1,zaehler);
=== Rechnen mit Integer-Variablen ===
  WriteLnTo(Memo1,'. Runde)
Nehmen wir an, wir hätten drei Integer-Variablen, <tt>a</tt>,<tt>b</tt> und <tt>c</tt>. Das Programm soll nun die Summe der Werte in <tt>a</tt> und <tt>b</tt> ausrechnen; das Ergebnis soll in der Variablen <tt>c</tt> gespeichert werden.
  end;
 
end;                     
Dies erreicht man wieder mit einem Zuweisungsbefehl mit dem stilisierten Pfeil nach links:
</source>}}
<source lang="pascal">
c := a+b;
</source>
 
Natürlich gibt es neben der Addition von Integer-Zahlen auch andere Rechenoperationen:
 
{| class ="wikitable toptextcells"
! Rechenoperation
! Rechenzeichen <br />in der Sprache Pascal
! Beispiel
|-
| Addition || <nowiki>+</nowiki> || c:=a+b;
|-
| Subtraktion || <nowiki>-</nowiki> || c:=a-b;
|-
| Multiplikation || <nowiki>*</nowiki> || c:=a*b;
|-
| (ganzzahlige) Division|| <nowiki>div</nowiki> || c:=a div b;
|-
| Rest der (ganzzahligen) Division|| <nowiki>mod</nowiki> || c:=a mod b;
|}
 
Die ganzzahlige Division ist die Division, die die meisten von uns aus der Grundschule kennen:
 
<math>34 : 5 = 6 \text{ Rest } 4</math>
 
Den Wert "6" würde dann die Rechenoperation <tt>34 div 5</tt> liefern, den Wert "4" die Operation <tt>34 mod 5</tt>.
 
=== Ausgabe von Integer-Variablen ===
 
Bisher steht das Ergebnis nur in der Variable <tt>c</tt>. Der Benutzer des Programms sieht davon gar nichts. Der Wert muss noch irgendwie auf der Oberfläche erscheinen. Eine Möglichkeit dazu wäre, die Zahl in ein weiteres Edit-Feld zu schreiben:
 
<source lang="pascal">
Edit3.Text:=IntToStr(c);
</source>
 
=== Das ganze Programm zum Rechnen mit Integer-Zahlen ===
Das folgende Programm funktioniert, wenn es auf der Oberfläche die Komponenten <tt>Edit1</tt>, <tt>Edit2</tt> und <tt>Button1</tt> gibt.
{{kasten_blau|<source  line highlight="33-44" lang="pascal">
unit zahlen_main;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls;
 
type
 
  { TForm1 }
 
  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    procedure Button1Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;
 
var
  Form1: TForm1;


implementation
== Schleifen mit Eingangsbedingung (while-Schleifen)==
 
Nehmen wir an, ein (recht phantasieloser) Lehrer gäbe seinen Schüler die Stillarbeit, so viele aufeinanderfolgende Zahlen zu addieren und die Zwischenergebnisse zu notieren, bis die Summe den Wert 1000 erreicht. Schüler Fritz hat sein Netbook im Ranzen und will das Problem mit Lazarus lösen. Das Problem: Er kann jetzt natürlich auf gut Glück ungefähr raten, bis zu welcher Zahl er die Zahlen addieren muss und dies mit einer for-Schleife tun. Aber es muss doch auch eine andere Möglichkeit geben, nämlich, dass der Computer selbst merkt, wenn das Ergebnis erreicht ist. Tatsächlich gibt es diese Möglichkeit:
{ TForm1 }


{{kasten_blau|<source  line start="30" highlight="6-15" lang="pascal">
procedure TForm1.Button1Click(Sender: TObject);
procedure TForm1.Button1Click(Sender: TObject);
var a : integer; // wir erfinden eine Zahlen-Variable a
var zaehler : integer;
     b : integer; // wir erfinden eine Zahlen-Variable b
     summe : integer;
    c : integer;  // wir erfinden eine Zahlen-Variable c
 
begin
begin
a:=StrToInt(Edit1.Text); // belege die Variablen
Clear(Memo1);
b:=StrToInt(Edit2.Text); // mit den Inhalten der Edit-Felder
zaehler:=0;
 
summe:=0;
c:=a+b; // Addiere a und b und weise den Wert der Variable c zu
while summe<1000
Edit3.Text:=IntToStr(c);
do begin
end;
  zaehler:=zaehler+1;
 
  summe:=summe+zaehler;
initialization
  WriteTo(Memo1,zaehler);
  {$I zahlen_main.lrs}
  WriteTo(Memo1,':');
 
  WriteLnTo(Memo1,summe);
end.
  end;
end;             
</source>}}
</source>}}


==Arbeiten mit Reellen Zahlen==
Man erkennt deutliche Unterschiede: Die Schleife, so heißt es in dem Programm, wird so lange wiederholt, solange die Summe noch einen Wert kleiner als 1000 hat. Das Setzen des Zählers auf 0 am Anfang und das Hochzählen in jedem einzelnen Schritt, muss der Programmierer hier selbst übernehmen (Zeilen 35 bzw. 39).
Das Arbeiten mit reellen Zahlen vom Typ <tt>real</tt> oder <tt>double</tt> funktioniert sehr ähnlich, mit ein paar kleinen Unterschieden:


Statt <tt>IntToStr</tt> und <tt>StrToInt</tt> werden hier die Befehle <tt>FloatToStr</tt> und sinnvollerweise <tt>format</tt> verwendet.
'''Wichtige Anmerkung''':
Angenommen, man würde in Zeile 36 den anfänglichen Wert der Variable <tt>summe</tt> auf 1000 setzen, so würde der Computer sozusagen gar nicht erst mit der Schleife anfangen, sondern alles zwischen <tt>while</tt> und dem <tt>end</tt> der Schleife überspringen. Denn die Schleife soll ja nur solange ausgeführt werden, solange die Bedingung <tt>summe<1000</tt> erfüllt ist. Und das wäre sie in diesem Fall ja von Anfang an nicht. Deshalb spricht man bei der while-Schleife auch von einer Schleife mit Eingangsbedingung.


Die Zeile
== Schleifen mit Abbruchbedingung (repeat-until-Schleifen) ==
<source lang="pascal">
Edit3.Text:=format('%5.2f',[c]);
</source>
sorgt dafür, dass die double-Variable <tt>c</tt> in das Edit-Feld geschrieben wird, dass sie insgesamt 5 Stellen und 2 Nachkommastellen hat.


{{kasten_blau|<source  line highlight="33-44" lang="pascal">
Anders ist es bei Schleifen mit Abbruchsbedingung. Bei denen wird das Innere der Schleife mindestens einmal durchlaufen. Eine solche Schleife ist in Pascal die so genannte Repeat-Until-Schleife. Unser Problem mit dem Aufsummieren von Zahlen bis zur Summe 1000 könnte mit einer solchen Schleife so aussehen:
unit rzahlen_main;


{$mode objfpc}{$H+}
{{kasten_blau|<source  line start="30" highlight="6-14" lang="pascal">procedure TForm1.Button1Click(Sender: TObject);
 
var zaehler : integer;
interface
    summe : integer;
 
begin
uses
Clear(Memo1);
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls;
zaehler:=0;
 
summe:=0;
type
  repeat
 
  zaehler:=zaehler+1;
  { TForm1 }
  summe:=summe+zaehler;
  WriteTo(Memo1,zaehler);
  WriteTo(Memo1,':');
  WriteLnTo(Memo1,summe);
  until summe>1000;
end;   
</source>}}


  TForm1 = class(TForm)
Das Programm verhält sich haargenau wie das Programm mit der While-Schleife. Solange man nicht die Summe vorher größer oder gleich 1000 wählt. Würde man das tun, würde zumindest ein Summations- und Schreibschritt ausgeführt und erst dann die Schleife abgebrochen.
    Button1: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    procedure Button1Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{ TForm1 }
 
procedure TForm1.Button1Click(Sender: TObject);
var a : double;  // wir erfinden eine Zahlen-Variable a
    b : double;  // wir erfinden eine Zahlen-Variable b
    c : double;  // wir erfinden eine Zahlen-Variable c
 
begin
a:=StrToFloat(Edit1.Text);  // belege die Variablen
b:=StrToFloat(Edit2.Text);  // mit den Inhalten der Edit-Felder


c:=a+b; // Addiere a und b und weise den Wert der Variable c zu


Edit3.Text:=format('%5.2f',[c]);
==Aufgaben==
#Ändere das einfache Zählprogramm mit for-Schleife so ab, dass man in einem Edit-Feld angeben kann, bis zu welcher Zahl der Computer zählen soll.
#Karin bekommt 100 Euro geschenkt. Sie legt sie auf der Bank an mit einem Zinssatz von <nowiki>2.3%</nowiki> (Jahreszins). Ein Programm soll ihr sagen, nach wievielen Jahren sich die Summe verdoppelt hat (oder mehr).
#Bei radioaktiven Stoffen spricht man von der Halbwertszeit, das ist die Zeit, nach der ein Stoff nur noch halb soviel strahlt. Schreibe ein Programm, das die Halbwertszeit (in Jahren) vom Benutzer erfragt und dann ausrechnet, nach wievielen Jahren die Strahlung auf ein Hundertstel zurückgegangen ist.
#In grauer Vorzeit (bis zur Erfindung des Taschenrechners) hatte man sogenannte Logarithmentafeln, in denen die Werte der Logarithmusfunktion tabelliert waren, also eine Tabelle mit x und ln x als Spalten. Schreibe ein Programm, das eine solche Tafel ausdruckt (für x-Werte 0.01, 0.02 . . . 1.00).
#Der Mathematiker Leibnitz fand eine Methode, die Zahl π näherungsweise zu berechnen.<br/> Es gilt: <math>\frac{\pi}{4}=1-\frac{1}{3}+\frac{1}{5}-\frac{1}{7}+\frac{1}{9}+\ldots </math><br/> Schreibe ein Programm, das diesen langen Ausdruck bis zum Summanden <math>\frac{1}{401}</math> ausrechnet. Vergleiche die Zahl mit dem Ergebnis Deines Taschenrechners.
#Die Fakultät einer Zahl n (geschrieben als n!) ist definiert als <math> n!= 1 \cdot 2 \cdot 3 \cdot \ldots \cdot n</math> <br /> Schreibe ein Programm, das nach Eingabe einer Zahl n die Fakultät ausrechnet. Was passiert bei großen Werten für n?
#Zwei Würfel werden geworfen. Schreibe ein Programm, dass alle Möglichkeiten ausgibt, wie die beiden Augenzahlen aussehen können (also etwa: (1,1), (1,2), (1,3), ... (6,6)).


end;</source>
{{Lazarus-Buch}}
}}

Version vom 17. Januar 2013, 18:41 Uhr


Zählschleifen

Mit Hilfe von Alternativen (if-then-else) konnten wir Programme so steuern, dass bestimmte Anweisungen nur unter ganz bestimmten Bedingungen ausgeführt wurden, andernfalls nicht. Allerdings wurde die gleiche Anweisung (bei ein und demselben Knopfdruck) immer nur ein einziges Mal ausgeführt.

Bei vielen Dingen ist es jedoch sinnvoll, wenn Dinge mehrfach ausgeführt werden. Nicht umsonst heißt es: "Ein Computer ist unglaublich dumm, aber sehr sehr fleißig". So könnte eine sehr einfache Aufgabe an den Computer lauten, er solle die Zahlen von 1 bis 10 nacheinander in das Memo-Feld Memo1 schreiben. Natürlich könnten wir den Befehl WriteLnTo(Memo1,1) zehn mal untereinander kopieren und dann die Zahlen zwischen den Klammern verändern. Aber das wäre sehr sehr lästige -- und schlimmer noch -- langweilige Arbeit.

Viel bequemer ist es dagegen, wenn wir dem Computer sagen:

"Es gibt eine Variable zaehler. Setze diese Variable zunächst auf 1 und zähle sie dann schrittweise auf 10 hoch. Nach jedem Zählschritt schreibe den Wert der Variable in das Memo-Feld." Genau dies tut das folgende Programm. (Es ist nur die entscheidende Prozedur vermerkt, den Rest kennst Du mittlerweile).


Vorlage:Kasten blau

Auch hier können bei jedem Zählschritt auch mehrere Anweisungen ausgeführt werden; die muss man hier wieder mit begin und end zu einem Anweisungsblock gruppieren: Vorlage:Kasten blau

Schleifen mit Eingangsbedingung (while-Schleifen)

Nehmen wir an, ein (recht phantasieloser) Lehrer gäbe seinen Schüler die Stillarbeit, so viele aufeinanderfolgende Zahlen zu addieren und die Zwischenergebnisse zu notieren, bis die Summe den Wert 1000 erreicht. Schüler Fritz hat sein Netbook im Ranzen und will das Problem mit Lazarus lösen. Das Problem: Er kann jetzt natürlich auf gut Glück ungefähr raten, bis zu welcher Zahl er die Zahlen addieren muss und dies mit einer for-Schleife tun. Aber es muss doch auch eine andere Möglichkeit geben, nämlich, dass der Computer selbst merkt, wenn das Ergebnis erreicht ist. Tatsächlich gibt es diese Möglichkeit:

Vorlage:Kasten blau

Man erkennt deutliche Unterschiede: Die Schleife, so heißt es in dem Programm, wird so lange wiederholt, solange die Summe noch einen Wert kleiner als 1000 hat. Das Setzen des Zählers auf 0 am Anfang und das Hochzählen in jedem einzelnen Schritt, muss der Programmierer hier selbst übernehmen (Zeilen 35 bzw. 39).

Wichtige Anmerkung: Angenommen, man würde in Zeile 36 den anfänglichen Wert der Variable summe auf 1000 setzen, so würde der Computer sozusagen gar nicht erst mit der Schleife anfangen, sondern alles zwischen while und dem end der Schleife überspringen. Denn die Schleife soll ja nur solange ausgeführt werden, solange die Bedingung summe<1000 erfüllt ist. Und das wäre sie in diesem Fall ja von Anfang an nicht. Deshalb spricht man bei der while-Schleife auch von einer Schleife mit Eingangsbedingung.

Schleifen mit Abbruchbedingung (repeat-until-Schleifen)

Anders ist es bei Schleifen mit Abbruchsbedingung. Bei denen wird das Innere der Schleife mindestens einmal durchlaufen. Eine solche Schleife ist in Pascal die so genannte Repeat-Until-Schleife. Unser Problem mit dem Aufsummieren von Zahlen bis zur Summe 1000 könnte mit einer solchen Schleife so aussehen:

Vorlage:Kasten blau

Das Programm verhält sich haargenau wie das Programm mit der While-Schleife. Solange man nicht die Summe vorher größer oder gleich 1000 wählt. Würde man das tun, würde zumindest ein Summations- und Schreibschritt ausgeführt und erst dann die Schleife abgebrochen.


Aufgaben

  1. Ändere das einfache Zählprogramm mit for-Schleife so ab, dass man in einem Edit-Feld angeben kann, bis zu welcher Zahl der Computer zählen soll.
  2. Karin bekommt 100 Euro geschenkt. Sie legt sie auf der Bank an mit einem Zinssatz von 2.3% (Jahreszins). Ein Programm soll ihr sagen, nach wievielen Jahren sich die Summe verdoppelt hat (oder mehr).
  3. Bei radioaktiven Stoffen spricht man von der Halbwertszeit, das ist die Zeit, nach der ein Stoff nur noch halb soviel strahlt. Schreibe ein Programm, das die Halbwertszeit (in Jahren) vom Benutzer erfragt und dann ausrechnet, nach wievielen Jahren die Strahlung auf ein Hundertstel zurückgegangen ist.
  4. In grauer Vorzeit (bis zur Erfindung des Taschenrechners) hatte man sogenannte Logarithmentafeln, in denen die Werte der Logarithmusfunktion tabelliert waren, also eine Tabelle mit x und ln x als Spalten. Schreibe ein Programm, das eine solche Tafel ausdruckt (für x-Werte 0.01, 0.02 . . . 1.00).
  5. Der Mathematiker Leibnitz fand eine Methode, die Zahl π näherungsweise zu berechnen.
    Es gilt:
    Schreibe ein Programm, das diesen langen Ausdruck bis zum Summanden ausrechnet. Vergleiche die Zahl mit dem Ergebnis Deines Taschenrechners.
  6. Die Fakultät einer Zahl n (geschrieben als n!) ist definiert als
    Schreibe ein Programm, das nach Eingabe einer Zahl n die Fakultät ausrechnet. Was passiert bei großen Werten für n?
  7. Zwei Würfel werden geworfen. Schreibe ein Programm, dass alle Möglichkeiten ausgibt, wie die beiden Augenzahlen aussehen können (also etwa: (1,1), (1,2), (1,3), ... (6,6)).