MonteCarlo Simulation zur Approximation von pi

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
Sconine
User
Beiträge: 49
Registriert: Montag 1. Juni 2009, 11:00

Hallo zusammen,
schon wieder ich. :D

Diesmal habe ich mit einen Mitstudenten zu der Aufgabe:

Einem Kreis mit Radius 1 sei ein Quadrat dicht umschrieben: ‚Dart-Scheibe‘.
• Simulieren Sie zufällige Würfe auf die Dart-Scheibe.
• Zählen Sie die Treffer (im Kreis).
• Berechnen Sie 4 · (Treffer/Würfe).
• Vergleichen Sie mit π

folgendes Programm geschrieben:

Code: Alles auswählen

def montecarlo(N): # Funktion wird definiert

    """Auf einen Kreis in einem 1*1 großen Quadrat werden N Wuerfe simuliert.
    Sie liefert die durchschnittlichen Treffer * 4 zurueck. """ 

    from random import random # implementiert Zufallszahlen

    wuerfe, treffer = 0, 0 # bei 0 Wuerfe und Treffer wird begonnen

    while wuerfe<N: # Anweisungsblock wird solange wiederholt, bis die Bedingung
                    # eingetroffen ist (bis 

        # x und y sind die Koordinaten des geworfenen Pfeils
        # random liefert die Werte zwischen 0 und 1, zufällig

        x, y = random(), random()

        
        if (x**2+y**2)**0.5 < 1: # euklidische Abstand vom Nullpnkt wird
                                 # definiert, wenn die berechneten Abstand
                                 # kleiner 1 sind, dann wurde der Kreis getroffen

            treffer+=1

        wuerfe+=1

    return 4.*treffer/wuerfe # 4 mal werden de Treffer und Wuerfe berechnet



if __name__=='__main__':

    from math import pi # implementiert von math pi

    # Der versuch wird mit immer groesseren Anzahlen von Würfen wiederholt
    #und dann wird der Betrag des jeweiligen Abstandes zum bekannten pi berechnet

    
    for N in [1,10,100,1000,10000,100000,1000000]: # Anzahl von Wuerfen wird angegeben

        abweichung = abs(montecarlo(N)-pi) # liefert den absoluten Wert von x
                                           # (Abstand zwischen zwischen x und Null)
                                           

        print "Nach %d Wuerfen betrug die Abweichung zu pi: %f" %(N,abweichung)
Was bedeutet nochmal die Funktion _main_?
Ich wollte nun fragen, ob meine Kommentare richtig sind und ob es noch verbesserungsvorschläge gibt.
So langsam bekomme ich gefallen an Python. :)
Benutzeravatar
Dill
User
Beiträge: 470
Registriert: Mittwoch 10. Januar 2007, 14:52
Wohnort: Köln

wenn du die antworten zu deinem letzen posting gelesen hättest wüsstests du's... :o
http://www.kinderpornos.info
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Noch ein paar Anmerkungen:

- Variablennamen solltest du klein schreiben, dass gilt auch für Parameter (siehe PEP8)
- die Importe sollten am Anfang des Programms stehen: das ist übersichtlicher und sie werden nicht bei jedem Funktionsaufruf ausgeführt
- die while-Schleife sollte durch eine for-Schleife ersetzt werden
- das Ziehen der Quadratwurzel ist hier überflüssig ;-)
- "# implementiert von math pi " hast du falsch verstanden: pi wird aus dem Modul math importiert
- __main__ ist übrigens keine Funktion ;-)
- Kommentare sollten über den betreffenden Zeilen stehen und nicht hinter
- und noch ein Tipp:

Code: Alles auswählen

for x in (10**i for i in range(6)):
     print x
Das Leben ist wie ein Tennisball.
Benutzeravatar
Dill
User
Beiträge: 470
Registriert: Mittwoch 10. Januar 2007, 14:52
Wohnort: Köln

das meiste davon hatten wir schon in seinem anderen thread.
http://www.kinderpornos.info
BlackJack

Ist'n bisschen "wortreich" die `montecarlo()`-Funktion.

Code: Alles auswählen

def montecarlo(n):
    return 4.0 * sum((random()**2 + random()**2) < 1 for _ in xrange(n)) / n
Mit einem ordentlichen DocString würde ich das als lesbare Implementierung durchgehen lassen.
Sconine
User
Beiträge: 49
Registriert: Montag 1. Juni 2009, 11:00

Ich habe versucht die Tipps zu übernehmen.
Jetzt habe ich glaub ich alles kaputt gemacht.

Code: Alles auswählen

