@rectosh99: Wenn man den Quelltext in Code-Tags setzt im Beitrag, dann bleiben die Einrückungen erhalten, die bei Python ja wichtiger Bestandteil der Syntax sind:
Code: Alles auswählen
import numpy as np
import pylab as pl
#--------------------------------------------
def fu(x):
#--------------------------------------------
#return np.exp(-x**2)
return np.sin(x)/(x+1)+0.2
#return 2*x**2-x+1 # hier liefert Sipson den korr Wert!!
#--------------------------------------------
def IntTrapez(a, b, n):
#--------------------------------------------
sr = []
X = []
Y = []
X.append(a)
Y.append(fu(a))
dx = (b-a)/n
s = (fu(a) + fu(b))/2
xi=a
for i in range(2,n+1,1):
xi += dx
s += fu(xi)
cs = " Trapez: i=%2d x=%6.2f f(x)=%6.2f summe=%8.5f" % (i, xi, fu(xi), s*dx)
X.append(xi)
Y.append(fu(xi))
sr.append(cs)
s *= dx
X.append(b)
Y.append(fu(b))
return (s, sr, X, Y)
#--------------------------------------------
def IntSimpson(a, b, n):
#--------------------------------------------
sr = []
if (n % 2 != 0):
sr.append("Simpson: n muss gerade sein.")
return (0, sr)
dx = (b - a) / n
s = fu(a) + fu(b)
xi = a
for i in range(1,n,1):
xi = xi + dx
if (i % 2 == 0 ):
s += 2 * fu(xi)
else:
s += 4 * fu(xi)
cs = " Simpson: i=%2d x=%6.2f f(x)=%6.2f summe=%8.5f" % (i, xi, fu(xi), s*dx/3)
sr.append(cs)
return (s*dx/3 , sr)
#--------------------------------------------
def IntGauss3(a, b):
#--------------------------------------------
sr = []
xsi =[-0.774596669241483, 0, 0.774596669241483]
alpha =[0.555555555555556, 0.888888888888889, 0.555555555555556]
s = 0
for i in range(0,3,1):
xi = (a + b) / 2 + xsi[i] * (b - a) / 2
Wi = alpha[i] * (b - a) / 2
s += Wi * fu(xi)
cs = " Gauss3: i=%2d xi=%6.4f Wi=%6.4f f(xi)= %6.2f summe=%8.5f" % (i, xi, Wi, fu(xi), s)
sr.append(cs)
return (s, sr)
#--------------------------------------------
def SubsequCallToAllMethods(a,b,n):
#--------------------------------------------
# unsere Ergebnisse:
(sTr,srT,Xi,Yi) = IntTrapez(a, b, n)
(sSi,srS) = IntSimpson(a, b, n)
(sGs,srG) = IntGauss3(a, b)
print("Trapez =", sTr)
for c in srT :
print(c)
print("Simpson =", sSi)
for c in srS :
print(c)
print("Gauss3 =", sGs)
for c in srG :
print(c)
# Plot:
X = np.linspace(a,b,100)
Y = fu(X)
ax=pl.gca()
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data',0))
clabel =("f(x)")
pl.plot( X, Y, 'b', label=clabel)
clabel =("Trapez = %8.6f") % (sTr)
pl.plot( Xi, Yi, 'g', label=clabel)
#pl.scatter(X, Y)
pl.xlabel("x")
pl.ylabel("f(x)")
pl.legend ()
pl.show()
#--------------------------------------------
def Konvergenztester(a,b):
#--------------------------------------------
results_n1 =[]
results_n2 =[]
results_Trapez = []
results_Simpson = []
err_Trapez = []
err_Simpson = []
quitAtRoudOffErrPerc = 0.005
(errp1, errp2) = (1e100,1e100)
happy = False
iTest1, iTest2 = 0,0
for n in range(4,1000,2):
(intTrapez,srT,Xi,Yi) = IntTrapez(a, b, n)
(intSimpson,srS) = IntSimpson(a, b, n)
if(len(results_Trapez) > 0 and len(results_Simpson) > 0):
errp1 = abs((results_Trapez[-1] - intTrapez)/intTrapez) * 100
errp2 = abs((results_Simpson[-1] - intSimpson)/intSimpson) * 100
if(errp1 > quitAtRoudOffErrPerc or len(results_n1) == 0):
iTest1 += 1
results_n1.append(n)
err_Trapez.append(errp1)
if(errp2 > quitAtRoudOffErrPerc or len(results_n2) == 0):
iTest2 += 1
results_n2.append(n)
err_Simpson.append(errp2)
results_Trapez.append(intTrapez)
results_Simpson.append(intSimpson)
if(errp1 <= quitAtRoudOffErrPerc and errp2 <= quitAtRoudOffErrPerc):
happy = True
break
if(not happy):
print("Keine Konvergenz nach", n , "Schritten")
clabel = "Trapezregel %s intervals, err=%6.2f %% after %d steps" % (results_n1[-1],err_Trapez[-1],iTest1)
pl.plot( results_n1, err_Trapez, 'b', label="%s" % clabel)
clabel = "Simpson %s intervals, err=%6.2f %% after %d steps" % (results_n2[-1],err_Simpson[-1],iTest2)
pl.plot( results_n2, err_Simpson, 'g', label="%s" % clabel)
pl.xlabel(r'$intervals$')
pl.ylabel(r'$est. err. [\%] $')
pl.legend ()
pl.show()
#--------------------------------------------
def main():
#--------------------------------------------
# Eingabe:
inpStr = input("Integrationsformeln\nGib a= b= n= (mit , getrennt)")
nSeps = inpStr.count(',')
if (nSeps != 2):
print("error: you have to define a,b,n separated by exactly two commas such as 0,1,10")
return False
(a,b,n) = inpStr.split(",")
if (a.isnumeric() == False or b.isnumeric() == False or n.isnumeric() == False):
print("error: a,b,n have to be numbers")
return False
(a,b,n) = [float(a), float(b), int(n)]
print("a=",a,"b=",b,"n=",n)
SubsequCallToAllMethods(a,b,n)
Konvergenztester(a,b)
#input("...press any key to continue")
#--------------------------------------------
#--------------------------------------------
if __name__ == "__main__":
main()
Was meinst Di mit „Programmierungsprinzip“? Ich sehe da Funktionen mit prozeduralem Code als Inhalt, also nichts was sich jetzt wesentlich von Basic/VBA unterscheiden würde. Du hast da sogar ein bisschen Glück, dass da scheinbar nichts verwendet wird, was zu weit von VBA abweicht. Die Funktion hätte man beispielsweise als Argument übergeben können/sollen, statt da eine hart kodierte `fu()`-Funktion in den verschiedenen Integrationsvarianten aufzurufen. Funktionen sind in Python nämlich auch Werte.
Wo genau liegen denn die Verständnisprobleme? Was sind die Fragen die nach dem Durcharbeiten vom Grundlagentutorial in der Python-Dokumentation nicht geklärt sind? Was verstehst Du konkret nicht? Weicht irgendwo ein (Zwischen)Ergebnis von dem ab was Du erwartest? Was hättest Du da erwartet und was bekommst Du?
Hilfreich wäre vielleicht wenn Du das Programm etwas überarbeitest. Ich habe jetzt raus was die *Werte* von `sr` und `cs` bedeuten, aber nicht wirklich was die *Namen* bedeuten. Wenn man da sinnvolle Namen verwendet, wird es schon verständlicher. Im allgemeinden sollte man keine kryptischen Abkürzungen in Namen verwenden, und schon gar keine Namen die nur daraus bestehen. Denn der Zweck von Namen ist ja dem Leser die Bedeutung der Werte dahinter zu vermitteln.
Ich würde übrigens sagen, dass das Programm fehlerhaft ist, denn die Schrittweite ``dx = (b-a)/n`` berechnen und dann in jedem Schritt `dx` aufaddieren ist bei Gleitkommazahlen eine schlechte Idee, denn die sind nicht exakt und bei jeder Addition kann es dadurch ungenauer werden. An einer Stelle beim Plotten wird ja bereits `numpy.linspace()` verwendet. Insgesamt würde es vielleicht Sinn machen wenn man `numpy` mehr verwenden würde in dem Programm.
Das scheint auch nicht von einem Python-Programmierer zu sein. Es wird sich an einige Konventionen aus dem
Style Guide for Python Code nicht gehalten. Zum Beispiel das Namen klein_mit_unterstrichen geschrieben werden, und was Leerzeichen- und Zeilensetzung angeht um die Lesbarkeit zu erhöhen. Dann gibt es unnötige Klammern um Bedingungen bei ``if`` & Co und den Defaultwert 1 für die Schrittweite bei `range()` gibt man auch nicht an. ”Linien”-Kommentare sind auch unüblich.
Man muss auch nicht jedes kleine Zwischenergebnis an einen Namen binden. Insbesondere wenn der Name dann auch noch kryptisch ist, macht dass das lesen/verstehen eher schwerer als einfacher.
Bei der `main()` machen die ``return False`` keinen Sinn, weil es nirgends ein ``return True`` gibt. Die Funktion gibt also entweder `False` oder `None` zurück.
Man vergleicht auch nicht mit literalen Wahrheitswerten. Da kommt ja nur wieder ein Wahrheitswert bei heraus. Also hätte man auch gleich den Wert nehmen können mit dem man vergleicht, beziehungsweise dessen negation. Also statt:
Code: Alles auswählen
if (
a.isnumeric() == False
or b.isnumeric() == False
or n.isnumeric() == False
):
print("error: a,b,n have to be numbers")
# besser
if not a.isnumeric() or not b.isnumeric() or not n.isnumeric():
print("error: a,b,n have to be numbers")
# beziehungsweise
if not (a.isnumeric() and b.isnumeric() and n.isnumeric()):
print("error: a,b,n have to be numbers")
Diese Tests sind aber ein bisschen ”unpythonisch”. Man würde einfach die Umwandlung machen und auf den `ValueError` reagieren der dabei ausgelöst werden kann. Da Zuweisung an mehrere Namen auch mit einem `ValueError` fehl schlägt, wenn die Anzahl der Werte nicht passt, kann man das gleich mit berücksichtigen.
Den ``%``-Operator für Zeichenkettenformatierung benutzt man eigentlich schon lange nicht mehr ohne einen guten Grund. Dafür gibt es f-Zeichenkettenliterale.
Bei `konvergenztester()` sind viele schlechte Namen, die man besser sprechender wählen würde.
`iTest1` und `iTest2` sind überflüssig, weil das die Längen der dazugehörigen Listen sind, die man einfach mit `len()` abfragen kann.
Das ganze in einem ersten Überarbeitungsschritt (ungetestet) etwas „pythonischer“ und lesbarer:
Code: Alles auswählen
#!/usr/bin/env python3
import numpy as np
import pylab as pl
def funktion(x):
# return np.exp(-x ** 2)
return np.sin(x) / (x + 1) + 0.2
# return 2 * x ** 2 - x + 1 # hier liefert Simpson den korrekten Wert!
def trapez_integration(a, b, n):
summe = (funktion(a) + funktion(b)) / 2
texte = []
xs = [a]
ys = [funktion(a)]
x_i = a
d_x = (b - a) / n
for i in range(2, n + 1):
x_i += d_x
summe += funktion(x_i)
xs.append(x_i)
ys.append(funktion(x_i))
texte.append(
f"Trapez: i={i:2d} x={x_i:6.2f} f(x)={funktion(x_i):6.2f}"
f" summe={summe * d_x:8.5f}"
)
xs.append(b)
ys.append(funktion(b))
return (summe * d_x, texte, xs, ys)
def simpson_integration(a, b, n):
if n % 2 != 0:
return (0, ["Simpson: n muss gerade sein."])
summe = funktion(a) + funktion(b)
texte = []
x_i = a
d_x = (b - a) / n
for i in range(1, n):
x_i += d_x
summe += (2 if i % 2 == 0 else 4) * funktion(x_i)
texte.append(
f"Simpson: i={i:2d} x={x_i:6.2f} f(x)={funktion(x_i):6.2f}"
f" summe={summe * d_x / 3:8.5f}"
)
return (summe * d_x / 3, texte)
def gauss3_integration(a, b):
xsis = [-0.774596669241483, 0, 0.774596669241483]
alphas = [0.555555555555556, 0.888888888888889, 0.555555555555556]
summe = 0
texte = []
for i, (xsi, alpha) in enumerate(zip(xsis, alphas)):
x_i = (a + b) / 2 + xsi * (b - a) / 2
w_i = alpha * (b - a) / 2
summe += w_i * funktion(x_i)
texte.append(
f"Gauss3: i={i:2d} xi={x_i:6.4f} Wi={w_i:6.4f}"
f" f(xi)={funktion(x_i):6.2f} summe={summe:8.5f}"
)
return (summe, texte)
def subsequent_call_to_all_methods(a, b, n):
trapez_summe, trapez_texte, trapez_xs, trapez_ys = trapez_integration(
a, b, n
)
simpson_summe, simpson_texte = simpson_integration(a, b, n)
gauss_summe, gauss_texte = gauss3_integration(a, b)
for methoden_name, summe, texte in [
("Trapez", trapez_summe, trapez_texte),
("Simpson", simpson_summe, simpson_texte),
("Gauss3", gauss_summe, gauss_texte),
]:
print(methoden_name, "=", summe)
for text in texte:
print(" ", text)
ax = pl.gca()
ax.xaxis.set_ticks_position("bottom")
ax.spines["bottom"].set_position(("data", 0))
xs = np.linspace(a, b, 100)
pl.plot(xs, funktion(xs), "b", label="f(x)")
pl.plot(trapez_xs, trapez_ys, "g", label=f"Trapez = {trapez_summe:8.6f}")
pl.xlabel("x")
pl.ylabel("f(x)")
pl.legend()
pl.show()
def konvergenztester(a, b):
max_allowed_error = 0.005
trapez_ns = []
trapez_results = []
trapez_errors = []
simpson_ns = []
simpson_results = []
simpson_errors = []
trapez_error = simpson_error = np.Infinity
for n in range(4, 1000, 2):
trapez_summe, _, _, _ = trapez_integration(a, b, n)
simpson_summe, _ = simpson_integration(a, b, n)
if trapez_results and simpson_results:
trapez_error = (
abs((trapez_results[-1] - trapez_summe) / trapez_summe) * 100
)
simpson_error = (
abs((simpson_results[-1] - simpson_summe) / simpson_summe)
* 100
)
if trapez_error > max_allowed_error or not trapez_ns:
trapez_ns.append(n)
trapez_errors.append(trapez_error)
if simpson_error > max_allowed_error or not simpson_ns:
simpson_ns.append(n)
simpson_errors.append(simpson_error)
trapez_results.append(trapez_summe)
simpson_results.append(simpson_summe)
if (
trapez_error <= max_allowed_error
and simpson_error <= max_allowed_error
):
break
else:
print("Keine Konvergenz nach", n, "Schritten")
for methoden_name, ns, errors, colour in [
("Trapezregel", trapez_ns, trapez_errors, "b"),
("Simpson", simpson_ns, simpson_errors, "g"),
]:
pl.plot(
ns,
errors,
colour,
label=(
f"{methoden_name} {ns[-1]} intervals,"
f" err={errors[-1]:6.2f} % after {len(ns)} steps"
),
)
pl.xlabel(R"$intervals$")
pl.ylabel(R"$est. err. [\%] $")
pl.legend()
pl.show()
def main():
input_text = input(
"Integrationsformeln\n" "Gib a= b= n= (mit , getrennt)"
)
try:
a, b, n = map(int, input_text.split())
except ValueError:
print(
"error: a,b,n must be numbers and separatet by exactly two commas."
)
else:
print("a=", a, "b=", b, "n=", n)
subsequent_call_to_all_methods(a, b, n)
konvergenztester(a, b)
if __name__ == "__main__":
main()