PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Java: Gauss-Verteilung


Kinehs
2005-08-16, 00:25:13
Hallo zusammen!

Programmiere gerade einige einfache Beispiele, um mal mit Java vertraut zu werden. Diesmal wollte ich eine Gauss-Verteilung in einem Applet.


import java.awt.*;
import java.applet.*;
import java.util.*;

public class HistoApplet extends Applet
{
/** Variablen definieren*/
final int MAXVERSUCHE = 50000;
final int MAXBALKEN = 30;
final double BEREICHMIN = -3.0;
final double BEREICHMAX = +3.0;
int balken = 0;
int maximum = 0;
/** Ende Variablendefinition*/
double ErgFeld[] = new double[MAXBALKEN]; // Array definieren


public void paint(Graphics g)
{
//for(int i=0; i<MAXBALKEN; i++) ErgFeld[i] = 0; // Feld auf 0

Rectangle rClient = g.getClipBounds();
int width = rClient.width;
int height= rClient.height;
double x;

Random r = new Random();


for(int i=0; i<MAXVERSUCHE; i++) //Zufallszahlen ziehen und Bereich zuordnen
{
x = r.nextGaussian(); //ziehe Zufallszahl
balken = (int)((x- BEREICHMIN)/((BEREICHMAX-BEREICHMIN)/MAXBALKEN)); //Welcher Balkenbereich im Array wird angesprochen?
if (balken<0) balken=0; // Absicherung < 0
if (balken>(MAXBALKEN-1)) balken=(MAXBALKEN-1); //Absicherung > Max
//System.out.println(balken);
ErgFeld[balken]+=1; //Entsprechender Balken wird im Wert um 1 erhöht
}

for(int i=0; i<MAXBALKEN; i++) //Relativwerte
{
ErgFeld[i] = ErgFeld[i]/MAXVERSUCHE;
}


for(int i=1; i<MAXBALKEN; i++) //Maximum bestimmen
{
if (ErgFeld[i]>ErgFeld[maximum]) maximum = i;
}

for(int i=1; i<MAXBALKEN; i++) //Relativ zum Maximum
{
ErgFeld[i] = ErgFeld[i]/ErgFeld[maximum];
}

for(int i=0; i<MAXBALKEN; i++)
{
System.out.println("Array = " + i + " Wert = " + ErgFeld[i]);
}


g.setColor(Color.white);
g.fillRect(0, 0, rClient.width, rClient.height);


for(int i=0; i<MAXBALKEN; i++)
{ g.setColor(Color.darkGray);
g.fillRect(0, (i+1)*height/MAXBALKEN, (int)(ErgFeld[i]*width), 10);
}
}
}

Meine Arraywerte sind aber leider nicht ganz gaussverteilt, sondern seht selbst:

Array = 0 Wert = 0.002514004936009808
Array = 1 Wert = 0.026530409107645106
Array = 2 Wert = 0.046189013478636604
Array = 3 Wert = 0.07317249023441715
Array = 4 Wert = 0.11206200941339775
Array = 5 Wert = 0.16638139654190445
Array = 6 Wert = 0.23560209389658757
Array = 7 Wert = 0.3278795450385251
Array = 8 Wert = 0.4321132721002976
Array = 9 Wert = 0.5561314555420386
Array = 10 Wert = 0.6694271461945653
Array = 11 Wert = 0.7883103376935586
Array = 12 Wert = 0.8783480640819892
Array = 13 Wert = 0.9522252563985979
Array = 14 Wert = 0.9993202292593296
Array = 15 Wert = 1.0
Array = 16 Wert = 0.07614215191630454
Array = 17 Wert = 0.06992014172828172
Array = 18 Wert = 0.06244012517625027
Array = 19 Wert = 0.053592105916213335
Array = 20 Wert = 0.043286087568173294
Array = 21 Wert = 0.034780068028136886
Array = 22 Wert = 0.025854051768103854
Array = 23 Wert = 0.01870803801607568
Array = 24 Wert = 0.01290802648005209
Array = 25 Wert = 0.008824017264035967
Array = 26 Wert = 0.005688011324022208
Array = 27 Wert = 0.0036640071240135203
Array = 28 Wert = 0.002042004444008648
Array = 29 Wert = 0.002494005092010088


Also < 0 alles normal, >0 sieht es anders aus.

Komme aber nicht dahinter, wo was falsch gerundet (?) wird. :confused:

Gast
2005-08-16, 09:03:11
Hm...

Dein Gecaste auf int finde ich ein bißchen gewagt. Kann sein dass es gut geht, kann aber auch sein dass nicht... Verwende lieber Math.round(), um einen vernünftigen Wert zu kriegen! Dann musst du allerdings entweder long statt int oder float statt double verwenden, weil sonst passen die Datentypen nicht zusammen.


Und ich empfehle dir, die Verwaltung deiner Balken (wo ihre Grenzen sind, was für eine relative Höhe sie haben usw.) in eine eigene Klasse zu kapseln, und wenn es nur eine innere Klasse ist. Wenn du das ganze grafisch ausgibst, tust du dir auch leichter. Du kannst z.B. Methoden schreiben, die dir die Balkenhöhe in relativer oder absoluter Höhe ausgeben.
Und du solltest die grafische Darstellung von der internen Berechnung abgrenzen: mach EINE Methode, die dir die Zufallszahlen generiert und einsortiert, und mindestens eine weitere, um den ganzen Klumpatsch auszugeben. Ordnung ist das halbe Leben...


--- Monger

Gast
2005-08-16, 09:08:27
Nachtrag:

Mir fällt gerade auf - deine Gausskurve ist ja nichtmal mittig!

