Übungsprojekt: ein geprüfter Taschenrechner
Der Rechner akzeptiert eine Zeile wie 7 / 2. q beendet den Dialog. Er erlaubt die vier Grundrechenarten und begrenzt beide Operanden auf endliche Werte von -1.000.000 bis 1.000.000. Diese Fachgrenze verhindert in diesem kleinen Beispiel extreme Rechenergebnisse; eine universelle numerische Bibliothek ist es nicht.
Übungsprojekt: ein geprüfter Taschenrechner#
Übungsprojekte · Lektion 55 von 60
Voraussetzungen: Funktionen, getline, Optional. Lernziel: Du verbindest vollständige Eingabeprüfung mit einer getrennten Berechnung.
Der Rechner akzeptiert eine Zeile wie 7 / 2. q beendet den Dialog. Er erlaubt die vier Grundrechenarten und begrenzt beide Operanden auf endliche Werte von -1.000.000 bis 1.000.000. Diese Fachgrenze verhindert in diesem kleinen Beispiel extreme Rechenergebnisse; eine universelle numerische Bibliothek ist es nicht.
Vollständiges Programm#
1#include <cmath>2#include <iostream>3#include <optional>4#include <sstream>5#include <string>6 7std::optional<double> berechnen(double links, char operation, double rechts) {8 switch (operation) {9 case '+': return links + rechts;10 case '-': return links - rechts;11 case '*': return links * rechts;12 case '/':13 if (rechts != 0.0) {14 return links / rechts;15 }16 return std::nullopt;17 default: return std::nullopt;18 }19}20 21int main() {22 std::string zeile;23 std::cout << "Rechnung wie 7 / 2 eingeben; q beendet.\n";24 while (std::getline(std::cin, zeile)) {25 if (zeile == "q") {26 return 0;27 }28 std::istringstream eingabe{zeile};29 double links{}, rechts{};30 char operation{}, rest{};31 if (!(eingabe >> links >> operation >> rechts) || (eingabe >> rest)) {32 std::cerr << "Format: Zahl Operator Zahl\n";33 continue;34 }35 if (!std::isfinite(links) || !std::isfinite(rechts)36 || std::abs(links) > 1'000'000.0 || std::abs(rechts) > 1'000'000.0) {37 std::cerr << "Operanden muessen endlich und im erlaubten Bereich sein.\n";38 continue;39 }40 const auto ergebnis = berechnen(links, operation, rechts);41 if (!ergebnis || !std::isfinite(*ergebnis)) {42 std::cerr << "Operation ungueltig oder Ergebnis nicht endlich.\n";43 continue;44 }45 std::cout << "Ergebnis: " << *ergebnis << '\n';46 }47 return std::cin.eof() ? 0 : 1;48}Warum diese Aufteilung?#
berechnen kennt keine Konsole. Du kannst sie mit festen Argumenten testen. Die Dialogschleife übernimmt Parsing, Bereichsprüfung und Rückmeldung. std::isfinite aus <cmath> prüft, ob ein Gleitkommawert endlich ist; std::abs liefert den Betrag, also den Abstand von null.
Die Apostrophe in 1'000'000.0 sind Zifferntrenner für bessere Lesbarkeit im C++-Quelltext. Sie ändern den Wert nicht und sind nicht automatisch Teil der erlaubten Benutzereingabe.
Auch ein sehr kleiner Nichtnullteiler kann ein nicht endliches Ergebnis erzeugen. Deshalb prüft der Dialog zusätzlich das Ergebnis. Durch die Kurzschlussauswertung von || wird ein leeres Optional dabei nicht dereferenziert.
Testfälle#
Eingabe | Erwartung |
|---|---|
7 / 2 | Ergebnis 3.5 |
0 * 5 | Ergebnis 0 |
2 / 0 | Fehlermeldung, weiterer Dialog möglich |
2 % 3 | Nicht unterstützte Operation |
2 + 3 extra | Formatfehler |
2000000 + 1 | Bereichsfehler |
Eingabeende | Kontrolliertes Ende |
Erweiterungsaufgabe#
Unterscheide „unbekannter Operator“ und „Division durch null“ durch einen eigenen Ergebnistyp.
Lösungsidee
Definiere einen Aufzählungstyp für Fehler und eine Struktur für Ergebnis oder Fehler. Alternativ kann eine passende Variant die beiden Fälle ausdrücken. Die Rechenfunktion liefert die Information; der Dialog übersetzt sie in einen verständlichen Text. Gib in der Rechenfunktion nicht plötzlich selbst eine Fehlermeldung aus.
Weiterlernen#
Zurück: Nebenläufigkeit, Threads und Datenrennen · Kursübersicht · Weiter: Übungsprojekt: Notizen dauerhaft speichern
Kommentare 0
Kommentare sind für diese Seite deaktiviert.