from random import random

from math import pi

def montecarlo(n):

    wuerfe, treffer = 0, 0

    #while wuerfe < n:
    for wuerfe in range (n):

        x, y = random (), random()

        if (x**2 + y**2)++0.5 < 1:

            treffer += 1

            wuerfe +=1

        return 4.*treffer/wuerfe

if __name__ == '__main__':

    #for n in [1,10,100,1000,10000,100000,1000000]:

    
    for x in (10**i for x in range(6)):
          print x
       
       #abweichung = abs(montecarlo(N)-pi) 
       # print "Nach %d Wuerfen betrug die Abweichung zu pi: %f" %(n,abweichung)
 

Ich bin schon wieder am verzweifeln... :cry:
Sconine
User
Beiträge: 49
Registriert: Montag 1. Juni 2009, 11:00

Wws habe ich denn an den Tipps falsch übernommen???
BlackJack

Schau Dir Dein Programm noch einmal ganz aufmerksam, Zeile für Zeile an.

Interessant ist, dass Du einen Fehler in eine Zeile eingebaut hast, die eigentlich unverändert aus Deinem ersten Beitrag stammen müsste. Da war's nämlich richtig. Wobei die Operation, wie schon angemerkt wurde, beim Einheitskreis überflüssig ist.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Code: Alles auswählen

def montecarlo(n):
    treffer = 0

    for wuerfe in range(n):
        x, y = random (), random()
        if (x**2 + y**2) < 1:
            treffer += 1

    return 4.*treffer/n
- aus deinem ++ ein ** gemacht, wie gesagt kannst du das **0.5 auch weglassen
- dein return war falsch eingerückt und hat nach dem ersten Durchlauf die Schleife schon abgebrochen
- "wuerfe" brauchst du nicht extra berechnen, das entspricht n
Das Leben ist wie ein Tennisball.
Sconine
User
Beiträge: 49
Registriert: Montag 1. Juni 2009, 11:00

Es ist zum Mäusemelken. Das Einrücken hat mir ja schon immer Probleme gemacht (wie ihr ja unschwer erkennen konntet), aber jetzt bin ich kurz vor dem Aufgeben bei dieser Aufgabe.

Code: Alles auswählen

from random import random

from math import pi

def montecarlo(n): 
    treffer = 0 

    for wuerfe in range(n): 
        x, y = random(), random() 
        if (x**2 + y**2) < 1: 
            treffer += 1 

    return 4.*treffer/n



if __name__ == '__main__':

    #for n in [1,10,100,1000,10000,100000,1000000]:

    for x in (10**i for i in range(6)):
        print x
    
    abweichung = abs(montecarlo(n)-pi)
    print "Nach %d Wuerfen betraegt die Abweichung zu pi: %f" %(n,abweichung)

Code: Alles auswählen

1
10
100
1000
10000
100000
Traceback (most recent call last):
  File "C:\Python25\Aufgabenzettel_9\MonteCarlo.ich.py", line 24, in <module>
    abweichung = abs(montecarlo(n)-pi)
NameError: name 'n' is not defined
Das kann doch nicht wahr sein? Wo habe ich denn diesmal eine Zeile falsch eingerückt???
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Wo soll n denn auch herkommen? Du willst die Abweichung außerdem in der Schleife bestimmen, warum steht der Aufruf dann danach?

Code: Alles auswählen

if __name__ == '__main__':
    for n in (10**i for i in range(6)):
        abweichung = abs(montecarlo(n)-pi)
        print "Nach %d Wuerfen betraegt die Abweichung zu pi: %f" %(n,abweichung)
Das Leben ist wie ein Tennisball.
losgehts
User
Beiträge: 19
Registriert: Montag 8. Juni 2009, 01:00

Hallo allerseits,

das ist mein erster Post (bin noch absoluter Frischling und komme gerade erst mit der Schlange in Berührung), habt also Nachsicht: falls ich ausversehen gegen irgendwelche Forenregeln verstoße, ist das nicht meine Absicht.

Zum Code selbst kann ich natürlich nichts beisteuern, aber ich bin der Meinung, dass die ganze Kreisfläche mit einbezogen werden sollte:

also als Prüfung statt:

Code: Alles auswählen

if x**2 + y**2 < 1:
ein KleinerGleich:

Code: Alles auswählen

if x**2 + y**2 <= 1:
Naja, klar dass das den Kuchen nicht fett macht, ist meiner Ansicht nach aber plausibler :roll: .

Oder habe ich da etwas falsch verstanden?

Grüße, Ulrich
Antworten