Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

04.12.2012, 20:40

Python - Taschenrechner programmieren, der Terme löst

Hallo an alle!


Ich habe erst kürzlich hier ins Forum gefunden und fühle mich doch schon wohl hier :).
Aber trotzdem muss ich erstmal nerven, ich fange nämlich gerade erst mit dem Programmieren in Python an und stoße auf viele Schwierigkeiten. :(
Ich versuche eienn Taschenrechner in Python zu programmieren, der einen Input ausliest und den Term dann berechnet.
Also den Term später zu berechnen, da habe ich wohl einige Ideen, aber die einzelnen Elemente auszulesen und diese beispielsweise alle in eine Liste zu speichern, da fällt mir leider nichts dazu ein, außer, den Benutzer aufzufordern, seine Elemente durch Leerzeichen zu trennen.
Könnte mir da jemand bitte eine kleine Hilfestellung geben?
Danke im Voraus!

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

2

04.12.2012, 21:34

Du möchtest also, dass der Term direkt komplett eingegeben wird?
Dein Rechner löst dann Quasi Terme wie:
37+15*6 oder so.
Guck dir mal an was ein Syntaxbaum ist. Das ganze kann man eigentlich recht schön rekursiv lösen. Das einlesen deiner einzelnen Elemente macht man normal mit einem Parser. Diesen kannst du auch recht simpel selbst schreiben. Im Prinzip ist der eingegebene Term ja nur ein String. Du ließt von vorne Zeichen für Zeichen und entscheidest, was dann passiert. Bei dem Beispiel oben würdest du also als erstes Zeichen eine 3 einlesen. Du weißt, dass nach einem Zahlensymbol noch weitere folgen können. Also guckst du dir das nächste Element an. Dieses Element ist eine 7. Da die 7 direkt auf die 3 folgt, weißt du dass die beiden zusammen gehören. Du hast also bis hier hin 37 gelesen. Jetzt guckst du dir das nächste Zeichen an. Dieses ist ein +. Deine Zahl ist also fertig eingelesen. Du weißt ab hier, dass du die Zahl 37 und ein + hast. Nach dem + kann nun wieder nur eine Zahl folgen (es sei denn du möchtest Klammern und weitere Funktionen wie Sinus etc unterstützen). Das sollte für den Anfang erst mal reichen. So gehst du den Term durch, bis du alle Zahlen und Operatoren gefunden hast. Dann würde man daraus normalerweise einen Syntaxbaum erstellen. An sich kann man das aber natürlich auch anders lösen.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

3

04.12.2012, 21:37

oooh dankeschön! :dash:
das hilft mir schonmal sehr weiter! Dann mach ich mich mal ran ^^

4

04.12.2012, 22:22

Zuerst einmal:
http://de.wikipedia.org/wiki/Umgekehrte_Polnische_Notation

Diese Notation ist sehr viel einfacher zu implementieren, aber zunächst etwas gewöhnungsbedürftig zu benutzen.

Dann solltest du dir reguläre Ausdrücke anschauen, die erleichtern das Parsen von Zahlen:
http://de.wikipedia.org/wiki/Regul%C3%A4rer_Ausdruck

Im Allgemeinen ist mathematische Ausdrücke berechnen das selbe Problem wie das Compilieren von Programmen. Es wird schnell komplex und es ist eine Wissenschaft für sich, aber es gibt mächtige Tools dafür:
http://de.wikipedia.org/wiki/Lex_%28Informatik%29
http://de.wikipedia.org/wiki/Yacc
Das ist jetzt wohl eher die C-Ecke, aber es sind möglicherweise gute Stichworte für weitere Recherchen.
Lieber dumm fragen, als dumm bleiben!

Architekt

Community-Fossil

Beiträge: 2 481

Wohnort: Hamburg

Beruf: Student

  • Private Nachricht senden

5

05.12.2012, 00:25

GreenPepper hat dazu mal einen interessanten Blog Artikel verfasst. Geht zwar um D, aber das Prinzip sollte klar werden: http://mydevcenter.blogspot.de/2011/06/e…grammieren.html
Der einfachste Weg eine Kopie zu entfernen ist sie zu löschen.
- Stephan Schmidt -

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

6

05.12.2012, 00:32

Der Tutorialbauer kann also mal eben so einen Regulären Ausdruck für Mailadressen schreiben;) Das bezweifle ich ja;)
Zu meinem oben beschriebenen Vorgehen gibt es in "Der C++ Programmierer" ein ganz gutes Kapitel. Falls du das Buch zur Hand haben solltest oder möglicherweise über die Uni daran kommst. Das Kapitel zum Taschenrechner ist wirklich gut.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

