Hallo zusammen,
Ich habe erst kürzlich an der Hochschule mit dem Programmieren begonnen, nun muss ich ein Programm erstellen, dass eine Approximation von Pi berechnet. Dies geschieht anhand dieser Formel von Srinivasa Ramanujan. In dieser Formel gibt es ein Summenzeichen, was mir in Python Mühe bereitet. Ich erhalte ein Resultat, das aber leider weit entfernt von Pi ist. Hier mein bisheriges Programm, wie gesagt ich bin Anfänger:
import math
first_part = float((2*math.sqrt(2))/9801)
n=0
second_part = (math.factorial(4*n))/(math.factorial(n))**4
third_part = ((1103+26390*n)/(396**(4*n)))
while third_part >(1e-15):
second_part = (math.factorial(n)*4)/(math.factorial(n))**4
third_part = ((1103+26390*n)/(396**(4*n)))
a=second_part*third_part
a=a+1
n+=1
pi=(a*first_part)**-1
print (pi)
Vielen Dank für eure Hilfe
Approximation von Pi mit Formel von Srinivasa Ramanujan
- __blackjack__
- User
- Beiträge: 14033
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@fcz1896: Da in Python Einrückung wichtiger Teil der Syntax ist, müsstest Du Code in [ code ] Tags posten. Im „Vollständigen Editor“ (Schaltfläche unter der Texteingabe mit dem Titel „Schnellantwort“) gibt es dafür auch eine Schaltfläche zum Einfügen der Tags wo der Quelltext dann zwischen stehen sollte. Wenn der Quelltext ausgewählt war, wird er beim klick auf die Code-Schaltfläche zwischen die Tags gesetzt.
Was ist denn Dein Problem mit dem Summenzeichen? Das ist in Code ausgedrückt ja eine Schleife.
Anmerkungen zum Code: Gleichen Code und gleiche Daten sollte man nicht wiederholen. Das ist unnötige Arbeit beim Programmieren, fehleranfälliger beim schreiben und erst recht wenn man Code anpassen muss/will, und auch der Leser wird mehr ”belastet”, weil der ja weiss das sich Programmierer nicht wiederholen, und dementsprechend nach Unterschieden in den Kopien sucht und sich fragt ob da ein Fehler gemacht wurde wenn es keine Unterschiede gibt. Konkret sollte die Berechnung von `second_part` und `third_part` da nicht zweimal im Code stehen, sondern nur einmal *in* der Schleife. Die Schleife selbst sollte dann die Abbruchbedingung mit einem ``if`` im Schleifenkörper haben und gegebenenfalls mit einem ``break`` abbrechen wenn das Ergebnis fest steht. Im Grunde ist da momentan auch ein Programmierfehler drin, denn wenn die Schleifenbedingung schon beim ersten mal nicht erfüllt würde, wird der Schleifenkörper gar nicht durchlaufen und damit auch `a` gar nicht definiert. Das wird *nach* der Schleife aber verwendet.
Also kann/sollte man aus der Schleife eine ”Endlosschleife” machen die am Ende eine Abbruchbedingung mit ``if`` und ``break`` kodiert hat. Entweder mit ``while True:`` oder mit einer ``for``-Schleife über ganze Zahlen, denn `n` ist hier ja eigentlich eine Schleifenlaufvariable.
Für den `float()`-Aufruf bei `first_part` sehe ich keinen Grund. Bei den Berechnungen sind einige Klammerpaare überflüssig. Also *so* überflüssig das man nicht mal argumentieren kann, dass die beim Lesen/verstehen helfen.
Warum hast Du die Berechnung von `a` in zwei Teile aufgeteilt? Das ``+ 1`` kann man doch auch sofort machen, statt in einem extra Schritt.
`first_part` wird lange berechnet bevor der Wert überhaupt benötigt wird. Das kann man nicht nur hinter die Schleife ziehen, sondern auch gleich direkt in die Berechnung einbauen. Der Name selbst hatte ja keinen Mehrwert.
Ich sehe in dem Code jetzt aber auch nirgends wo etwas wie bei einem Summenzeichen üblich aufsummiert wird.
Ich bin zu faul um nach der mathematischen Formel zu suchen. Ich vermute mal das Du die halt irgendwo falsch in Code umgesetzt hast, insbesondere weil es Code ja keine Entsprechung eines Summenzeichens gibt. Beim Programmieren hilft es in der Regel Probleme die man nicht so leicht lösen kann in kleinere Teilprobleme aufzuteilen und die dann einzeln in Funktionen zu lösen. Bei einem Summenzeichen könntest Du eine Funktion schreiben, die einen Summanden berechnet, und diese Funktion dann in einer Schleife verwenden welche die ausgerechneten Summanden dann aufsummiert.
Was ist denn Dein Problem mit dem Summenzeichen? Das ist in Code ausgedrückt ja eine Schleife.
Anmerkungen zum Code: Gleichen Code und gleiche Daten sollte man nicht wiederholen. Das ist unnötige Arbeit beim Programmieren, fehleranfälliger beim schreiben und erst recht wenn man Code anpassen muss/will, und auch der Leser wird mehr ”belastet”, weil der ja weiss das sich Programmierer nicht wiederholen, und dementsprechend nach Unterschieden in den Kopien sucht und sich fragt ob da ein Fehler gemacht wurde wenn es keine Unterschiede gibt. Konkret sollte die Berechnung von `second_part` und `third_part` da nicht zweimal im Code stehen, sondern nur einmal *in* der Schleife. Die Schleife selbst sollte dann die Abbruchbedingung mit einem ``if`` im Schleifenkörper haben und gegebenenfalls mit einem ``break`` abbrechen wenn das Ergebnis fest steht. Im Grunde ist da momentan auch ein Programmierfehler drin, denn wenn die Schleifenbedingung schon beim ersten mal nicht erfüllt würde, wird der Schleifenkörper gar nicht durchlaufen und damit auch `a` gar nicht definiert. Das wird *nach* der Schleife aber verwendet.
Also kann/sollte man aus der Schleife eine ”Endlosschleife” machen die am Ende eine Abbruchbedingung mit ``if`` und ``break`` kodiert hat. Entweder mit ``while True:`` oder mit einer ``for``-Schleife über ganze Zahlen, denn `n` ist hier ja eigentlich eine Schleifenlaufvariable.
Für den `float()`-Aufruf bei `first_part` sehe ich keinen Grund. Bei den Berechnungen sind einige Klammerpaare überflüssig. Also *so* überflüssig das man nicht mal argumentieren kann, dass die beim Lesen/verstehen helfen.
Warum hast Du die Berechnung von `a` in zwei Teile aufgeteilt? Das ``+ 1`` kann man doch auch sofort machen, statt in einem extra Schritt.
`first_part` wird lange berechnet bevor der Wert überhaupt benötigt wird. Das kann man nicht nur hinter die Schleife ziehen, sondern auch gleich direkt in die Berechnung einbauen. Der Name selbst hatte ja keinen Mehrwert.
Code: Alles auswählen
#!/usr/bin/env python3
import math
from itertools import count
def main():
for n in count():
second_part = math.factorial(4 * n) / math.factorial(n)**4
third_part = (1103 + 26390 * n) / 396**(4 * n)
a = second_part * third_part + 1
if third_part <= 1e-15:
break
pi = (a * 2 * math.sqrt(2) / 9801)**-1
print(pi)
if __name__ == '__main__':
main()
Ich bin zu faul um nach der mathematischen Formel zu suchen. Ich vermute mal das Du die halt irgendwo falsch in Code umgesetzt hast, insbesondere weil es Code ja keine Entsprechung eines Summenzeichens gibt. Beim Programmieren hilft es in der Regel Probleme die man nicht so leicht lösen kann in kleinere Teilprobleme aufzuteilen und die dann einzeln in Funktionen zu lösen. Bei einem Summenzeichen könntest Du eine Funktion schreiben, die einen Summanden berechnet, und diese Funktion dann in einer Schleife verwenden welche die ausgerechneten Summanden dann aufsummiert.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
schau mal hier rein
https://kalanjia.wordpress.com/2017/08/ ... thon-code/
https://kalanjia.wordpress.com/2017/08/ ... thon-code/
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
@fcz1896: eine Summation sieht meist so aus:
Wie sieht bei Dir der Term aus, der aufsummiert werden soll?
@ThomasL: toll, eine Seite, wo der Pythoncode auch ohne Einrückung abgedruckt ist, und factorial selbst definiert wird, obwohl das schon in math.factorial existiert und pow benutzt, obwohl es ja ** gibt.
Code: Alles auswählen
summe = 0
for n in count():
term = ...
summe += term
if term < 1e-15:
break
@ThomasL: toll, eine Seite, wo der Pythoncode auch ohne Einrückung abgedruckt ist, und factorial selbst definiert wird, obwohl das schon in math.factorial existiert und pow benutzt, obwohl es ja ** gibt.
Nun ja, allgemeiner Tenor hier im Forum ist ja wohl nicht jeden Pups vorzukauen sondern zum selber nachdenken und lernen anzuregen.Sirius3 hat geschrieben: Samstag 27. Oktober 2018, 09:53 @ThomasL: toll, eine Seite, wo der Pythoncode auch ohne Einrückung abgedruckt ist, und factorial selbst definiert wird, obwohl das schon in math.factorial existiert und pow benutzt, obwohl es ja ** gibt.
Mit etwas Pythongrundlagen kann man sich den Code dort entsprechend erarbeiten und erkennen, dass dieser etwas anders ist als man selber zuvor gecodet hat.
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Hmja. Der Tenor ist richtig. Aber wenn ich sehe, wieviel Code da draußen dermaßen offensichtlich abgeschrieben/kopiert wird, und wie sich in speziellen Communities wirklich grauenvolle Muster entwickeln und halten, dann bin ich deiner These, dass sich da was ausmengelt skeptisch gegenüber. Das DU das tust, daran zweifele ich nicht 

