Fractal Flame

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.

Fractal Flame
Hey,

also ich habe jetzt alles implementiert und so, soweit scheint auch alles zu passen bei den Filtern, allerdings ähneln meine Fraktals denen auf dem PDF nur stark, sind aber nicht gleich… Als Beispiel mal 1.000.000 Iterationen mit 4 Threads:

Jemand ne Idee woran das liegen könnte? Ich meine da sollten doch theoretisch genau die gleichen Bilder rauskommen oder nicht? Oder wird das Bild zum dem auf der PDF wenn ich die vorher geschriebenen Filter drüberlaufen lasse? Das erscheint mir unwahrscheinlich.

Und dann habe ich da noch eine Frage: Wenn ich mittels des Pseudocodes ein Fraktal berechne was mache ich dann mit dem maxFrequency? Muss ich das auch berechnen in meiner generateFractalFlame Methode?


also meine Flamme sieht aus wie deine, aber nicht so wie die auf dem Angaben PDF


Hat irgendjemand eine Idee, warum meine Implementierung nicht skaliert? :confused: Im Gegenteil, sie wird sogar immer schlechter je mehr threads man nimmt…

Ist der gemeinsame (Lese-)Zugriff auf statische Variablen teuer?


Wenn die Variable volatile bzw iein Atomic* ist dann ja, weil die Daten dann nicht gecached werden. Wenn es ne ganz normale Variable ist und du auch nicht mit synchronized um dich wirfst dann eigentlich nicht (zumindest nicht teurer als sonst).

Ansonsten sollte man so über den Daumen gepeilt nicht mehr als 2*AnzahlKerne Threads laufen lassen darüber wird der Verwaltungsaufwand größer als die Performance, wobei das natürlich vom Problem abhängig ist. Konkret bei den Fractalen kann ich mir vorstellen, dass das ausgeben auf dem Bildschirm der Flaschenhals ist und mit steigender Threadanzahl sich das ganze verschlimmert.


Ok, danke für die Antwort.

Ich bin einfach ein bisschen dumm, weißt du? ^^ Es soll ja gar nciht skalieren, denn man zeichnet ja mit 4 Threads 4 Fraktale und mit einem nur eines…

Trotzdem danke dass du dir mühe gegeben hast ^^


@NCK

Ich hatte bei meiner implementierung das gleiche bild wie du, das ist aber glaube ich falsch.

Habe es jetzt verbessert und jetzt sieht meine FractalFlame aus wie auf dem Aufgabenblatt.

Mein Fehler (falls du den gleichen hast):

Ich habe beim berechnen von (x,y) ← (Fj.a*x…)
erst x und dann y von (x,y) berechnet.
dabei habe ich aber zwischenzeitlich mein x verändert und mit dem veränderten x das y ausgerechnet, das ist aber falsch.

Nachdem ich das angepasst hatte sah mein Bild dann richtig aus

Attachment:
FractFlame.jpg: https://fsi.cs.fau.de/unb-attachments/post_132546/FractFlame.jpg

1 Like

Kann mir das jmd erklären?:

Folgende Zeilen in meinem Parallelem Postfilter:

System.out.println("Par: redTmp[0][0]: " + redTmp[0][0]);
System.out.println("Par: redTmp[1][1]: " + redTmp[1][1]);
return new FractalResult(frequencyAvgTmp, redTmp, blueTmp, greenTmp, frequencyAvgMax, result.width / cellSize, result.height / cellSize);

Ausgabe in der Konsole:
[m]Par: redTmp[0][0]: NaN
Par: redTmp[1][1]: NaN[/m]

Wenn ich im Testcase

assertEquals(flames[1].red[i][j], flames[0].red[i][j],EPSILON);
ausführe, schlägt er fehl mit:
[m]java.lang.AssertionError: expected: but was:<0.0>[/m]

Warum/wo/warum wird mein NaN zu 0.0 gemacht?!

In Flames[0] steht das Ergebnis vom parallelem Postfilter,
in Flames[1] das Ergebnis vom sequentiellen Postfilter.


Da das Array mit 0 vorinitialisiert ist, wuerde ich drauf tippen, dass du NaN nicht mit 0 ueberschreibst, sondern dass bei der Synchronisation irgendwas schief laeuft. Hast du vllt ein join() vergessen?


gelöscht


Der Satz macht nicht so ganz Sinn :smiley:
Aber redTmp ist ein double array. Also sollte per default 0.0 drinnen stehen.

[quote]sondern dass bei der Synchronisation irgendwas schief laeuft. Hast du vllt ein join() vergessen?
[/quote]
Mein Algorithmus ist momentan, dass jeder Thread einen Block cellSize x cellSize nimmt und diesen supersampelt.
Sprich „Datenparallele vorgehenseweise, geometrische Dekomposition“.
Da sollten ja per Definition keine Nebenläufigkeitsprobleme entsthen, da jeder Thread seine eigenen unabhängigen Daten hat.

Und ich hab eine Schleife mit .join() vor dem return-Statement, sollte soweit passen, oder?

EDIT:
Das wird immer dubioser…
Ich hab nun in den Testcase mit einem Print erweitert:

	for (int i = 0; i < width / 3; i++) {
				for (int j = 0; j < height / 3; j++) {
//					assertEquals(flames[1].frequency[i][j],
//							flames[0].frequency[i][j], EPSILON);
					if (flames[1].red[i][j]!= flames[0].red[i][j]){
						System.out.println("ungleich bei i=" + i + ", j=" + j + ", Werte: f1=" + flames[1].red[i][j]+ ", f0="+ flames[0].red[i][j]);
					}
					assertEquals(flames[1].red[i][j], flames[0].red[i][j],
							EPSILON);
//					assertEquals(flames[1].blue[i][j], flames[0].blue[i][j],
//							EPSILON);
//					assertEquals(flames[1].green[i][j], flames[0].green[i][j],
//							EPSILON);
				}
			}

Ausgabe (nur die letzten beiden Zeilen, meine ganze Konsole wird vollgeschrieben)
[m]
ungleich bei i=199, j=198, Werte: f1=NaN, f0=NaN
ungleich bei i=199, j=199, Werte: f1=NaN, f0=0.0[/m]

  • Warum geht der denn in die Ausgabe bei i=199, j=198 ? Ist doch gleich :open_mouth:
  • Kann man mir mal erklären, was der Samplingfilter tun soll? Der soll doch in eine cellSize x cellSize Feld den Durchschnittswert berechnen, und dann in ein kleineres Array an die entsprechende Position schreiben. Warum kommt da überhaupt NaN raus?

Die Java Language Specification zu deinem Problem im Abschnitt 4.2.3

Damit ist es nicht verwunderlich, dass dein Vergleich zweier NaN-Werte false zurück liefert. Egtl. sollte das aber wirklich nicht passieren. Hast du sicher gestellt, dass das Test-Bild, welches konvertiert werden soll auch geladen werden kann?


Danke für den Tipp, dass man nicht NaN vergleichen kann -.-

Das Testbild benötige ich noch nicht, der SampleFilter arbeitet auf zufälligen Farbwerten, die im TestCase in getRandomFlames() erstellt werden.
Und wenn ein fehler mit dem Laden des Testbildes wäre, müsste da nicht sowieso eine Exception bemerkbar machen?

Noch weitere Tipps? :>


@ [hedgehogs dilemma = 42]

vielen Dank! :smiley: auf dieses Problem wäre ich ja in hundert Jahren nicht gekommen, hab genau den selben Fehler


Ich glaube die Ursache für mein Problem gefunden zu haben, weiß aber nicht wie ich es beheben kann.

double alpha = 1.0;
if (gamma > 1) {
	alpha = Math.log(frequencyAvg)	/ Math.log(result.frequencyMax);
	alpha = Math.pow(alpha, 1 / gamma);
}
float redFinal = (float) (redAvg * alpha);

[m]gamma[/m] wird im Testcase auf 100 gesetzt, d.h. die if-Abfrage ist true
[m]alpha[/m] wird nun in Z.3 nun negativ: -0.009…. Ich glaube das ist ein numerisches Problem, da [m]result.frequencyMax[/m] eine sehr winzige Zahl ist: 4.9E-324
[m]alpha[/m] wird dann in Z.4 zu [m]NaN[/m], da eine Wurzel aus einer negativer Zahl gezogen wird: -0.009^(1/100)
und redFinal wird dann abschlißend auch zu NaN, da scheinbar Zahl * NaN = NaN ergibt.

Nun weiß ich aber nicht, woran das liegt, v.a. da bei anderen Leuten die Testcases ja zu laufen scheinen… Ich vermute [m]frequencyMax[/m] ist das Problem. Hört sich auch nicht wirklich nach einem Maximalwert an :smiley:
Auch habe ich zur Sicherheit nochmal den Code für den sequentiellen PostFilter neu heruntergeladen, um auszuschließen, dass ich etwas ausversehen geändert habe.

Kann mir mal jemand seine Werte für die Variablen aus obigen Abschnitt schreiben?

EDIT:
Das Probem besteht scheinbar nur bei [m]public void postFilterThreads()[/m],
da [m]public void postFilterFourThreads()[/m] der vermeintlich schwerere Fall ohne Problem durchläuft. Das ist nun extrem komisch :nuts:

Er läuft durch, weil wieder überall NaN steht … FFFFFFFFFFUUUUUUUUUUUUUUUUUUUU


Uh, ja da war ein Fehler in der Testmethode :blush:. Ist jetzt behoben.


stehe gerade auf dem schlauch wie die convertierung von x und y zu indexen funktionieren soll,
hab mal das versucht, denke aber mal das war nicht gemeint:

int xc = (int) ((x+1)*width/2);
int yc = (int) ((1-y)*height/2);

mir ist auch noch nicht ganz klar wie bei dem algorithmus vom aufgabenblatt das erste res erstellt werden soll,
einfach ein FractalResult komplett schwarz erstellen?


Muss gleich weg, aber wenn mich nicht alles täuscht wäre das:

int xc = (int) ((x+1)*width/2.0);
int yc = (int) ((y*-1+1)*height/2.0);

Wenn du damit meinst, welche Farbwerte initial für jedes Pixel gesetzt werden sollen, dann ja, alles schwarz (bzw. (0; 0; 0)).


Kann mir jemand sagen wofür ich das frequencyMax benötige?

Und was genau ist mit dem Hinweis

gemeint?