6.6: Monte-Carlo-Integration

Disclaimer: Dieser Thread wurde aus dem alten Forum importiert. Daher werden eventuell nicht alle Formatierungen richtig angezeigt. Der ursprüngliche Thread beginnt im zweiten Post dieses Threads.

6.6: Monte-Carlo-Integration
Hallo miteinander,

und zwar scheiter ich leider schon an der wikipedia ( http://de.wikipedia.org/wiki/Monte-Carlo-Algorithmus) beschreibung und der ganzen umsetzung der Methode “computeIntegral”.

Also Integral-rechnung kenne ich,
die vorlesungsfolien habe ich mir auch angeschaut,

Die fragen sind nun:

ich nehme an ich muss die auf Wikipedia beschriebene Funktion Sm(f) implementieren und m ist in dem fall mein “iterations” oder?
wenn das bis dahin so stimmt, dann setze ich ja in f(x) meine i-Werte ein die hochgezählt werden bis i<=m oder? Denn jetzt frage ich mich wann und wo setze ich die grenzen a und b vom integral ein? normalerweise ist ja die integralrechnung f(obereGrenze)-f(untereGrenze).

und was hat es mit meinem minY und maxY auf sich? wahrscheinlich ob mein berechneter wert in diesem bereich liegt?!
In folie 6-33 wurde ja “count” hochgezählt wenn der wert im Einheitskreis war… sollte hier auch dann eine selbstangelegte Variable hochgezählt werden oder wie soll ich Wikipedia+Vorlesungsfolie miteinander kombinieren dass es klappt? :scared:


Ich denke, die Übungsfolien dazu seien ziemlich hilfreich. Du integrierst eine Funktion von a nach b, also berechnest du die Fläche, die die Funktion einschließt. Die Funktion ist auf dem Intervall [a, b] beschränkt durch den maximalen und den minimalen Funktionswert. Somit ist ihre Fläche nicht größer als |b-a|*|max-min|. Analog zum Kreisbeispiel aus der Vorlesung kannst du irgendwelche zufälligen Punkte mit den Koordinaten x aus [a, b] und y aus [min, max] wählen. Dann kannst du schauen, ob dieser Punkt innerhalb deiner Funktion liegt oder nicht. Die Anzahl der Punkte innerhalb der Funktion geteilt durch die Anzahl aller Punkte konvergiert dann für große Anzahlen der Punkte gegen die Fläche. Ansonsten muss man noch beim Vorzeichen aufpassen, aber das erklären dir die Folien besser.


Du kannst auch die Variante der Vorlesung nehmen, dann müsst du dich aber um die Verschiebung in y-Richtung kümmern (siehe Übungsfolien).
Wenn du die aus der Wikipedia nimmst, musst du tatsächlich Sm(f) implementieren. m entspricht dann den iterations ;).

In Wikipedia steht du brauchst eine Menge K um deine Punkte zu bestimmen. In der Übungsaufgabe ist K die Menge
an Punkten (x,y) wobei x im Intervall [a,b] und y im Intervall [minY, maxY] liegt.

Die x-Werte von Sm(f) sind Zufallswerte im Intervall [a,b], damit hast du automatisch die Grenzen berücksichtigt.

minY und maxY brauchst du nur in der Vorlesungsvariante.

edit: Hier stand vorher Schwachsinn: Sm(f) benötigt die Fläche von K ;).

Wenn du die Wikipedia-Variante nimmst, brauchst du kein count.


Also ich habe jetzt die Wikipedia-variante sm(f) implementiert,
das Volumen von K habe ich auch berrechnet mit jeweil den betrag von (a-b) und (minY-maxY)

y-werte berechnet mir ja die Funktion und x-werte muss ich selber „zufällig“ aus dem Wertebereich [a, b] bestimmen und in f(x) einsetzen.

ich habe versucht die x-werte zufällig zu berechnen indem ich Random.nextDouble() nutze und die zahl erhöhe mit 1 bis ich im intervall [a,b] bin, ist wahrscheinlich nicht das geschickteste, aber spontan fiel mir keine andere Methode ein um es noch zufälliger zu berechnen.

Jetzt habe ich 6 von 12 Testcases richtig mit meiner implementierung jeweils komischerweise die ersten 3… also testIntegral bis testIntegral2 und testIntegralOneThread1 bis testIntegralOneThread3.

Die Frage nun ist, was habe ich vermutlich verbockt bei meiner implementierung der „computeIntegral“?
bzw. wie kann das sein das jeweils die ersten 3 richtig sind bei mir und die letzen 3 falsch? <_<


Ohne das jetzt sicher sagen zu können, aber mein Verdacht liegt bei der Berechnung deines Volumens von K. Die Wikipedia deutet da auf ein Volumen hin, das bei mehrdimensionaler Integration wichtig wird. Wir integrieren jedoch nur über die x-Dimension. Insofern solltest du die Berechnung deines Volumens nochmal überdenken.


Ja stimmt, da hab ich Schwachsinn erzählt :blush:.


Ja klasse jetzt funktioniert meine Implementierung schon mal! Danke für die hilfe! :smiley:

…weitere fragen werden wahrscheinlich noch auftauchen, hoffe aber nicht :rolleyes:


Ich habe ein anderes Problem, das Atomic macht mir Probleme.

