Gleichungslösungs-Programm Problem

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
gr4v3l
User
Beiträge: 4
Registriert: Montag 9. September 2013, 20:00

Ich hab ein kleines Programm geschriben das einfache Gleichungen lösen können soll. Es sollte im Prinzip funktionieren, nur geht´s eben nicht.
Hier mal das Programm:

Code: Alles auswählen

inp1=input()
inp2=input()
X=0
test=False
z=0

while test==False and X<100:
        z=z+1
        print(z)
        if inp1==inp2:
                print(X)
                test=True
        else:
                X=X+1


print("Fertig...oder Fehler")
print(X)
input()
Erkrlärung:
Man gibt erst den linken Teil der Gleichung ein( z.B. 5+X=6+3
Dann den rechten Teil( 5+X=6+3
Dann testet er alle Zahlen von 0-100 durch (bei der Gleichung müsste 4 rauskommen...)
Wenn dann die beiden Werte übereinstimmen sagt er dir X (die Variable)
nun ist der Fehler, dass er jedesmal keine Nummer findet die stimmt.

Die einzige Lösung die mir noch einfallen würde wäre eine for-schleife(bei der aber wahrscheinlich der gleiche fehler auftauchen würde...)

Ich hoffe mal euch fällt dazu etwas ein, ich bin dankbar für jede Hilfe:)
MfG gr4v3l

P.S.:Bin noch relativ neu bei Python, also bitte nicht aufregen :mrgreen: .
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

So einfach wie du dir das vorstellst geht es nicht. Du hast einen String wie beispielsweise "5+x". Eine Variable x hat nun aber überhaupt nichts mit diesem String zu tun. Da wird nicht plötzlich auf magische Art und Weise irgendwie das x ersetzt. Selbst wenn, dann wäre "5+4" immer noch nicht "6+3".
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Vielleicht brauchts nur ein eval.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

darktrym hat geschrieben:Vielleicht brauchts nur ein eval.
Wenn man die Eingaben wirklich vollständig unter Kontrolle hat, dann tut es auch eval. Wenn nicht, dann hat man sich ein riesiges Loch in die Sicherheit der Anwendung gerissen.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Was /me gesagt hat.

Dazu noch dies: Einen Gleichungslöser in Python zu programmieren ist natürlich möglich. Es wäre nicht übermäßig schwierig, aber auch nicht trivial. Man würde typischerweise nicht versuchen, numerische Werte durch Ausprobieren zu finden, da das viel zu lange dauern würde. Und mit reellen Zahlen würde es manchmal gar nicht funktionieren, da manche Dezimalzahlen gar nicht genau durch floating-point-Zahlen dargestellt werden können:

Code: Alles auswählen

>>> .1 + .2
0.30000000000000004
Man würde es statt dessen symbolisch lösen, ziemlich genau so, wie man es mittels Papier und Bleistift lösen würde:

Code: Alles auswählen

5 + X = 6 + 3  |  - 5
X = 6 + 3 - 5
X = 9 - 5
X = 4
Dazu müsste man in Python erst mal einen Parser für solche Gleichungen schreiben. Als Ergebnis würde man einen sog. Abstract Syntax Tree (AST) erhalten, der so aussähe:

Code: Alles auswählen

      =
     / \
    /   \
   /     \
  +       +
 / \     / \
5   X   6   3
Der Gleichungslöser besteht dann aus zwei Teilen. Erstens muss er Strukturen in diesem Baum erkennen, und zweitens bestehende Strukturen durch neue ersetzen können. Die o.s. Rechnung etwa würde dabei schrittweise so transformiert werden:

Code: Alles auswählen

      =
     / \
    /   \
   /     \
  X       -
         / \
        +   5
       / \
      6   3      

-----------------

      =
     / \
    /   \
   /     \
  X       -
         / \
        9   5

-----------------

      =
     / \
    /   \
   /     \
  X       4
Wie man sieht, wird hierbei das numerische Ausrechnen ebenfalls als Ersetzen von Strukturen verstanden.

In symbolischen Sprachen wie Prolog oder Lisp ist sowas trivial umzusetzen, da dort Bäume direkt als Ausdrücke codiert werden können. In Python könnte man evtl. geschachtelte Listen verwenden, oder man baut sich entsprechende Klassen (für =, +, -, usw.). Manchmal findet man auch eine Parser Library, die einem das heavy lifting abnimmt, wie in diesem Beispiel, das etwas ähnliches tut (Auswertung aussagenlogischer Ausdrücke): http://www.python-forum.de/viewtopic.ph ... 78#p230178. Auch das dort weiter unten stehende Programm von BlackJack zeigt eine Möglichkeit, wie man sowas umsetzen kann.
In specifications, Murphy's Law supersedes Ohm's.
gr4v3l
User
Beiträge: 4
Registriert: Montag 9. September 2013, 20:00

/me hat geschrieben:So einfach wie du dir das vorstellst geht es nicht. Du hast einen String wie beispielsweise "5+x". Eine Variable x hat nun aber überhaupt nichts mit diesem String zu tun. Da wird nicht plötzlich auf magische Art und Weise irgendwie das x ersetzt. Selbst wenn, dann wäre "5+4" immer noch nicht "6+3".
Danke an alle für so schnelle Antworten (^-^)v
Hmm, stimmt ich hab vergessen, dass inputs immer zu strings konvertiert werden (._. )
Könnte es nicht funktionieren, wenn ich die Eingabe in Integer umwandle ( int() ) und irgendeinen Weg finde, wie er die Variable erkennt...
Hat irgendwer ne Idde :mrgreen: ?

@/me:
Wie meinst du "wenn ich die Kontrolle über die Eingaben habe" "sonst hast du eine riesige Sicherheitslücke in die Anwendung gerissen" :) ?
eval an sich heißt ja "ausechnen", aber falls es noch eine "schizophräne böse Seite" haben sollte würd ich mich sehr freuen, wenn mir sie wer erklären könnte^^

