Die Funktion bei den Wertetafeln wollen wir nun außerhalb der button1click-Prozedur definieren. Das Programm lässt sich dann besser pflegen
Wichtig: Selbstdefinierte Funktionen müssen im Programm vor dem Aufruf stehen.
Hinweis: Viele Funktionen brauchen gar nicht mehr selbst definiert werden, da
sie schon als Standardfunktionen zur Verfügung stehen.
Klassische Mathematische Funktionen: *) Betrag-, Quadrat- und und Wurzelfunktion Abs(x):real (x:real) Beispiel: abs(-5) = 5 Die Funktion Abs(x) gibt den Absolutbetrag |x| zurück. Sqr(x):real (x:real) Beispiel: sqr(-2.5) = 6.25 Die Funktion Sqr gibt das Quadrat eines Wertes zurück. Sqrt(x):real (x:real) Beispiel: sqrt(2.25) = 1.5 Die Funktion Sqrt gibt die Quadratwurzel eines Wertes zurück. *) Exponential- und Lorarithmusfunktione Exp(x) = e^x (e hoch x) mit e=2.171828... Beispiel: exp(1) = 2.171828... Ln(x):real Die Funktion Ln gibt den natürlichen Logarithmus einer Zahl zurück. Hinweis: Der Logarithmus zur Basis B ist dann ln(x)/ln(B) Beispiel: lg(10000) = ln(10000)/ln(10) = 4 Und: Um a^x zu berechnen kann man für a>0 setzen: a^x = exp(ln(a)·x) *) Trigonometrische Funktionen: Sin(x):real (x:real im Bogenmaß) Beispiel: sin(30*Pi/180) = 0.5 Die Funktion Sin berechnet den Sinus eines Winkels. Hinweis: sin(x*Pi/180) ist dann der sinus (x:Gradmaß) Beachte: Pi=3,1415926535897932385 ist eine Konstante Cos(x):real (x:Bogenmaß) Beispiel: cos(60*Pi/180) = 0.5 Die Funktion Cos berechnet den Cosinus eines Winkels. Hinweis: cos(x*Pi/180) ist dann der Cosinus (x:Gradmaß) tan(x):real (x:real im Bogenmaß) Beispiel: tan(45*Pi/180) Die Funktion Tan berechnet den Tangens eines Winkels. Hinweis: 1. tan(x*Pi/180) ist dann der Tangens (x:Gradmaß) 2. In der Standardversion von Delphi ist Tangens nicht verfügbar. Kein Problem: Tan(x) = sin(x)/cos(x) ArcTan(x):real (x:real) Beispiel:ArcTan(1) = Pi/4 (Hauptwert) Die Funktion ArcTan berechnet den Arcustangens einer bestimmten Zahl. ArcSin und ArcCos muss man sich selbst schreiben (Ist auch Sinnvoll, da nicht eindeutig!) Delphifunktionen vom Typ Integer: Round(x):integer (x:real) Round(4.5351) = 5 Round(4.45351) = 4 Die Funktion Round rundet den Wert von x auf den nächsten Integer-Wert. Trunc(x):Integer Beispiel: Trunc(4.983) = 4 Die Funktion Trunc konvertiert eine Gleitkommazahl in einen Integer-Wert. Delphifunktionen vom Typ Real: Frac(x): real (x:real) Beispiel: Frac(2.4578) = 0.458 Die Funktion Frac gibt den Nachkommaanteil einer Zahl zurück. Int(x):real (x:real). Fast dasselbe trunc(x):integer Die Funktion Int gibt den ganzzahligen Anteil einer Zahl zurück. Beispiel: Int(4.899) = 4 Funktionen vom Typ String: Copy(s,a,b);string (s:string a,b:integer) Beispiel: copy('abcde',2,3) = 'bcd' Die Funktion Copy gibt einen Teilstring eines Strings zurück. Length(s):integer (s:string) Beispiel: length('abcde') = 5 Die Funktion Length gibt die Anzahl der Zeichen eines String zurück. Pos (a,b):integer (a,b:string) Beispiel: pos('ef','aebcdef') = 6 Die Funktion Pos gibt den Indexwert des ersten Zeichens von a innerhalb zurück, der in dem String b vorkommt (sonst =0) Chr(n):char (n:integer 0<=n<=255). Umkehrfunktion ist ord(n). Die Funktion Chr gibt das Zeichen mit einem bestimmten ASCII-Wert zurück. Beispiel: chr('a') = 97 chr('A') = 65 Ord(c):integer (c:char) Beispiel: ord(97) = 'a' ord(65) ='A' Die Umkehrfunktion von chr(n) Konvertierungsfunktionen: StrToInt(s):integer (s: String) StrToInt konvertiert einen String, der eine Integer repräsentiert, in eine Zahl. StrToFloat(s): real (s: String) StrToFloat konvertiert einen bestimmten String in einen Gleitkommawert. IntToStr(n): String (n:integer) IntToStr konvertiert den Integer-Wert n in einen String. FloatToStr(x): String (x:real) FloatToStr konvertiert die Gleitkommazahl x in die entsprechende String-Darstellung. Weitere Funktionen: Random(n):integer (n:integer) Beispiel: Wuerfelaugenzahl :=Random(6) + 1 Die Funktion Random erzeugt die Zufallszahl 0 oder höchstens n-1 Randomize sollte einmal im Programm aufgerufen werden, das Random(n) verwendet. Randomize initialisiert den Zufallszahlengenerator mit einem zufälligen Wert. formatfloat('Aufgabe 6.1 Betrachte folgende Funktion:
0.
',x) :string (x: real) formatfloat konvertiert die Gleitkommazahl x in die entsprechende String-Darstellung. Die Stringdarstellung ist - hier als Beispiel - mit einer Null vor dem Komma und mit passenden Leerzeichen formatiert.
function f(x: real):real; begin result := round(abs(1000*x))/1000; if x < 0 then result := -result; end;Was ist a) f(25.45778) b) f(-35,4445) c) f(0.00005) ? c) allgemein f(x) ?
Nun wird am Beispiel gezeigt, wie mit einer selbst definierten Funktion x ——> f(x) gerechnet wird.
Beispiel 6.1 a) Berechnung von f(3) und f(2.1345) für f(x)= 1/3x^3 - 3x function f(x:real):real; //Die eigenständig definierte Funktion var y:real; begin y := 1/3*x*x*x - 3*x; //result ist der Rückgabewert result := y; //Version ohne "y" siehe unten end; procedure TForm1.Button1Click(Sender: TObject); var a,b: real; begin a := f(3); b := f(- 2.1345); showmessage('Der Wert der Funktion für x = 3 ist y= ' + FloatToStr(a)); showmessage('Der Wert der Funktion für x = -2,1345 ist = ' + FloatToStr(b)); end; Beispiel 6.1 b) Wertetafel für f(x) = 1/3x^3 - 3x function f(x:real):real; begin result := 1/3*x*x*x - 3*x; end; procedure TForm1.Button1Click(Sender: TObject); var x, x1, x2, s, y:real; begin x1 := -5; //Alternative: Einlesen von editx1 x2 := 5; //Alternative: Einlesen von editx2 s := 1/2; //Alternative: Einlesen von editx2 x := x1; //Anfangswert memo1.Lines.clear; while x <= x2 do Begin y := f(x); memo1.lines.Add(FloatToStr(x) + ' ' + FloatToStr(y)); x := x + s; End; end;
Aufgabe 6.2: Schreibe mit Hilfe einer Funktion eine Wertetafel für f(α)=2*sin(α)+sin(2*α) für α = -720°, ..., 0°, 30°, 60°, .. 720°Lösung
Beispiel 6.2 a) Die Fakultät n! = 1*2*...*n wird als Funktion definiert, auf "Buttonklick" dann 10! ausgegeben. function fakultaet(n:integer):real; //n: Eingangsparameter var k: integer; p: integer; //k und p: lokale Variable begin p := 1; //Version ohne "p" siehe unten for k := 1 to n do p := p*k; //siehe Produkt result := p; //result ist der Rückgabewert end; procedure TForm1.Button1Click(Sender: TObject); begin showmessage(FloatToStr(fakultaet(10))); //Zeigt: 10! = 3 628 800 end; {Bemerkung: Da Fakultaet(17) schon zu groß für den Typ Integer wird, ist hier der Rückgabewert von Fakultaet vom Typ real} Beispiel 6.2 b) (rekursiv siehe Beispiel 10.1)Funktionen mit zwei oder mehr Eingangsparametern sind möglich. Zum Beispiel die bei der Binominialverteilung wichtige Funktion:
Die Fakultät n! = 1*2*...*n wird als Funktion definiert. Auf "Buttonklick" dann eine Wertetafel ausgedruckt. Bemerkung: Der Rückgabewert result darf wie eine lokale Variable verwendet werden. function fakultaet(n:integer):real; //Ohne lokale Variable p var k: integer; //k: lokale Variable begin result := 1; for k := 1 to n do result :=result*k; end; procedure TForm1.Button1Click(Sender: TObject); var i:integer; begin memo1.text := 'n fakultaet(n)'; for i := 1 to 100 do memo1.lines.add(IntToStr(i)+' '+ formatfloat('
',fakultaet(i))); end;
Aufgabe 6.3 a) Programmiere nuebk(n,k) ohne Fakultäte nach folgender Formel:n n! 49 "n über k". ( ) = ————————— . Zum Beispiel ( ) = 13 983 816 k k!·(n-k)! 6 Die Funktion in Delphi programmiert: function nuebk(n,k:integer):real; begin result := fakultaet(n)/(fakultaet(k)*fakultaet(n-k)) end;
Weitere Aufgaben zu Funktionen (mit Lösungen)n n·(n-1)·(n-2)·..·(n-k+1) ( ) = ———————————————————————— k 1 · 2 · 3 ... · k Hinweis: Hier kann der Ergebnistyp als integer deklariert werden. Die Division muss dann allerdings mit "div" (ganzzahlige Division) statt mit "/" durchgeführt werden. b) Drucke in ein Memofeld das Pascalsche Dreieck 1 Zeile 0: nuebk(0,0) 1 1 Zeile 1: nuebk(1,0) nuebk(1,1) 1 2 1 ... 1 3 3 1 1 4 6 4 1 Zeile 4: nuebk(4,0) nuebk(4,1)...nuebk(4,4) ... Lösung
Aufgabe 6.4: Schreibe eine Funktion hoch(x,n), die für natürliche Zahlen n den Wert y := yn ausgibt. Teste 210; 1,52 und 50! Lösung
procedure TForm1.Button1Click(Sender: TObject); var p,i:integer; begin p := 17017; memo1.text := 'Teiler von ' + intToStr(p) + ':'; for i := 1 to round(sqrt(p)) do if p mod i = 0 then memo1.Lines.add(intToStr(i)+' '+intToStr(p div i)); end; Beispiel für die hier verwendeten Operatoren div und mod: 17 : 5 = 3 Rest 2 Ganzahlig kann 17 nicht durch 5 dividiert werden, deshalb ist 17/5 als Gleitkommadivision bei Integer-Zahlen nicht erlaubt. q := 17 div 5 ergibt q = 3 (div: Die ganzzahlige Division) r := 17 mod 5 ergibt r = 2 (mod: Der Rest) Somit: 17 = q*5 + r mit 0 <= r < 5 Allgemein: q := p div i ergibt den ganzzahligen Quotienten r := p mod i ergibt den Rest Somit: p = q*i + r mit 0 <= r < i, (p,q,r : Integer) Und: Ist i ein Teiler von p, dann ist der Rest r = p mod i = 0
Wir verwenden hier einen Trick, um die Schleife
for i := 1 to pdrastisch verringern zu können. Wir geben gleichzeitig zum Teiler i den korrespondierenden Teiler j = p/i aus. So braucht die Schleife nur bis höchstens zur Quadratwurzel sqrt(q) von q laufen.
Im folgendem Programm werden die 2-er Potenzen ausgegeben. Dazu wird
die Funktion hoch(x,n) = xn verwendet.
Beispiel 7.6: Wertetafel für
2-20, 2-19, ... 219, 220
Die Funktion hoch(x,n) wird jetzt auf negative Hochzahlen n erweitert. function hoch(x:real; n:integer):real; //x^n (x:real; n ganze Zahl) var p:real; i,nabs:integer; begin nabs := abs(n); p :=1; for i := 1 to nabs do p := p*x; if n < 0 then result := 1/p else result := p; //Beachte: x^(-n) = 1/x^n für n < 0 end; procedure TForm1.Button1Click(Sender: TObject); var n: integer; y: real; begin memo1.lines.clear; for n := -20 to 20 do Begin y :=hoch(2,n); memo1.Lines.Add(IntToStr(n)+ ' ' + formatfloat('
0.
',y)); End; end;
formatfloat('
0.
',y) gibt den Wert von
y formatiert aus: Eine Null vor dem Komma und mit passenden Leerzeichen.
Wahrheitstabelle nach Wittgenstein | |||||
---|---|---|---|---|---|
a | not a | b | a and b | a or b | a xor b |
true | false | true | true | true | false |
true | false | false | false | true | true |
false | true | true | false | true | true |
false | true | false | false | false | false |
function f(a: boolean): string; // f=BooleanToString begin if a then result := ' true ' else result := ' false '; end; procedure TForm1.Button1Click(Sender: TObject); var a, b :boolean; begin memo1.Font.Name := 'Courier New'; //gleicher Abstand memo1.text := ' a b a and b a or b a xor b'; a := true; b := true; memo1.lines.add(f(a) + f(b) + f(a and b) + f(a or b) + f(a xor b)); a := true; b := false; memo1.lines.add(f(a) + f(b) + f(a and b) + f(a or b) + f(a xor b)); a := false; b := true; memo1.lines.add(f(a) + f(b) + f(a and b) + f(a or b) + f(a xor b)); a := false; b := false; memo1.lines.add(f(a) + f(b) + f(a and b) + f(a or b) + f(a xor b)); end;Das folgende, elegantere Programm macht dasselbe. Dabei ändert b seinen Wahrheitswert ständig, a nur jedes zweite Mal. Dann würde es von vorne beginnen, wenn nicht nach fünf Zeilen Schluss wäre. (Für dich eine gute Übung, das ausführlich nachzuvollziehen. Vielleicht wird es für ich einfacher, wenn du "b" durch das äquivalente "b = true" ersetzt. Denn ist "b" true, dann ist "b = true" natürlich auch true und auch "(b = true) = true" u.s.w. Die Beteuerung "Ich sag die Wahrheit" ist, logisch gesehen, überflüssig.)
function f(a: boolean): string; // f=BooleanToString begin if a then result := ' true ' else result := ' false '; end; procedure TForm1.Button1Click(Sender: TObject); var a, b :boolean; begin memo1.Font.Name := 'Courier New'; //gleicher Abstand memo1.wordwrap := false; //siehe Bemerkung unten memo1.text := ' a b a and b a or b a xor b'; a := true; b := true; repeat memo1.lines.add(f(a) + f(b) + f(a and b) + f(a or b) + f(a xor b)); b := not b; if b then a := not a; until memo1.lines.count >= 5; end;Bei diesem Programm zeigte sich wieder einmal die Tücke der Programmierung: Beim ersten Test meines Programms fehlte die Zeile "memo1.wordwrap := false". (Das bedeutet: Kein Zeilenumbruch, falls Zeile zu lang.) Und: Der Abbruch der Repeat-Schleife war "until memo1.lines.count = 5". Promt landete ich in einer Endlosschleife, weil mein Memo1 nicht breit genug war und auf einmal eine Zeile durch zwei Zeilen ersetzt wurde. Nach Zeilenlänge "4" kam nicht "5" sondern "6". Fatal!
function f(a: boolean): string; // f=BooleanToString begin if a then result := ' true ' else result := ' false '; end; procedure TForm1.Button1Click(Sender: TObject); var a, b :boolean; k: integer; begin memo1.lines.clear: memo1.lines.add := ' a b a and b a or b a xor b'; a := true; b := true; k := 0; repeat memo1.lines.add(f(a) + f(b) + f(a and b) + f(a or b) + f(a xor b)); inc(k); //Dasselbe wie k := k + 1; b := not b; if b then a := not a; until k = 5; end;Beispiel 7.7: In einer Schachtel befinden sich 15 blaue, grüne, rote und gelbe Buntstifte, von jeder Farbe mindestens einer. Blaue Stifte sind am meisten und grüne am wenigsten vorhanden. Außerdem hat es gleichviele rote wie gelbe Stifte.
procedure TForm1.Button1Click(Sender: TObject); var blau, gruen, rot, gelb: integer; begin memo1.Text := 'blau grün rot gelb'; for blau := 1 to 15 do for gruen := 1 to 15 do for rot := 1 to 15 do for gelb := 1 to 15 do if (blau > gruen) and (blau > rot) and (blau > gelb) and (gruen < blau) {entbehrlich} and (gruen < rot) and (gruen < gelb) and (rot = gelb) and (blau + gruen + rot + gelb= 15) then memo1.lines.add(IntToStr(blau)+ ' ' + IntToStr(gruen) + ' ' + IntToStr(rot) + ' ' + IntToStr(gelb)); end;Die Klammern in diesem Beispiel sind unbedingt notwendig, da z.B. X and Y für Integerzahlen X und Y (siehe Bitweise Operatoren) Vorrang vor true and false hat.
Beispiel 7.8: Drei Lottozahlen werden erzeugt (erweiterbar auf 6 Lottozahlen plus Zufallszahl) procedure TForm1.Button1Click(Sender: TObject); var x1,x2,x3: integer; begin randomize; x1 := random(49) + 1; edit1.text := IntToStr(x1); application.ProcessMessages; //Windows ändert sofort edit1 sleep(2000); // 2 Sekunden Geduld x2 := x1; while x2 = x1 do x2 := random(49) + 1; edit1.text := edit1.text+' '+IntToStr(x2); application.ProcessMessages; sleep(2000); x3 := x2; while (x3 = x1) or (x3 = x2) do x3 := random(49) + 1; edit1.text := edit1.text+' '+IntToStr(x3); application.ProcessMessages; sleep(2000); end;Beispiel 7.9: Umwandlung Dezimalzahl in roemische Zahl
Der Algorithmus ist folgender: Beispiel 1964 1. Tausender verarbeiten 1000 = M 1964=M+964 (M+Rest) Rest >=900? 900 = CM 1964=M+CM+64 (MCM+Rest) Rest >=500? 500 = D Rest >= 400? 400 = CD 2. Hunderter verarbeiten 100 = C Rest >= 90? 90 = XC Rest >= 50? 50 = L 1964=MCM+L+14 Rest >= 40? 40 = XL 3. Zehner verarbeiten 10 = X 1964=MCM+L+X+4 Rest >= 9? 9 = IX Rest >=5? 5 = V Rest >= 4? 4 = IV 1964=MCM+L+X+IV 4. Einer verarbeiten 1 = IIn Delphi "übersetzt" wird es etwas lang. Wenn du aber die "Tausender" verstanden hast, ist der Rest wegen der Ähnlichkeit leicht.
Function roemisch(n: integer):string; begin result := ''; {——————— Tausender —————————} while n >= 1000 do Begin //kann mehrmals vorkommen result := result +'M'; n := n-1000; End; if n >= 900 then Begin //kann nur einmal vorkommen result := result +'CM'; n := n-900; End; if n >= 500 then Begin result := result +'D'; n := n-500; End; if n >= 400 then Begin result := result +'CD'; n := n-400; End; {————————— Hunderter ——————————— } while n >= 100 do Begin //kann mehrmals vorkommen result := result +'C'; n := n-100; End; if n >= 90 then Begin result := result +'XC'; n := n-90; End; if n >= 50 then Begin result := result +'L'; n := n-50; End; if n >= 40 then Begin result := result +'XL'; n := n-40; End; {——————— Zehner ———————————} while n >= 10 do Begin result := result +'X'; n := n-10; End; if n >= 9 then Begin result := result +'IX'; n := n-9; End; if n >= 5 then Begin result := result +'V'; n := n-5; End; if n >= 4 then Begin result := result +'IV'; n := n-4; End; { ——————————— Einer ——————————— } while n >= 1 do Begin //kann mehrmals vorkommen result := result +'I'; n := n-1; End; end;Dieses Programm kürzer geschrieben findest du im Downloadverzeichnis unter Umwandlung Dezimalzahl in römische Zahl
Aufgabe 7.5: Ineinandergeschachtelte if ... then-Anweisungen. Was wird im folgendem Programm berechnet? procedure TForm1.Button1Click(Sender: TObject); var a,b,c :integer; begin for a := 0 to 1 do for b := 0 to 1 do Begin if a = 0 then BEgin if b = 0 then c := 2 else c := 3; ENd else BEgin if b = 0 then c := 5 else c := 7; ENd; memo1.lines.add('a='+IntToStr(a)+' b='+IntToStr(b)+ ' c='+IntToStr(c)); End; end;Hinweis: Bei verschachtelten if ... then-Konstrukten ist Pascal zweideutig.
if b0 then if b1 then s0 else s1sondern entweder
if b0 then Begin if b1 then s0 else s1 Endoder
if b0 then Begin if b1 then s0 End else s1wobei b0,b1 Bedingungen und s0,s1 Anweisungen bedeuten sollen.
procedure TForm1.erKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); begin if sender <> er then er.text := ''; if sender <> ed then ed.text := ''; if sender <> eu then eu.text := ''; if sender <> ea then ea.text := ''; end;Weise nun auch den Feldern ed, eu, eA im Objektinspektor unter "Ereignisse" dieselbe Ereignisprozedur OnKeyUp zu.
Wiederhole... |
Falls n durch i (i=2,3,5,7,...) dividiert werden kann, notiere i und ersetze n durch n/i. |
... bis n=1. |
Die notierten i's sind die Faktoren der PFZ |
Bsp.: n=4004 i=2 n=2002 i=2 n=1001 i=7 n=143 i=11 n=13 i=13 n=1 Also: 4004=2*2*7*11*13Eine Beschleunigung erreicht man durch folgende Überlegung: Ist n=a·b so muss ein Faktor a oder b kleiner/gleich sqrt(n) sein. (Widerspuchsbeweis: a > sqrt(n) und b > sqrt(n) = > a·b > n ) Man braucht also nur mögliche Faktoren i <= sqrt(n) betrachten.
function PFZ(n:integer):string; var i:integer; begin result:=''; i:=2; repeat while n mod i =0 do BEgin n:=n div i; if result <> '' then result:=result+'*'; //Das 1. Mal kein '*' result:=result+floatToStr(i); ENd; if i=2 then i:=i+1 else i:=i+2; //ungerade (eigentlich genügen Primzahlen) if i > trunc(sqrt(n)) then i:=n; //ohne diese Zeile:Kaffeepause! until n=1; if pos('*',result)=0 then result:='Primzahl'; end;
Viele ineinandergeschachtelte if .. then kann man ersetzten durch Case .. of .. else .. End.
Zum Beispiel kann man statt if i = 1 then s := 'eins' else if i = 2 then s := 'zwei' else if i =3 then s := 'drei' else s := 'viel' schreiben Case i of 1: s := 'eins'; 2: s := 'zwei'; 3: s := 'drei'; else s := 'viel'; End; Beispiel 8.1: Hier wird dies demonstriert: procedure TForm1.Button1Click(Sender: TObject); var i : integer; s : string; begin for i := 1 to 10 do Begin CAse i of 1: s := 'eins'; 2: s := 'zwei'; 3: s := 'drei'; else s := 'viel'; ENd; showmessage(intToStr(i) + ' = ' + s); End; end; Dasselbe ohne else: procedure TForm1.Button1Click(Sender: TObject); var i : integer; s : string; begin for i := 1 to 10 do Begin s := 'viel'; CAse i of 1: s := 'eins'; 2: s := 'zwei'; 3: s := 'drei'; ENd; showmessage(intToStr(i) + ' = ' + s); End; end; Beispiel 8.2: Du benötigst hier radiogroup1 aus der Standardkomponentenleiste. Bei einer Radiogroup kann der Benutzer aus einer Gruppe von Feldern genau eines auswählen. Aktiviere radiogroup1 und doppelklicke im Objektinspektor bei items auf "..." und schreibe in den sich nun öffnenden String-Listen-Editor rot blau grün gelb schwarz weiß Wird jetzt auf der Radiogrup eine Farbe gewählt, soll das Fenster die entsprechnede Farbe enthalten: procedure TForm1.RadioGroup1Click(Sender: TObject); begin Case radiogroup1.ItemIndex of 0 : color := clred; 1 : color := clblue; 2 : color := clgreen; 3 : color := clyellow; 4 : color := clblack; 5 : color := clwhite; End; //Nur zur Demonstration for i :=0 to radiogroup1.Items.Count -1 do showmessage(IntToStr(i) + '=' +radiogroup1.items[i]); end; Beachte: Die Feldelemente heißen items. Die Anzahl der Elemente ist radiogroup1.Items.Count. Die Feldelemente (Items) der Radiogroup werden von 0 an durchnummeriert bis radiogroup1.Items.Count -1. (In der Informatik fängt man häufig bei 0 an zu zählen!) Die Eigenschaft itemindex ist die Nummer des ausgewählten Elements. Für den Fachmann:clred u.s.w. sind vordefinierte Konstanten. Genauer: In der unit graphics wird definiert clRed = TColor($0000FF) clBlue = TColor($FF0000) clLime = TColor($00FF00) (Daraus kann man alle Farben mischen) clBlack = TColor($000000) (Kein Farbpixel wird aktiviert) clWhite = TColor($FFFFFF) (Alle drei Farbpixel) Aufgabe 8.1: Unter folgenden Bedingungen zahlt ein Betrieb an seine Mitarbeiter eine Jahresendprämie: Betriebszugehörigkeit weniger als ein Jahr : keine Prämie Betriebszugehörigkeit ein Jahr aber weniger als 5 Jahre: 200 EUR Betriebszugehörigkeit 5 Jahre aber weniger als 10 Jahre: 400 EUR Betriebszugehörigkeit 10 Jahre und mehr : 800 EUR Schreibe dazu ein passendes Programm und verwende dabei "Case"! Aufgabe 8.2: Der Fahrkartenautomat gibt aus Einzeltageskarten für 1 Zone zu EUR 2,00 Gruppentageskarten für 1 Zone zu EUR 3,00 Einzeltageskarten für 3 Zonen zu EUR 5,00 Gruppentageskarten für 3 Zonen zu EUR 8,00 Einzeltageskarten für 6 Zonen zu EUR 9,00 Gruppentageskarten für 6 Zonen zu EUR 14,00 Simuliere den Automaten! Aufgabe 8.3: Plaztiere ein Spinedit- und ein Editfeld auf Dein Formular. Nach Eingabe der Punktzahl im Spineditfeld soll die Note in Worten im Editfeld erscheinen. Zum Beispiel: Notenpunkte Note 11 gut Schreibe dazu ein Programm. Aufgabe 8.4: Oft werden Prüfsummen folgendermaßen gebildet: Multipliziere die erste Ziffer mit 7, die zweite mit 3, die dritte mit 1, die vierte wieder mit 7, u.s.w. und addiere alle Summandden. Die Prüfziffer ist dann die letzte Ziffer dieser Summe. z.B. Prüfsumme von 861214 = 8·7 + 6·3 + 1·1 + 2·7 + 1·3 + 4·1 = 96 Prüfziffer = 6 Schreibe eine Funktion unter Verwendung von Case, die die Prüfsumme ermittelt.Lösung
a) function flaeche(art: string; r: real): real; begin if art = 'Kreis' then result := Pi*r*r else if art = 'Quadrat' then result := r*r else if art = 'Kugel' then result := 4/3*Pi*r*r*r else Begin showmessage('Unbekanntes Objekt'); result := 0; End; end; procedure TForm1.Button1Click(Sender: TObject); var a, r, y: real; begin r := 5; y := flaeche('Kreis',r); memo1.lines.Add('Kreisfläche (r=5) = ' + FloatToStr(y)); a := 3; y := flaeche('Quadrat',a); memo1.lines.Add('Quadrat (a=3) = ' + FloatToStr(y)); a := 10; y := flaeche('Dreieck',a); memo1.lines.Add('gleichseitiges Dreieck (a=10) = ' + FloatToStr(y)); end; b) function f(x: real): real; var p, q: real; begin p := 0; if x < 0 then p:= 2*x; if x > 0 then q := x/2 else q := 0; result := p + q; end; procedure TForm1.Button1Click(Sender: TObject); var i: integer; begin for i := - 2 to 2 do memo1.lines.add(IntToStr(i)+ ' '+ floatToStr(f(i))); end; c) function g(a,b: real): real; begin if a > 0 then result := 2*a + 3*b else result := 2*a - 3*b; end; procedure TForm1.Button1Click(Sender: TObject); var i:integer; begin i := -4; repeat memo1.lines.add(IntToStr(i)+ ' '+ floatToStr(g(i,2*i))); i := i+2; until i = 4; end; d) function h(x: integer): real; var p, q: real; begin p := 1; q := 1; while q <= x do Begin p := p*q; q := q + 1; End; result := p; end; procedure TForm1.Button1Click(Sender: TObject); var a: integer; begin a := 0; while a <= 5 do Begin memo1.lines.add(IntToStr(a)+ ' '+ floatToStr(h(a))); a := a + 1; End; end;Aufgabe 8.6 Schreibe ein Programm "Procedure ... Button1Click ..", das die Lösungen x1,2 = (-b ± sqrt(d))/(2·a) der quadratischen Gleichung ax2 + bx +c = 0 ausgibt, wobei d = b2 - 4·a·c ist.
edit1 edit2 edit3 a b c edit4 edit5 x1 x2Das zusätzlich Besondere bei Deinem Programm soll sein:
Zwei Lösungen (d > 0): zusätzlich edit5.show Eine Lösung (d = 0): edit5.hide Keine Lösung (d < 0): edit4.text ='keine Lösung' edit5.hideAufgabe 8.7 Im Edit1-Feld soll die Punktzahl eingeben werden, im Edit2-Feld soll dann die zugehörige Note in Buchstaben stehen. Schreibe unter Verwendung von Case das zugehörige Programm!
Zur Erinnerung: 0 -> ung; 1, 2, 3 -> mgh; 4, 5, 6 -> ausr; 7,8,9 -> bfr; 10,11,12 -> gut; 13,14,15 -> sgtAufgabe 8.8 Formuliere die Funktionen f und g in Delphi (n: Integer)
Aufgabe 8.9 Was wird bei folgendem Programm ins Memo geschrieben?1 1 1 a) Die Funktion f(n) soll 1 + - + - + ... + - berechnen. 2 3 n 1 3 5 2n-1 b) Die Funktion g(n) soll -·-·- · ... · ———— 2 4 6 2n berechnen.
procedure TForm1.Button1Click(Sender: TObject); var a, b, q, r, a1:integer; begin a := 416; b := 160; repeat q:= a div b; r:= a mod b; a1 := q*b + r; memo1.Lines.Add(' a = ' + intToStr(a) + ' q = ' + intToStr(q) + ' r = ' + intToStr(r) + ' a1 = ' + intToStr(a1)); a:=b; b:=r; until r = 0; end;Lösungen von Aufgaben 8.5 bis 8.9
Eugen hat eine Aktie A im Wert von 1000 EUR. Josef hat 1000 EUR bar.
Täglich wechselt die Aktie den Besitzer. Der Wert der Aktie kann
täglich um maximal p% nach oben oder unten schwanken (random).
Wie viel besitzt jeder nach einem Tag, nach zwei, drei ... Tagen?
y := 1 (Anfangswert) |
Multipliziere n mal y mit x |
function hoch(x:real; n:integer):real; var k:integer; begin result := 1; for k := 1 to n do result := x*result; end;Wenn man jedoch sehr oft Potenzen oder sehr hohe Potenzen (wie bei Verschlüsselungen) berechnen muss, ist diese Funktion nicht sehr effizient. Potenzen kann man auch mit sehr viel weniger Multiplikationen durchführen.
Beispiel y = 221 Rechne a:=2*2 b:=a*a (=24) c:=b*b (=28) d:=b*b (=216) y:=d*b*2*1 (=216*24*2=221) ("*1" steht hier nur wegen des Anfangswertes beim Algorithmus.)Statt 21 Multiplikationen hat man hier nur 7. Man sagt: Die Effizienz dieser Methode ist besser.
Anfangswert y:=1 |
Wiederhole den folgenden Befehl solange, bis e=0 ist: Wenn e ungerade, dann y:=y·m und e:=e-1 (m ungeändert), sonst m:=2*m und e:=e/2 (y ungeändert) |
function hoch(m:extended; e:integer):extended; begin result := 1; while e > 0 do if odd(e) then Begin //odd(e) = true, wenn e ungerade result := result*m; e := e -1; End else Begin m :=m*m; e := e div 2 End; end;Beispiel 9.2 Der Euklidische Algorithmus zur Berechnung des ggT.
zum Beispiel: ggT(18,12) = 6 ggT(5406,1785) = 51Wenn du das zweite Beispiel nachprüfen willst, musst du dich schon ganz schön anstrengen (Stichwort: Primfaktorenzerlegung). Bei sehr großen Zahlen ist es so aussichtslos. Siehe Zur Primfaktorenzerlegung
Ist nämlich t ein gemeinsamer Teiler von a und b mit a div t = x und b div t = y (x, y ganze Zahlen), dann ist bekanntlich ——————————————————— (a - b) div t = x - y (Vertausche a und b, falls a < b). Zum Beispiel: 143 div 13 = 11 52 div 13 = 4 ——————————————————— 91 div 13 = 7 Also: ggT(a,b) = ggT(b,a - b) Zum Beispiel: ggT(143,52) = ggT(91,52), nämlich 13 Man kann sogar statt a - b auch a - 2b oder a - 3b ... nehmen. Am besten ist natürlich a - k·b für das größte k so, dass noch a -k·b > 0. Es ist a mod b = a - k·b = Rest bei Division von a durch b Also gilt auch hier: ggT(a,b) = ggT(b,a mod b) Zum Beispiel: ggT(143,52) = ggT(52,143 - 2·52) = ggT(52,39) Beachte: 143/52 = 2 Rest 39 weiteres Beispiel: ggT(5406,1785) = ggT(1785, 5406 - 3·1785) = ggT(1785, 51) Beachte: 5406/1785 = 3 Rest 51 Jetzt können wir das Spiel wiederholen, bis der Rest Null ist. ggT(1785,51) = ggT(51, 1785 - 35·51) = ggT(51, 0) Wir sehen: ggT(1785,51) = 51. Also ebenfalls ggT(5406,1785) = 51 Hier noch ein längeres Beispiel: ggT(416,256) = ggT(256,160) = ggT(160,96) = ggT(96,64) = ggT(64,32) = ggT(32,0) = 32 Der Algorithmus lautet:
Wiederhole: |
solange durch b und (a mod b) |
bis a mod b = 0. |
Der ggT ist dann die letzte Zahl <> 0. |
a a div ggT(a,b) - = —————————————— b b div ggT(a,b) Das Formular könnte folgendermaßen aussehen: Bruch(Label1) gekürzter Bruch(Label2) spinedit1 spinedit3 ————————— = ————————— spinedit2 spinedit4Lösung
function RoemischeMultiplikation(a,b: integer):integer; var s: integer; begin form1.memo1.lines.Clear; //Nur zum Testen s := 0; repeat form1.memo1.Lines.Add('a=' + IntToStr(a) + ' b=' + inttostr(b) + ' s=' + inttostr(s));//Test if a mod 2 = 1 then s := s + b; a := a div 2; b := b*2; until a = 0; result:=s; end; procedure TForm1.Button1Click(Sender: TObject); var x, y: integer; begin x:= 45; y := 17; memo1.lines.add('Erg.=' + IntTostr(RoemischeMultiplikation(x,y))); //Bemerkung 45*17=(32 + 8 + 4 + 1)*17 end;Lösung
Setzte Anfangswert a=0 und y = x. 0 2 2 1 Ist y > 2, dann setze y = y - 2 und addiere - zu a, 0 1 0 2 2 andernfalls setze y = y und addiere nichts zu a. 1 0 2 2 1 Ist y > 2, dann setze y = y - 2 und addiere - zu a, 1 2 1 4 2 andernfalls setze y = y und addiere nichst zu a. 2 1 1 1 1 Fahre so fort und addiere gegebenenfalls -, ——, ——, ... 8 16 32Schreib dazu eine passende Delphifunktion.
Bei der Rekursion wird ein großes Problem in Teilprobleme zerlegt, die ähnlich strukturiert sind. Hier betrachten wir nur einen kleinen Ausschnitt von diesem Thema: Funktionen, die sich selbst aufrufen.
Man erhält damit häufig erstaunlich kurze, leicht verständliche und effiziente Algorithmen.
Beispiel 10.1:(iterativ siehe Beispiel 6.2)Das berühmteste Beispiel ist die Fakultät f(n)= n! =1·2·3·...·nBeispiel 10.2: Die Funktion kann auch mehrfach aufgerufen werden.1 falls n = 0 f(n) := { n*f(n-1) falls n > 0
Als Delphifunktion: function f(n: integer): real; begin if n < 1 then result := 1 else result := n*f(n-1) end; Wird zum Beispiel f(5) aufgerufen, muss man den Werten "hinterher rennen": f(5) = 5*f(4) mit f(4) = 4*f(3) mit f(3) = 3*f(2) mit f(2) = 2*f(1) mit f(1) = 1*f(0) mit f(0) = 1 (Anfangswert) Also f(5) = 5*4*3*2*1*1 Wichtig: Bei rekursiven Funktionen muss gewährleistet sein. I Das Problem wird auf einfachere Probleme reduziert. (Bei der Fakultät: Rechnung für ein kleineres n) II Nach endlich vielen Schritten ist das Problem ohne Rekursion lösbar. (Bei der Fakultät: Schließlich kommt man zu n = 0) Aufgabe 10.1: Schreibe ein Programm, das eine Wertetafel für f ausgibt. Aufgabe 10.2: Was wird bei der folgenden Funktion g berechnet? a) g(5) b) g(-5) function g(n: integer): real; begin if n = 0 then result := 1 else result := n*g(n-1) end; Aufgabe 10.3: Was wird bei folgender Funktion h berechnet? Gib nicht den Wert der Rechnung, sondern einen Rechenausdruck an! a) h(1.5,5) b) h(1.5,-5) c) Allgemein function h(x:real; n: integer): real; begin if n < 0 then result := 1/h(x,-n) else if n = 0 then result := 1 else result := x*h(x,n-1) end; Aufgabe 10.4: Was wird bei folgender Funktion berechnet? Gib nicht den Wert der Rechnung, sondern einen Rechenausdruck an! a) f(2) b) f(10) c) Allgemein function f(n: integer): real; begin if n < 0 then result := 0 else result := 1/(2*n+1) + f(n-1) end; Lösung
Leonardo Fibonacci, eigentlich Leonardo von Pisa, 1170 - 1250, gehörte zum Gelehrtenkreis
Kaiser Friedrich II, führte die arabischen Ziffern in Europa ein. Er stellte in seinem Buch "Liber Abaci" folgende Aufgabe: |
Ein Mann hält ein Kaninchenpaar an einem Ort, der gänzlich von einer Mauer umgeben ist. Wir wollen nun wissen, wie viele Paare von ihnen in einem Jahr gezüchtet werden können, wenn die Natur es so eingerichtet hat, dass diese Kaninchen jeden Monat ein weiteres Paar zur Welt bringen und damit im zweiten Monat nach ihrer Geburt beginnen. |
Man kommt dann auf die Zahlenfolge: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ... |
Es gibt viele interessante Eigenschaftren dieser Folge. Zum Beispiel konvergiert die Folge der aufeinander folgenden Zahlen 1/1, 1/2, 2/3, 3/5, 5/8, 8/13 ... gegen die vom goldenen Schnitt her bekannte Zahl (sqrt(5)-1)/2. Mit TTMathe kannst Du Dir den passenden Kettenbruch berechnen lassen. |
Die Fibonacci-Folge lautet rekursiv definiert: 1 für n = 1 und n = 2 f(n) = { f(n-1) + f(n-2) für n > 2Als Delphifunktion:
function fib(n:integer):integer; begin if n < 2 then result := 1 else result := fib(n-1) + fib(n-2) end; |
procedure TForm1.Button1Click(Sender: TObject); const max = 500; var n: integer; nn: array[1..max] of real; function f(n: integer): real; //zuvor muss f(1), f(2), ..., f(n-1) aufgerufen sein begin if n <= 2 then result := 1 else result := nn[n-1] + nn[n-2]; nn[n] := result; end; begin for n := 1 to max do memo1.Lines.Add(inttostr(n) + ' ' +floattostr(f(n))); end; |
function fib(n:integer):integer; var k, x1,x2: integer; begin result := 1; //für n=1 oder n=2 x1 := 1; x2 := 1; for k := 3 to n do Begin result := x1 + x2; x1 := x2; x2 := result; End; end; |
/ 1, falls e=0 | | e | e-1 m = | m·m , falls e ungerade | | e | - | 2 2 \ (m )In Delphi:
function h(m:extended; e:integer):extended; begin if e = 0 then result := 1 else if odd(e) then result := m*h(m,e-1)//da me=m*m(e-1) else result := h(m*m,e div 2) //da me=(m*m)(e/2) end;Beispiel 10.4 Primfaktorenzerlegung (iterativ Beispiel 7.10)
Die Rekursiosformel: / k*PFZ(n div k), falls k Teiler von m (k > 1 minimal} PFZ(n) ={ \ n, sonst (d.h. n Primzahl) wobei die Darstellung als String noch erforderlich ist. In Delphi: function PFZ(const n:integer):string; var k:integer; begin for k:=2 to trunc(sqrt(n)) do if n mod k = 0 then Begin result:=intToStr(k)+'*'+PFZ(n div k); //rekursiv exit; End; result:=intToStr(n); end;Beispiel 10.5 Der Euklidische Algorithmus (rekursiv):
function ggT(a,b:integer):integer; begin if b=0 then result := a else result := ggT(b, a mod b); //Rekursiv end;
Aufgabe 10.8: Was berechnet die Funktion f bei Eingabe von
a) n = 5 b) n = 10 c) n =-2 d) allgemein. Ergebnis bei allen Teilaufgaben als Rechenausdruck, falls möglich! |
function f(n: integer): real; begin if n <=0 then result := 0 else result := 1/n + f(n-1); end; |
Aufgabe10.9: Was berechnet folgende Funktion bei Eingabe von a) n=3 b) n=5 c) n=10 d) n=-2 |
function f(n: integer): real; begin if (n=0) or (n=1) then result := 0 else result := f(n-1) + 2*f(n-2); end; |
n n·(n-1)·(n-2)·...(n-k+1) 49 49·48·47·46·45·44 ( ) = ——————————————————————— zum Beispiel ( ) =—————————————————— k 1 · 2 · 3 · ... ·k 6 1· 2· 3· 4 ·5 ·6
function nuebk(n,k: integer): integer; begin if k <= 0 then result := 1 else result := nuebk(n-1,k-1)*n div k; end;Diese Funktion wird bei der Binomialverteilung " benötigt.
zurück | Lösungen der Aufgaben | Inhalt | Lektion 11 |