BlitzBasic für Einsteiger
Ein Lösungsvorschlag zur Aufgabe im Abschnitt „Kontrollstrukturen für den Programmfluss“
Wir haben die folgende Aufgabenstellung:
Vorgaben:
- Schreibe ein Programm zur Berechnung der Grundrechenarten, der Potenz zweier Zahlen und lasse es bestimmen, ob die Division zweier Ganzzahlen einen Rest besitzt (Modulo)
- Verwende für die Berechnungen Funktionen und rufe sie über ein Menü auf.
- Verwende für die Benutzereingabe der beiden Zahlen ein Statement.
Tipp: Lokale und globale Variablen, Schlüsselwort SHARED. - Lasse vor Aufruf der Funktion zur Division prüfen, ob der Divisor Null ist. Die Berechnung soll nur ausgeführt werden, wenn der Divisor ungleich Null ist – andernfalls soll eine Fehlermeldung ausgegeben und die Funktion nicht ausgeführt werden.
- Die Modulo-Funktion soll Aussagen darüber treffen, ob eine Division mit oder ohne Rest erfolgt ist und anschließend das Ergebnis der Division zum Vergleich als Fließkommawert ausgeben.
- Sorge dafür, dass das Programm so lange läuft, bis der Benutzer es beendet.
Tipp: Sprungmarke, Goto. - Achte auf passende Datentypen!
Lösung – Listing shellcalc.ab3
; ------------------------------ ; File: shellcalc.ab3 ; Rechenprogramm mit Menue ; Version: 1.0 ; ------------------------------ OPTIMIZE 1 SYNTAX 1 ; Amiga Version String und das Compilerdatum !version {"ShellCalc 1.0 (\\__DATE_GER__)"} ; -- Globale Variablen deklarieren -- DEFTYPE .b mySelection ; Menue DEFTYPE .s myQuit ; Programmende DEFTYPE .l ergebnis ; Berechnung DEFTYPE .f f_zahl1, f_zahl2 ; Float-Berechnung ; -- Functions und Statements -- Statement UserInput{} SHARED zahl1.l, zahl2.l ; mache Variablen global! NPrint "Gib zwei Ganzzahlen ein!" NPrint "(max. 8 Ziffern)":NPrint "" Print "Erste Zahl : " zahl1 = Edit(8) Print "Zweite Zahl: " zahl2 = Edit(8) End Statement Function addiere{zahl1.l, zahl2.l} Function Return (zahl1.l + zahl2.l) End Function Function subtrahiere{zahl1.l, zahl2.l} Function Return (zahl1.l - zahl2.l) End Function Function multipliziere{zahl1.l, zahl2.l} Function Return (zahl1.l * zahl2.l) End Function Function dividiere{zahl1.l, zahl2.l} Function Return (zahl1.l / zahl2.l) End Function Function potenziere{zahl1.l, zahl2.l} Function Return (zahl1.l ^ zahl2.l) End Function Function modulus{zahl1.l, zahl2.l} Function Return (zahl1.l MOD zahl2.l) End Function ; ----- HAUPTPROGRAMM ----- ; -- Titel -- ANFANG: Print Chr$($0c) ; Bildschirm (Shell) loeschen NPrint "**************************" NPrint "* ShellCalc v1.0 *" NPrint "* *" NPrint "* Menueauswahl *" NPrint "* ============ *" NPrint "* Addition - 1 - *" NPrint "* Subtraktion - 2 - *" NPrint "* Multiplikation - 3 - *" NPrint "* Division - 4 - *" NPrint "* Potenzieren - 5 - *" NPrint "* Modulus (Rest) - 6 - *" NPrint "* *" NPrint "* Programm beenden - 0 - *" NPrint "**************************" ; -- Benutzer-Eingabe -- Print "Deine Wahl: " mySelection.b = Edit(1) NPrint "" Select mySelection.b Case 0 Print "Programm beenden? (j/n): " myQuit.s = Edit$(1) Select myQuit.s Case "j" End Case "J" End Default NPrint "" Goto ANFANG End Select Case 1 NPrint "Addition:" UserInput{} ; Zahlen eingeben ergebnis.l = addiere{zahl1.l, zahl2.l} NPrint "Die Summe von " + Str$(zahl1.l) + " + " + Str$(zahl2.l) + " ist " + Str$(ergebnis.l) NPrint"":NPrint "Weiter: Maustaste" MouseWait NPrint "" Goto ANFANG Case 2 NPrint "Subtraktion:" UserInput{} ; Zahlen eingeben ergebnis.l = subtrahiere{zahl1.l, zahl2.l} NPrint "Die Summe von " + Str$(zahl1.l) + " - " + Str$(zahl2.l) + " ist " + Str$(ergebnis.l) NPrint"":NPrint "Weiter: Maustaste" MouseWait Goto ANFANG Case 3 NPrint "Multiplikation:" UserInput{} ; Zahlen eingeben ergebnis.l = multipliziere{zahl1.l, zahl2.l} NPrint "Das Produkt aus " + Str$(zahl1.l) + " * " + Str$(zahl2.l) + " ist " + Str$(ergebnis.l) NPrint"":NPrint "Weiter: Maustaste" MouseWait NPrint "" Goto ANFANG Case 4 NPrint "Division:" UserInput{} ; Zahlen eingeben If zahl2 > 0 ; Division durch Null abfangen ergebnis.l = dividiere{zahl1.l, zahl2.l} NPrint "Das Produkt aus " + Str$(zahl1.l) + " / " + Str$(zahl2.l) + " ist " + Str$(ergebnis.l) Else NPrint "Fehler: Division durch Null" EndIf NPrint "":NPrint "Weiter: Maustaste" MouseWait NPrint "" Goto ANFANG Case 5 NPrint "Potenz:" UserInput{} ; Zahlen eingeben ergebnis.l = potenziere{zahl1.l, zahl2.l} NPrint "Die Potenz von " + Str$(zahl1.l) + " hoch " + Str$(zahl2.l) + " ist " + Str$(ergebnis.l) NPrint "Weiter: Maustaste" MouseWait NPrint "" Goto ANFANG Case 6 NPrint "Modulus:" UserInput{} ; Zahlen eingeben ; Floats initialisieren f_zahl1.f = zahl1.l f_zahl2.f = zahl2.l ergebnis.l = modulus{zahl1.l, zahl2.l} If ergebnis.l = 0 NPrint "Die Division von " + Str$(zahl1.l) + " durch " + Str$(zahl2.l) + " hat keinen Rest:" ; Float Ergebnis ausgeben NPrint (f_zahl1.f / f_zahl2.f) Else NPrint "Die Division von " + Str$(zahl1.l) + " durch " + Str$(zahl2.l) + " hat einen Rest:" ; Float Ergebnis ausgeben NPrint (f_zahl1.f / f_zahl2.f) EndIf NPrint"":NPrint "Weiter: Maustaste" MouseWait NPrint "" Goto ANFANG Default NPrint "Falsche Eingabe!" NPrint "Weiter: Maustaste" MouseWait NPrint "" Goto ANFANG End Select End
Erklärungen:
- die Zeilen 13 bis 16 deklarieren die im Programm verwendeten Variablen.
- Zeilen 13: Die Variable mySelection dient der Auswertung des Menüs. Da wir hier keine großen Zahlen verwenden genügt es, sie als Byte zu deklarieren.
- Zeile 14: Die Variable myQuit soll ein einzelnes Zeichen zur Bestätigung für das Programmende aufnehmen. Wir deklarieren sie als String.
- Zeile 15: Die Variable ergebnis soll den Rückgabewert der Berechnungs-Funktionen aufnehmen. Da hierbei große Zahlen anfallen können, deklarieren wir sie als Long Word.
- Zeile 16: Die beiden Variablen f_zahl1 und f_zahl2 dienen der korrekten Berechnung eines Fließkomma-Ergebnisses und werden deshalb als Float deklariert. Wir werden ihnen später noch die Werte der Variablen zahl1 und zahl2 zuweisen.
- die Zeilen 19 bis 28 sind für unser Statement zur Abfrage der beiden Zahlen für die Rechenoperationen zuständig. Wir haben für diese Aufgabe ein Statement ohne Parameter gewählt, weil für die weitere Bearbeitung durch die Berechnungsfunktionen zwei Zahlenwerte benötigt werden und Functions lediglich einen Wert zurückliefern können. Auch Statements besitzen keinen Rückgabewert – deshalb stellen wir mittels des Schlüsselworts SHARED in Zeile 28 die Variablen zahl1 und zahl2 global zur Verfügung. Beide Variablen sollen große Ganzzahlenwerte aufnehmen können und sind deshalb vom Typ Long Word.
- Zeilen 38 bis 52: Hier definieren wir die Functions für Addition, Subtraktion, Multiplikation, Division, Potenzieren und zur Restwertermittlung. Sie arbeiten alle nach dem gleichen Prinzip: Mit dem Schlüsselwort Function Return wird direkt das Ergebnis der jeweiligen Rechenoperation an die aufrufende Variable ergebnis zurück geliefert.
- Zeilen 56 bis 164: Hier arbeitet unser Hauptprogramm. Es gibt ein Menü aus, verlangt eine Benutzereingabe zur Wahl der Rechenoperation und ruft anschließend das Statement zur Zahleneingabe aus der entsprechenden Function zur Berechnung heraus auf.
- Zeile 56 definiert die Sprungmarke ANFANG, zu der im Programmverlauf per Goto nach einer Operation so lange zurückgesprungen wird, bis der Benutzer die Option zum Beenden des Programms wählt (nicht-konditionale Schleife). Das Programm wird jeweils nach der Sprungmarke fortgesetzt.
- Zeile 74: Hier wird die Wahl der der gewünschten Rechenoperation in der Variablen mySelection abgelegt.
- Zeile 77 fragt in einem Select … Case … Default-Konstrukt den Wert der Variablen mySelection ab und verzweigt dementsprechend.
- Zeilen 78 bis 89: Wenn der Wert 0 zum Verlassen des Programms eingegeben wurde (Case 0), dann erfolgt eine Sicherheitsabfrage durch ein weiteres, eingeschachteltes Select … Case … Default-Konstrukt. Es prüft anhand der Variablen myQuit, ob der Benutzer ein „j“ oder „J“ eingegeben hat. Trifft dies zu, so wird das Programm mittels des Schlüsselworts End verlassen, andernfalls läuft es weiter.
- Die Case-Anweisungen zum Aufruf der Rechenoperationen laufen alle nach dem gleichen Prinzip ab: Zunächst wird das Statement UserInput{} aufgerufen, um die zu berechnenden Zahlenwerte abzufragen. Danach wird die Function zur gewählten Rechenoperation aufgerufen und ihr Ergebnis der Variablen ergebnis zugewiesen. Anschließend wir der berechnete Wert ausgegeben und per MouseWait darauf gewartet, dass der Benutzer die linke Maustaste drückt. Ohne MouseWait würde die Ausgabe des Ergebnisses direkt vom Bildschirm gelöscht, da wir direkt im Anschluss per Goto zur Sprungmarke ANFANG verzweigen, wo als nächster Befehl die Escape-Sequenz zum Löschen des Bildschirms ausgeführt wird.
- Die Zeilen 117 bis 128 verarbeiten die Division und weisen eine Besonderheit auf: Da Division durch Null nicht erlaubt ist und einen Laufzeitfehler verursachen würde, fangen wir den Aufruf der Funktion dividiere{} vorher ab. Wir prüfen zunächst per If … Else-Konstrukt in Zeile 119, ob der Divisor (zahl2) größer als Null ist. Trifft dies zu, dann wird in Zeile 120 die Divisions-Funktion aufgerufen und ihr Ergebnis wird anschließend ausgegeben. Wenn aber die Bedingung nicht erfüllt ist (Else-Zweig in Zeile 122), dann wird eine Fehlermeldung ausgegeben.
- Eine weitere Besonderheit findet sich in den Zeilen 138 bis 153, wo wir den Modulus berechnen lassen: Hier sollen eine Bewertung des Rechenergebnisses und die vergleichende Ausgabe des Ergebnisses der Division ausgegeben werden. Dazu weisen wir für die Fließkommaberechnung zunächst in den Zeilen 142 und 143 die erfassten Berechnungsparameter den Float-Variablen f_zahl1 und f_zahl2 zu. In Zeile 144 übergeben wir den Rückgabewert der Funktion modulus{} an die Variable ergebnis und überprüfen anschließend per If … Else-Konstrukt ab Zeile 145 ihren Wert. Die Ausgabe der Bewertung erfolgt abhängig vom Ergebnis in den Zeilen 146 oder 150, jeweils anschließend wird zum Vergleich per NPrint (f_zahl1.f / f_zahl2.f) das exakte Fließkomma-Ergebnis ausgegeben.Hinweis: Den letzten Schritt könnten wir auch erst nach If … Else ab Zeile 154 ausführen lassen und uns somit Schreibarbeit ersparen!