7

05.12.2012, 09:31

Wow danke!
Eines versteh ich noch nicht so ganz,
bei dem Blogeintrag mit dem Taschenrechner in D,

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
string[] lexStr(string term) {
    string[] lxdTerm;

    char[] tmpNr;
    char c;
    int i = 0;
    while (i<term.length) {
        c = term[i];
        if (c != ' ') {

            if (isOperation(c) || c == ',') {
                lxdTerm ~= [c];
            }

            else if (isNumber(c)) {
                int firstNr = i;

                while (i<term.length-1 && isNumber(term[++i])) {
                    // empty
                }

                if (!isNumber(term[i])) {
                    --i; // Set the cursor back
                }

                lxdTerm ~= term[firstNr..i+1];
            }

            else if (isFunction(c)) { // it should be a function
                int sc = i;

                while (i<term.length-1 && isFunction(term[++i])) {
                    // empty
                }

                if (term[i] != '(' || i-1<=0) {
                    throw new Exception("Syntax Error!\n");
                }

                lxdTerm ~= term[sc..i];
                --i;    // We have to go back to '('
            } else {
                throw new Exception("Syntax Error!\n");
            }
        }
        i++;
    }
    return lxdTerm;
}

könntet Ihr mir bitte erklären, was der lexer macht :(? Ich würde das schon gern verstehen.. :huh:
Mein erster Einfall wäre nämlich gewesen, die Elemente des eingegebenen Strings zu parsen und in eine Liste zu packen und diese dann irgendwie abzuarbeiten :S

8

05.12.2012, 10:24

Ok, kurzer Überblick:

http://de.wikipedia.org/wiki/Parser#Beispiel

Die Tabelle zeigt die gefundene Tokes. Um die Aufzubauen benutzt man einen Lexer/Tokenzier. Er bekommt den Term als Eingabe und liefert die Tabelle als Ausgabe.
Als nächstes kommt der Parser, der aus der Tabelle einen Syntaxbaum aufbaut. Den siehst du im Beispiel darunter. Für den Syntaxbaum definierst du vorher eine sog. Grammatik, die angibt, wie gültige Ausdrücke aussehen und wie diese verschachtelt sein müssen (Damit sowas wie Punkt vor Strichrechnung im Syntaxbaum beachtet wird). Der Parser versucht jetzt die Token so zu einem Baum zusammen zu setzen, dass dieser in der angegebenen Grammatik gültig ist.
Grammatiken sind ein Thema für sich, die zu definieren ist noch recht überschaubar, den Parser zu bauen ist dann aber schon echt kniffelig.

Aber wenn du diesen Syntaxbaum hast, ist es offensichtlich relativ einfach, den Ausdruck auszurechnen. Du fängst unten bei den Blättern an, rechnest die Teilausdrücke aus und reduzierst so den Baum immer weiter, bis irgendwann ganz oben nur noch das Ergebnis steht.
Lieber dumm fragen, als dumm bleiben!

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

9

05.12.2012, 11:43

Ist natürlich alles richtig und schön erweiterbar so, einem Programmieranfänger würde ich jedoch weiterhin die rekursive Variante Vorschlagen. Ein Lexer ist nicht unbedingt das, was man als Anfänger entwickeln sollte. Fertigen Code kopieren, auch wenn man dabei versucht ihn nachzuvollziehen, bringt meiner Meinung nach wenig bei.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

10

05.12.2012, 12:05

Ja, als Anfänger ist sowas kaum zu bewältigen.
Am einfachsten und durchaus machbar wäre echt ein Stack-Taschenrechner:
http://resume.technoplaza.net/java/postfix-calc.php (bzw. der bereits verlinkte Wiki-artikel (http://de.wikipedia.org/wiki/Umgekehrte_Polnische_Notation) mehr tolle Ressourcen find ich dazu gerade nicht.
Lieber dumm fragen, als dumm bleiben!

Werbeanzeige