System.out.println("myIntegral: " + myIntegral);
res.addAndGet((long) myIntegral);
System.out.println("res: " + res);

Die beiden prints geben mir Folgendes:

myIntegral: 0.7834280828975083
res: 0

Das schreiben in res geht scheinbar schief. addAndGet() wird auch in den Vorlesungsfolien verwendet. Warum wird mein Ergebnis aber nicht in res geschrieben?

Es ist in computeIntegral() als AtomicLong res = new AtomicLong(0); definiert. Übergeben tu ich es dann als Parameter an den Konsturuktor in meinem Runnable.

Hab mich sehr stark an die Vorlesungsfolien gehalten :open_mouth:


Hat jemand vielleicht Vergleichswerte für die Laufzeiten der Testfälle? :slight_smile:

testIntegralOneThread(3,5s)
testIntegralOneThread2(3,6s)
testIntegralOneThread3(3,75s)
testIntegralOneThread4(3,5s)
testIntegralOneThread5(11,5s)
testIntegralOneThread6(11,5s)

testIntegral(1,5s)
testIntegral2(0,9s)
testIntegral3(0,7s)
testIntegral4(0,9s)
testIntegral5(1,9s)
testIntegral6(1,8s)

Habe ich immer so in etwa.


Da geht nichts schief:
m myIntegral = (long) 0.783… = 0[/m] ;).

[m]long[/m] ist in diesem Fall möglicherweise ungeeignet, wenn du darin Funktionswerte speichern möchtest. Ich kann mir aber vorstellen, dasss diese Lösung ziemlich langsam wird, wenn jeder Thread in jeder Iteration den Zugriff auf die Variable synchronisieren muss. Schneller wird es vmtl., wenn zumindest jeder Thread für sich entsprechende Zwischenwerte alle Funktionswerte berechnet und diese dann nur am Ende synchronisiert.


Ich habe folgende Laufzeiten, die mir vor allem bei den letzten 6 Tests komisch vorkommen …

testIntegralOneThread(4,1s)
testIntegralOneThread2(3,9s)
testIntegralOneThread3(4,0s)
testIntegralOneThread4(4,0s)
testIntegralOneThread5(10,5s)
testIntegralOneThread6(22,9s)

testIntegral(35s)
testIntegral2(34s)
testIntegral3(34s)
testIntegral4(34s)
testIntegral5(33s)
testIntegral6(33s)

An meinem PC sollte es mit hoher Wahrscheinlichkeit nicht liegen. In der jeweiligen Berechnung, die ein Thread durchfuehrt, synchronisiere ich nichts. Das mache ich erst danach. Habt ihr eine Idee, wodurch diese langen Laufzeiten entstehen koennten?


Ein long ist die erweiterte Form eines int.

Edit:

Ja - es war zml langsam. Bei der Version mit AtomicLong hat’s ~40s gedauert.

Jetzt hab ich es mit einem normalen Double, dass synchronized ist versucht - es dauert nun 20sec … also immer noch langsam und es funzt immer noch net^^

Allerdings versteh ich deine Aussage mit „langsam weil synchronized“ nicht. Ich hab eine for()-Schleife in der ich alle Iterationen ausführe, und nach der for()-schleife wird einmalig (pro Thread) synchronized in res geschrieben.

Edit2:

Alles klar - mit der globalen Variable und einem synchronized Schreibzugriff funzt’s nun :slight_smile:
Hier sind meine Zeiten:


testIntegralOneThread(7,2s) <- die sind alle langsamer als Cybergy
testIntegralOneThread2(7,0s) // erklaer ich mir in dem Fall, damit dass mein Recher Asbach Uralt ist...
testIntegralOneThread3(7,7s)
testIntegralOneThread4(7,1s)
testIntegralOneThread5(20,6s)
testIntegralOneThread6(21,0s) // Interessant auch, dass der bei Cybergy doppelt so lange dauert, als Thread5

testIntegral(2,4s) <- die sind alle (bedeutend) schneller als Cybergy
testIntegral2(2,36s) // kann ich mir nicht erklären
testIntegral3(2,4s)
testIntegral4(2,5s)
testIntegral5(6,7s)
testIntegral6(6,6s)

Edit 3:

Achja - und warum gibt’s kein AtomicDouble oder AtomicFloat?


Das ist zumindest ne Lösung. Frag doch bei Java nicht nach dem warum…


Wie erzeugst du deine Zufallszahlen? Möglicherweise wird nämlich doch synchronisiert, aber in einer Methode, die du aufrufst.


Ich benutze [m]Math.random()[/m].


Benutz besser ein eigenes Random Object.


hint ThreadLocalRandom (Java Platform SE 7 )


Stimmt wäre noch besser :-D.


Danke, mit [m]ThreadLocalRandom[/m] gehts jetzt richtig schnell:

[code]testIntegralOneThread(1,6s)
testIntegralOneThread2(1,7s)
testIntegralOneThread3(1,8s)
testIntegralOneThread4(1,7s)
testIntegralOneThread5(7,7s)
testIntegralOneThread6(7,8s)

testIntegral(0,4s)
testIntegral2(0,5s)
testIntegral3(0,5s)
testIntegral4(0,5s)
testIntegral5(2,3s)
testIntegral6(2,2s)[/code]

1 Like