Vielen Dank an alle für eure Hilfe und ich entschuldige mich für die unprofessionelle Darstellung meines Beitrages. Ich bin nun ein gutes Stück weitergekommen, aber noch nicht ganz am Ziel. Ich vermute ich habe eine Endschlosschlaufe programmiert;
@__blackjack__ ich habe versucht meine Fehler und unnötigen Codezeilen so gut es geht zu korrigieren, vielen Dank für deine Inputs.
@ThomasL Danke für die Musterlösung, einige Funktionen darin wurden bei uns noch nicht behandelt, weshalb ich sie nicht verwenden kann.
Gibt es eine Möglichkeit meinen neuen Code mit den verwendeten Tools zum laufen zu bringen?
Nochmals danke für euren Support!
Code: Alles auswählen
import math
first_part=(math.sqrt(8))/9801
n=0
summe=0
while True:
second_part = ((math.factorial(n)*4)/(math.factorial(n))**4)
third_part=((1103+26390*n)/(396**(4*n)))
summe+=second_part*third_part
if third_part<=1e-15:
break
n+1
pi=(summe*first_part)**-1
print (pi)
@ThomasL Danke für die Musterlösung, einige Funktionen darin wurden bei uns noch nicht behandelt, weshalb ich sie nicht verwenden kann.
Gibt es eine Möglichkeit meinen neuen Code mit den verwendeten Tools zum laufen zu bringen?
Nochmals danke für euren Support!
@fcz1896 deine if Abfrage um die Schleife zu verlassen ist nicht ganz richtig, da fehlt ein _part (alles das was hinter dem Summenzeichen steht muss da hin)
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
@fcz1896: __blackjack__ hat Dir gezeigt, wie man eine Schleife mit Zählvariable richtig macht. Mit while statt for geht das zwar auch, aber dann macht man halt auch leicht mal einen Fehler, weil die while-Schleife deutlich komplizierter ist.
In die Formeln hast Du beim Abschreiben von Dir selbst auch noch zusätzlich Fehler eingebaut, die man dank der vielen überflüssigen Klammern kaum sieht.
In die Formeln hast Du beim Abschreiben von Dir selbst auch noch zusätzlich Fehler eingebaut, die man dank der vielen überflüssigen Klammern kaum sieht.
Ich habe schlussendlich noch eine Lösung gefunden. Sie ist nicht perfekt aber falls jemand mal vor dem gleichen Problem steht, hier mein Code:
Nochmals vielen Dank an alle für eure Hilfe.
Code: Alles auswählen
import math
n=0
summe=0 #Zwischenspeicher
summe_temp=1 #Sonst Division durch 0 auf Zeile 17
summe_teil3 =((1103+26390*n)/396**(4*n))
while summe_teil3>10**-15:
summe_temp = (math.factorial(4*n)/(math.factorial(n)**4))
summe_teil3 =((1103+26390*n)/396**(4*n))
summe = summe + summe_temp*summe_teil3 #Summenzeichen
n = n+1
pi= 1/(((2*((math.sqrt(2))))/9801)*summe) #1. Teil
print (pi)
print (math.pi)
Die Zeile mit `summe_temp=1` ist überflüssig, wie auch der Kommentar falsch. Das `summe_teil3` außerhalb der Schleife wird auch nirgends benutzt, außer in die while-Schleife einzutreten, daher for- oder while-True-Schleife.
oder um die teuren Operationen zu vermeiden:
Code: Alles auswählen
import math
n=0
summe = 0
while True:
teil2 = math.factorial(4*n) / math.factorial(n)**4
teil3 = (1103+26390*n) / 396**(4*n)
summe += teil2 * teil3
n += 1
if teil3 <= 1e-15:
break
pi = 1 / (2 * math.sqrt(2) / 9801 * summe)
print(pi)
print(math.pi)
Code: Alles auswählen
from itertools import count
summe = teil3 = 1103
teil2 = 1
for n in count(4, step=4):
teil2 *= (n-3) * (n-2) * (n-1) * n / (99 * n) ** 4
teil3 += 26390
summe += teil2 * teil3
if teil3*teil2 <= 1e-15:
break
pi = 1 / (summe * 8**0.5 / 9801)
print(pi)
print(math.pi)