1.0 sollte doch bei einer echten Glockenkurve wirklich beim mittleren Wert liegen. Bei einem Array von 0 - 29 wäre das an der 14ten, und nicht an der 15ten Stelle.

Kinehs
2005-08-18, 22:36:52
So ich hab jetzt herausgefunden, woran es gelegen hat:

for(int i=1; i<MAXBALKEN; i++) //Relativ zum Maximum
{ ErgFeld[i] = ErgFeld[i]/ErgFeld[maximum];
}

Überprüft habe ich alles, er verwendet die richtigen Plätze im Array, welche nach der Gaussverteilung mit Häufigkeiten belegt sind.

Das Maximum wird auch richtig berechnet.... usw.....

Aber bei der Geschichte Double = Double/Double macht er Fehler ?!

Kann mir wer erklären, warum?

EDIT: Noch stranger:

Wenn ich eben oben genannten Block nicht ausführe (also als Kommentar deklarieren) und statt dessen bei der graphischen Ausgabe diese Teilung verwende, funktioniert es:

for(int i=0; i<MAXBALKEN; i++) {
g.setColor(Color.darkGray);
g.fillRect(0, (i+1)*height/MAXBALKEN, (int)(ErgFeld[i]/ErgFeld[maximum]*width), 10);

Pinoccio
2005-08-19, 12:25:37
Kinehs' Quelltext: for(int i=0; i<MAXVERSUCHE; i++) //Zufallszahlen ziehen und Bereich zuordnen
{
x = r.nextGaussian(); //ziehe Zufallszahl
balken = (int)((x- BEREICHMIN)/((BEREICHMAX-BEREICHMIN)/MAXBALKEN)); //Welcher Balkenbereich im Array wird angesprochen?
if (balken<0) balken=0; // Absicherung < 0
if (balken>(MAXBALKEN-1)) balken=(MAXBALKEN-1); //Absicherung > Max
//System.out.println(balken);
ErgFeld[balken]+=1; //Entsprechender Balken wird im Wert um 1 erhöht
}1) Ich würde die Absicherung zu MIN und MAX auf die Zufallszahl anwenden, indem einfach Werte <MIN bzw >MAX ignoriert werden. Ansonsten werden dien Randbalken zu groß (auch wenn daß hier wohl kaum auffällt.
2) Durch das (int) schneidest du die Nachkommastellen ab. Das ist ok, führt aber dazu, daß, wie in Antwort #3 bemerkt, deine Kurve nach rechts verschoben wird. Entweder du rechnest vorher noch +0,5 oder nimmst Math.round() (http://java.sun.com/j2se/1.5.0/docs/api/index.html?java/lang/Math.html#round(double)).

Warum deine Werte nun aber nicht stimme sehe ich auch nicht. Eventuell mal mit mehr Durchläufen testen? (Wobei eigentlich 50000 reichen sollten.)

hth, mfg Sebastian

Kinehs
2005-08-19, 14:42:08
(1) Da hast du recht, das wäre besser, bemerkt man hier aber nicht. Mir geht es nicht (mehr) darum, dass Programm noch weiter zu verbessern oder zu verändern. Es war ja nur als Übung gedacht. Ich verstehe halt den "Fehler" nicht, das macht mich ganz kribbelig. ;)

(2) Balken[0] ist von Wert -3.0 bis -2.8 usw. balken[15] von 0.0 bis +0.2. Also passt das als Maximum schon. ;)

Die Werte stimmen ja, sprich es kommen auch gaussverteilte Werte im Array raus, habe ich mir ja mal alles ausgeben lassen. Auch das Maximum wird richtig bestimmt.

Nur eben diese Schleife macht mir mein vorheriges korrekte Array kaputt (wie im Ursprungspost):

for(int i=1; i<MAXBALKEN; i++) //Relativ zum Maximum
{ ErgFeld[i] = ErgFeld[i]/ErgFeld[maximum]; }

Pinoccio
2005-08-19, 16:18:44
Hab den Fehler gefunden!
Das Problem ist folgendes:
// Relativ zum Maximum
for(int i=1; i<MAXBALKEN; i++) {
ErgFeld[i] = ErgFeld[i]/ErgFeld[maximum];
}
Du schrumpfst deinen Eintrag ErgFeld[maximum] auch, so daß davor berechnete Werte stimmen, aber danach berechnete mit dem neuen Wert von ErgFeld[maximum] berechnet werden - und das funktioniert natürlich nicht!
Änderung wie folgt:
double maximalWert = ErgFeld[maximum];
for (int i = 1; i < MAXBALKEN; i++) {
ErgFeld[i] = ErgFeld[i] / maximalWert;
}
Das funktioniert!

In der Hoffnung geholfen zu haben.
mfg Sebastian

Kinehs
2005-08-19, 18:03:21
Hab den Fehler gefunden!
Das Problem ist folgendes:
// Relativ zum Maximum
for(int i=1; i<MAXBALKEN; i++) {
ErgFeld[i] = ErgFeld[i]/ErgFeld[maximum];
}
Du schrumpfst deinen Eintrag ErgFeld[maximum] auch, so daß davor berechnete Werte stimmen, aber danach berechnete mit dem neuen Wert von ErgFeld[maximum] berechnet werden - und das funktioniert natürlich nicht!
Änderung wie folgt:
double maximalWert = ErgFeld[maximum];
for (int i = 1; i < MAXBALKEN; i++) {
ErgFeld[i] = ErgFeld[i] / maximalWert;
}
Das funktioniert!

In der Hoffnung geholfen zu haben.
mfg Sebastian

Jo danke! Schande über mich, natürlich! :eek: