Genaue Berechnungen
Also wie krieg ich das hin damit mit Python etwas mit decimalstellen genau berechnet, ich schreib grad ein Prog dass Integrale Berechnen soll und da kommen ganz falsche Ergebnisse raus weil der irgendwie das float falsch rundet.
Hoi,
float soll "falsch runden"? Das glaube ich nicht .
Schau mal hier: http://www.python.org/doc/2.5/tut/node16.html
Außerdem gibt es bereits das scipy-Modul mit diversen Integrationsroutinen.
Magst Du ein wenig Beispielcode posten, damit wir herausfinden können, wo evtl. der Fehler liegt?
Gruß,
Christian
float soll "falsch runden"? Das glaube ich nicht .
Schau mal hier: http://www.python.org/doc/2.5/tut/node16.html
Außerdem gibt es bereits das scipy-Modul mit diversen Integrationsroutinen.
Magst Du ein wenig Beispielcode posten, damit wir herausfinden können, wo evtl. der Fehler liegt?
Gruß,
Christian
Code: Alles auswählen
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import decimal
import time
grenze1 = None
grenze2 = None
while True:
grenze1 = raw_input("erste Grenze: ")
try:
grenze1 = int(grenze1)
print "Sie haben",grenze1,"eingegeben"
str = raw_input("Ist das okay [y/n] ")
input = str.find("y")
if input==0:
break
except:
print "Bitte eine Zahl eingeben"
while True:
grenze2 = raw_input("zweite Grenze(größer als erste): ")
try:
grenze2 = int(grenze2)
if grenze2 < grenze1:
print "zweite Grenze ist kleiner als erste Grenze"
else:
print "Sie haben",grenze2,"eingegeben"
str = raw_input("Ist das okay [y/n] ")
input = str.find("y")
if input==0:
break
except:
print "Bitte eine Zahl eingeben"
print grenze1,grenze2
integral = 0
grenze1 = float(grenze1)
grenze2 = float(grenze2)
interval= 0.1
#Hier die Funktion eintragen
funktion = lambda x: x
i=grenze1
print interval,grenze1,grenze2
time.sleep(10)
while i < (grenze2):
integral += (((funktion(i)+funktion((i+interval))/2)*interval))
print integral,i
i += interval
print "Das Integral ist",integral
Wenn es auch eine Bibliothek sein darf, die nicht in der Standardbibliothek enthalten ist, dann gibt's auch eine Anbindung an die gmp-Bibliothek: http://code.google.com/p/gmpy/
Das Problem bei Deinem Quelltext ist wahrscheinlich, dass sich durch die vielen Additionen beim Intervall die Rechenungenauigkeiten addieren.
Ich habe einfach mal folgende Schleife an das Programm angehängt, die bekommt genauere Ergebnisse heraus:
Numerik mit Fliesskommazahlen sind ein spannendes Thema, allerdings muss man auch ziemlich aufpassen.
Das Problem bei Deinem Quelltext ist wahrscheinlich, dass sich durch die vielen Additionen beim Intervall die Rechenungenauigkeiten addieren.
Ich habe einfach mal folgende Schleife an das Programm angehängt, die bekommt genauere Ergebnisse heraus:
Code: Alles auswählen
integral = 0
interval = 0.1
for step in xrange(int((grenze2 - grenze1) / interval)):
point = step * interval
integral += (funktion(point) + funktion(point + interval)) / 2 * interval
print integral
Und wo verwendest du da decimal?
Wandel die raw_inputs doch in decimal.Decimal Objekte um. Beispielsweise
Wandel die raw_inputs doch in decimal.Decimal Objekte um. Beispielsweise
Code: Alles auswählen
# ...
try:
grenze1 = decimal.Decimal(grenze1)
# ...
-
- User
- Beiträge: 136
- Registriert: Sonntag 15. Januar 2006, 20:31
- Wohnort: Greifswald
- Kontaktdaten:
Ich entschuldige mich vorneweg, falls ich das Offensichtliche übersehen haben sollte, aber ich habe das Problem noch nicht verstanden. DaSch: Mit welchen Eingabewerten kommt bei Dir welches falsche Ergebnis heraus und welches richtige sollte heraus kommen?
Gruß,
Bernhard
- integral += (((funktion(i)+funktion((i+interval))/2)*interval))
Gruß,
Bernhard
Bei 0 und 1 sollte 0.5 herauskommen, bei DaSch's Implementierung kommt aber 0.88 heraus.
An der Ganzzahl kann es nicht liegen, da immer eine Fliesskommazahl durch die 2 geteilt wird, eine 2.0 ändert an der Stelle nichts am Ergebnis.
An der Ganzzahl kann es nicht liegen, da immer eine Fliesskommazahl durch die 2 geteilt wird, eine 2.0 ändert an der Stelle nichts am Ergebnis.
Hoi,
Nun ja, BJ hat das Problem ja sehr genau erkannt und auch ein Beispiel gegeben, wie es besser geht. Das Problem bleibt jedoch bestehen, wenn man ohne Approximation summiert: Das "Integral" wird durch das Inkrement oder Interval bestimmt, weil es sich um eine "Summe" handelt. Die (meiner Ansicht nach) einfachste, halbwegs exakte Möglichkeit ist die Integration nach der Simpsonschen Regel (gar nicht so schwer, wie es ausschaut!). Dies und mehr ist übrigens in scipy integriert - außerdem gibt es ein Tutorial mit Einleitung in die Mathematik hinter den einzelnen Funktionen. Soll natürlich niemanden abhalten selber zu coden .
Gruß,
Christian
Das ist nicht sehr clever: Erst kann Dein Anwender (und wenn es nur Du selber bist, solltest Du da aufpassen, denn Du wirst in einem halben Jahr nicht immer wissen, was Du genau geschrieben hast) beliebige Genauigkeit vor, konvertierst dann in einen Integer und rechnest am Ende mit einer Fließkommazahl weiter. Warum nicht gleich mit einer Fließkommazahl rechnen?DaSch hat geschrieben:Code: Alles auswählen
... grenze1 = int(grenze1)... grenze1 = float(grenze1)
Nun ja, BJ hat das Problem ja sehr genau erkannt und auch ein Beispiel gegeben, wie es besser geht. Das Problem bleibt jedoch bestehen, wenn man ohne Approximation summiert: Das "Integral" wird durch das Inkrement oder Interval bestimmt, weil es sich um eine "Summe" handelt. Die (meiner Ansicht nach) einfachste, halbwegs exakte Möglichkeit ist die Integration nach der Simpsonschen Regel (gar nicht so schwer, wie es ausschaut!). Dies und mehr ist übrigens in scipy integriert - außerdem gibt es ein Tutorial mit Einleitung in die Mathematik hinter den einzelnen Funktionen. Soll natürlich niemanden abhalten selber zu coden .
Gruß,
Christian
-
- User
- Beiträge: 136
- Registriert: Sonntag 15. Januar 2006, 20:31
- Wohnort: Greifswald
- Kontaktdaten:
Danke, BlackJack, für das Beispiel. Ich hatte übersehen, dass durch das feste Intervall mit 0.1 ja automatisch ein Float irgendwo da hinein kommt. Das ist aber nicht das Problem. Das Problem scheint mir die Schleifenbedingung.
Wenn man die Grenzen, wie von Blackjack vorgeschlagen mit 0.0 und 1.0 eingibt, dann rechnet der Originalcode auch noch die Fläche zwischen 1.0 und 1.1 mit. Das folgende Beispiel kommt auf den richtigen Wert 0.5:
Gruß,
Bernhard
Wenn man die Grenzen, wie von Blackjack vorgeschlagen mit 0.0 und 1.0 eingibt, dann rechnet der Originalcode auch noch die Fläche zwischen 1.0 und 1.1 mit. Das folgende Beispiel kommt auf den richtigen Wert 0.5:
Code: Alles auswählen
grenze1 = 0.0 #habe hier ein wenig gekürzt
grenze2 = 1.0
integral = 0.0
grenze1 = float(grenze1)
grenze2 = float(grenze2)
interval= 0.1
#Hier die Funktion eintragen
funktion = lambda x: x
i=grenze1
while i < (grenze2-interval): #hat vorher zu lange gerechnet !
integral += (funktion(i)+funktion(i+interval))/2 *interval
print funktion(i),'+',funktion(i+interval),'/2 *',interval,' = ', (funktion(i)+funktion(i+interval))/2 *interval
print "Summe bisher:",integral
i += interval
print
print 'Integral ist ',integral
Bernhard
Die laufende Summierung ist aber auch ein Problem weil in jedem Schritt `i` etwas ungenauer wird. Beispiel:
Die beiden letzten Ergebnisse müssten ja mathematisch betrachtet gleich sein. Da aber nach dem 10. mal 0.1 addieren etwas herauskommt, das kleiner ist als 1, rechnet die Schleife im Original noch ein Intervall weiter.
Ich könnt's jetzt nicht beschwören, aber ich habe so ein Bauchgefühl, dass man nur die richtigen Grenzen und eine passende Intervallbreite finden muss, damit Deine Schleife auch einmal zuviel oder zu wenig ausgeführt wird.
Code: Alles auswählen
[In [80]: [0.1] * 10
Out[80]:
[0.10000000000000001,
0.10000000000000001,
0.10000000000000001,
0.10000000000000001,
0.10000000000000001,
0.10000000000000001,
0.10000000000000001,
0.10000000000000001,
0.10000000000000001,
0.10000000000000001]
In [81]: sum([0.1] * 10)
Out[81]: 0.99999999999999989
In [82]: 0.1 * 10
Out[82]: 1.0
Ich könnt's jetzt nicht beschwören, aber ich habe so ein Bauchgefühl, dass man nur die richtigen Grenzen und eine passende Intervallbreite finden muss, damit Deine Schleife auch einmal zuviel oder zu wenig ausgeführt wird.
-
- User
- Beiträge: 136
- Registriert: Sonntag 15. Januar 2006, 20:31
- Wohnort: Greifswald
- Kontaktdaten:
Das ist schon ganz schön erschreckend, wenn man bedenkt, dass hier Fehler auftreten, obwohl interval mit 0.1 ja doch keine Zahl mit vielen Nachkommastellen ist.
Deine Version
dürfte da robuster sein.
Glaubst Du, dass sie völlig problemlos ist, oder könnte auch sie duch geeignete Grenzen und Intervalle (z.B. Differenz der Grenzen sehr ähnlich wie Intervall) torpediert werden?
Gruß,
Bernhard
Deine Version
Code: Alles auswählen
for step in xrange(int((grenze2 - grenze1) / interval)):
Glaubst Du, dass sie völlig problemlos ist, oder könnte auch sie duch geeignete Grenzen und Intervalle (z.B. Differenz der Grenzen sehr ähnlich wie Intervall) torpediert werden?
Gruß,
Bernhard
Da die Fliesskommazahlen nur endliche Genauigkeit haben kann man da sicher auch Fälle bekommen, bei denen es Probleme gibt.
Ich habe es mal mit rationalen Zahlen versucht:
Das bleibt natürlich nur solange genau, wie `funktion()` ein rationales Ergebnis liefert und im Zweifelsfall genug Speicher zur Verfügung steht um Zähler und Nenner zu speichern.
Ich habe es mal mit rationalen Zahlen versucht:
Code: Alles auswählen
from gmpy import mpq
funktion = lambda x: x
grenze1 = 0
grenze2 = 1
integral = 0
interval = mpq(1, 10)
for step in xrange(int((grenze2 - grenze1) / interval)):
point = step * interval
integral += (funktion(point) + funktion(point + interval)) / 2 * interval
print integral
also wenn man z.B. also Beispiel mit der Formel für y=x und den Grenzen 0 bis 1 mit einem Interval von 1 rechnet dann bekommt man ein korrecktes Ergebnis, das bring aber einen nicht weiter wenn man für einen größere Abstand zwischen den Grenzen dann Murks bekommt, das Problem ist wirklich wie geschildert dass mit der Menge der multiplikationen sich auch der Fehler multipliziert
Die Idee ist auch dass man das Intervall kleiner machen kann um dann die grenzen auch näher aneinander legen kann und dann trotzdem ein sinnvolles Ergebins rausbekommt egal welche Formel man da jetzt eintippt
Die Idee ist auch dass man das Intervall kleiner machen kann um dann die grenzen auch näher aneinander legen kann und dann trotzdem ein sinnvolles Ergebins rausbekommt egal welche Formel man da jetzt eintippt