MfG gr4v3l
Zuletzt geändert von gr4v3l am Donnerstag 24. Oktober 2013, 19:43, insgesamt 1-mal geändert.
webspider
User
Beiträge: 485
Registriert: Sonntag 19. Juni 2011, 13:41

Ich würde einen Post weiter oben anfangen, pillmuncher hat eine recht gute Anleitung geschrieben wie dieser Weg aussieht.
BlackJack

@gr4v3l: `eval()` heisst „werte den Ausdruck in der Zeichenkette aus”. Und so ein Ausdruck muss ja keine harmlose Rechnung sein, sondern der Benutzer kann damit fast beliebigen Code ausführen. Zum Beispiel auch so etwas wie ``__import__('os').system('rm -rf ~')`` was unter Linux/MacOS alle Dateien des Benutzers löscht. Darum ist `eval()` ziemlich *evil* solange man nicht garantieren kann, das der Wert für das Argument niemals von jemandem mit bösen Absichten direkt oder indirekt vorgegeben werden kann.

Eingaben werden auch nicht zu Zeichenketten konvertiert, sondern es *sind* Zeichenketten. Der Benutzer gibt über die Tastatur eine Folge von Zeichen ein → Zeichenkette.

pillmuncher hat einen Weg beschrieben. Allerdings ist der für Dich als Anfänger nicht wirklich leicht umsetzbar. Da würde Dir eine Menge Arbeit bevorstehen. Das ist keine einfache Aufgabe. Es sei denn man nimmt eine fertige Bibliothek um das umzusetzen. Beispielsweise `sympy`.
gr4v3l
User
Beiträge: 4
Registriert: Montag 9. September 2013, 20:00

@BlackJack
Danke für die Einführung auf die dunkle Seite, ich hab zum Glück (oder auch nicht...) keine Freunde die sich so gut in Python auskennen um mir meine Daten zu löschen :mrgreen:
Das Programmchen läuft jetzt auch mit eval() so gut wie ich´s mir nur wünschen kann^^

