Zufallskoordinaten innerhalb eines Kreises generieren
-
Hallo!
Ich muss zufällige Punkte innerhalb eines Kreises mit Zentrum (0,0) und Radius R generieren. Ich benutze den Zufallszahlgenerator MT:class MTRand { /*...*/ public: // Access to 32-bit random numbers double rand(); // real number in [0,1] double rand( const double& n ); // real number in [0,n] double randExc(); // real number in [0,1) double randExc( const double& n ); // real number in [0,n) double randDblExc(); // real number in (0,1) double randDblExc( const double& n ); // real number in (0,n) uint32 randInt(); // integer in [0,2^32-1] uint32 randInt( const uint32& n ); // integer in [0,n] for n < 2^32 double operator()() { return rand(); } // same as rand() // Access to 53-bit random numbers (capacity of IEEE double precision) double rand53(); // real number in [0,1) /*...*/ };
Mein Beispielcode ist:
MTRand r(123); r.seed(); /*...*/ short nx = r.randInt(R)*cos(r.rand(3.14)); short ny = r.randInt(R)*sin(r.rand(6.28));
Ist das Generieren korrekt? Ich habe bemerkt, dass cos alle seine Werte innerhalb [0, π] bekommt. Sin aber - [-π, +π]. Deshalb habe ich direkt 2pi geschrieben. Ist das OK?
-
Vielleicht solltest Du erklären, wie Du deine Zufallskoordinaten in deinem Kreis verteilt haben möchtest ... aber allgemein ist dein aktuelles Vorgehen falsch. Nehme an, beide randint(R) geben R zurück und sowohl sin als auch cos=1, dann bist Du außerhalb des Kreises ...
Was Du jetzt hier im wesentlichen machst (oder vermutlich machen willst, dein Vorgehen ist nicht richtig): Du würfelst einmal einen Winkel phi aus [0, 2pi) und einen Radius r aus [0, R]. Dann ist x=r*cos(phi), y=r*sin(phi). Damit kommen jedenfalls immer Werte im Kreis raus. Aber wenn deine beiden Zufallsgeneratoren gleichverteilt sind, dann werden alle Winkel gleich oft erwischt, aber es werden eben auch alle Radien gleich oft erwischt und das ist evtl. ein Problem. Wenn Du dir vorstellst, daß du für jeden Treffer in deinem Kreis den Punkt dunkel markierst, dann wirst Du feststellen, daß die schwarzen Punkte im Zentrum des Kreises viel näher beieinander liegen, als die schwarzen Punkte weiter aussen. Die Trefferdichte unterschiedet sich also. Da du nichts über deine Anforderungen gesagt hast, weiß ich natürlich auch nicht, ob das das ist, was Du willst.
-
Gleichverteilt müssen die Koordinaten nicht unbedingt sein. Wichtig ist es, dass sie innerhalb des Kreises liegen. Natürlich ist es empfehlenswert die Dichte möglichst distributiv auf der ganzen Kreisfläche zu machen. Wie mache ich das?
Ich habe schon das Algorithmus verbessert:short nx = static_cast<short>(r.randDblExc()*R*cos(r.randDblExc(3.14))); short ny = static_cast<short>(r.randDblExc()*R*sin(r.rand(6.28)));
Zusätzlich sichert r.randDblExc(3.14)), dass Winkeln zwischen (0, pi) rauskommen, also +/-1 als Ausgabe ist nicht möglich. r.randDblExc()*R sichert, dass die Koordinaten nie auf der Kreislinie liegen.
Ich hoffe, so ist es richtiger?
sin, cos - diese kommen aus math.h, also standard C!
-
Zdravko schrieb:
Gleichverteilt müssen die Koordinaten nicht unbedingt sein. Wichtig ist es, dass sie innerhalb des Kreises liegen. Natürlich ist es empfehlenswert die Dichte möglichst distributiv auf der ganzen Kreisfläche zu machen. Wie mache ich das?
In dem Du öfter 'weiter aussen' triffst, also hier am einfachsten, indem Du einen Zufallsgenerator verwendest, der x^2 gleichverteilt und nicht x. Gibt es bestimmt Bibliotheken für.
Ich habe schon das Algorithmus verbessert:
short nx = static_cast<short>(r.randDblExc()*R*cos(r.randDblExc(3.14))); short ny = static_cast<short>(r.randDblExc()*R*sin(r.rand(6.28)));
Zusätzlich sichert r.randDblExc(3.14)), dass Winkeln zwischen (0, pi) rauskommen, also +/-1 als Ausgabe ist nicht möglich. r.randDblExc()*R sichert, dass die Koordinaten nie auf der Kreislinie liegen.
Ich hoffe, so ist es richtiger?Es leidet immer noch am gleichen Problem, nämlich daß Du die x-Koordinate unabhängig von der y-Koordinate auswürfelst. Da jede Koordinate den Wert R erreichen kann, können auch Punkte ausserhalb des Kreises getroffen werden.
Pseudo-mäßig:
double phi = rand(2*PI); double r = rand(R); double x = r*cos(phi), y = r*sin(phi);
-
Ich poste die ganze Code, damit es klarer wird, was ich mache.
Ich will 500 Punkten generieren, die innerhalb des Kreises mit Zentrum (0,0) und Radius R = 200 liegen. Zusätzlich muss zu jedem Punkt noch einen Punkt generiert werden, der im Kreis des ersten Punktes liegt. Dies bedeutet, dass der zweite Punkt nicht unbedingt im ersten Kreis liegt.const int R = 200; of << "short NI[2000]={" << endl; for(int i = 0; i < 500; ++i) { short nx = static_cast<short>(r.randDblExc(R)*cos(r.randDblExc(3.14))); short ny = static_cast<short>(r.randDblExc(R)*sin(r.rand(6.28))); of << "\t" << nx << ", " << ny << ", "; short nx1 = nx + static_cast<short>(r.randDblExc(R)*cos(r.randDblExc(3.14))); short ny1 = ny + static_cast<short>(r.randDblExc(R)*sin(r.rand(6.28))); of << nx1 << ", " << ny1; if(i != 499) of << ","; of << endl; } of << "};" << endl << endl;
Und eine Ausgabe (jede Zeile ist ein Paar aus Punkten - die ersten zwei Zahlen sind X, Y des ersten Punktes, die letzten zwei Zahlen sind X, Y des zweiten Punktes). Vielleicht kann jemand das irgendwie graphisch veranschaulichen.
short NI[2000]={
/*zu lange zu lesen SELBST KORREKTUR*/
};
-
Daniel E. schrieb:
Zdravko schrieb:
Gleichverteilt müssen die Koordinaten nicht unbedingt sein. Wichtig ist es, dass sie innerhalb des Kreises liegen. Natürlich ist es empfehlenswert die Dichte möglichst distributiv auf der ganzen Kreisfläche zu machen. Wie mache ich das?
In dem Du öfter 'weiter aussen' triffst, also hier am einfachsten, indem Du einen Zufallsgenerator verwendest, der x^2 gleichverteilt und nicht x. Gibt es bestimmt Bibliotheken für.
Ich habe schon das Algorithmus verbessert:
short nx = static_cast<short>(r.randDblExc()*R*cos(r.randDblExc(3.14))); short ny = static_cast<short>(r.randDblExc()*R*sin(r.rand(6.28)));
Zusätzlich sichert r.randDblExc(3.14)), dass Winkeln zwischen (0, pi) rauskommen, also +/-1 als Ausgabe ist nicht möglich. r.randDblExc()*R sichert, dass die Koordinaten nie auf der Kreislinie liegen.
Ich hoffe, so ist es richtiger?Es leidet immer noch am gleichen Problem, nämlich daß Du die x-Koordinate unabhängig von der y-Koordinate auswürfelst. Da jede Koordinate den Wert R erreichen kann, können auch Punkte ausserhalb des Kreises getroffen werden.
Pseudo-mäßig:
double phi = rand(2*PI); double r = rand(R); double x = r*cos(phi), y = r*sin(phi);
Danke, das habe ich gerade implementiert:
const int R = 200; of << "short NI[2000]={" << endl; for(int i = 0; i < 500; ++i) { double phi = r.rand(6.28); double radius = r.randDblExc(R); short nx = static_cast<short>(radius*cos(phi)); short ny = static_cast<short>(radius*sin(phi)); of << "\t" << nx << ", " << ny << ", "; phi = r.rand(6.28); radius = r.randDblExc(R); short nx1 = nx + static_cast<short>(radius*cos(phi)); short ny1 = ny + static_cast<short>(radius*sin(phi)); of << nx1 << ", " << ny1; if(i != 499) of << ","; of << endl; } of << "};" << endl << endl;
Ich hoffe, so ist es richtig?