Code: Alles auswählen

inp1=input()
inp2=input()
X=0
test=False
z=0

while test==False and X<100:
        z=z+1
        print(z)
        eins=eval(inp1)
        zwei=eval(inp2)
        if eins==zwei:
                print("""Ergebnis: X=""",X)
                test=True
        else:
                X=X+1



input()
(Falls es wer haben will kann er das "Programm" gern benutzen solang er´s nicht vermarktet, Ich nenns mal Open-Source^^)

Nun isses nur so, dass er nur ganze Zahlen hernimmt.
Da ich´s mal mit Kommazahlen versuchen wollte (was ja eigentlich ähnlich sein müsste) hab ich den Code so umgeformt:

Code: Alles auswählen

inp1=input()
inp2=input()
X=0
test=False
z=0

while test==False and X<100:
        z=z+1
        print(z)
        print(X)
        eins=eval(inp1)
        zwei=eval(inp2)
        if eins==zwei:
                print("""Ergebnis: X=""",X)
                test=True
        else:
                X=X+0.1



input()


(Die Änderungen sind bei
else:
und ein zusätzlicher print() befehl in der while schleife)

Nur scheint es so als verstände Python unter 1.5 nicht das gleiche wie ich...
X sieht in etwa so aus:
0
0.1
0.2 #(alles noch normal)
0.30000000000000004
0.4
0.5
0.6
0.7
0.7999999999999999
0.8999999999999999
0.9999999999999999
1.0999999999999999
1.2
1.3
1.4000000000000001
und so weiter...

also naja...
dann funktionierts eben nicht.
hoffe auf Hilfe :mrgreen:
lG gr4v3l
BlackJack

@gr4v3l: Sorry, aber das funktioniert nicht. Nur wenn X zwischen 0 und 99 liegt, und selbst dann nicht wenn man die Eingabe so wählt das bei einem der Versuche vorher eine Division durch Null vorkommt. Wenn X nicht zwischen 0 und 99 liegt wird nicht einmal eine Ausgabe gemacht die den Benutzer darüber informiert.

Das ist einfach ein völlig ungeeigneter Ansatz um Gleichungen zu lösen.

Bei 1.5 hat der Rechner wohl noch die gleiche Vorstellung wie Du, aber bei 0.1 zum Beispiel nicht. Gleitkommazahlen sind ungenau. Lesestoff dazu: http://floating-point-gui.de/
gr4v3l
User
Beiträge: 4
Registriert: Montag 9. September 2013, 20:00

Ok, Danke an alle , ihr seit ne echt Große Hilfe :D
Ich weiß zwar, dass das "Programm" noch ziemlich in den Kinderschuhen steckt udn für den , naja "industriellen", Gebrauch eher unbrauchbar weil langsam und eingeschränkt ist, es funktioniert jetzt aber für einfache Sachen einwandfrei.
Ich bin echt froh über so gute Erklärungen, das findet man nicht so oft :mrgreen:
Hier noch mal für alle die´s interessiert oder es weiterführen wollen hier der Code:

Code: Alles auswählen

inp1=input()
print("=")
inp2=input()
X=0
test=False
z=0

while test==False and X<100:
        print(X)
        z=z+1
        eins=eval(inp1)
        zwei=eval(inp2)
        if eins==zwei:
                print("""Ergebnis: X=""",X)
                test=True
        else:
                X=X+0.1
                X=round(X, 3)



input()
lG gr4v3l
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

Hallo gr4v3l,

das Runden funktioniert nur solange Deine eingegebene Gleichung nicht ähnliche Rundungsprobleme hat.
Du mußt statt auf Gleichheit auf Fastgleichheit prüfen. Den »test« könntest Du eleganter durch »break« lösen.
Was ist der Sinn von »z« und dem »input« zum Schluß?
Antworten