CJam, 28 27 Bytes
PP+mr_mc\ms]1.mrmqf*"(,)".\
Diese Lösung basiert nicht auf Ablehnung. Ich generiere die Punkte in Polarkoordinaten, aber mit einer ungleichmäßigen Verteilung der Radien, um eine gleichmäßige Dichte der Punkte zu erreichen.
Teste es hier.
Erläuterung
PP+ e# Push 2π.
mr_ e# Get a random float between 0 and 2π, make a copy.
mc\ e# Take the cosine of one copy and swap with the other.
ms] e# Take the sine of the other copy and wrap them in an array.
e# This gives us a uniform point on the unit circle.
1.mr e# Get a random float between 0 and 1.
mq e# Take the square root. This is the random radius.
f* e# Multiply x and y by this radius.
"(,)".\ e# Put the resulting numbers in the required format.
Warum funktioniert es? Betrachten Sie einen engen Kreisring aus Radius r
und (kleiner) Breite dr
. Die Fläche ist ungefähr 2π*r*dr
(wenn der Kreisring eng ist, sind der innere und der äußere Umfang nahezu identisch, und die Krümmung kann ignoriert werden, so dass die Fläche wie die eines Rechtecks mit Seitenlängen des Umfangs und der Breite des Kreisrings behandelt werden kann) Annulus). Die Fläche wächst also linear mit dem Radius. Das heißt, wir wollen auch eine lineare Verteilung der Zufallsradien, um eine konstante Dichte zu erreichen (bei doppeltem Radius ist doppelt so viel Fläche zu füllen, also wollen wir dort doppelt so viele Punkte).
Wie erzeugen wir eine lineare Zufallsverteilung von 0 bis 1? Schauen wir uns zuerst den diskreten Fall an. Nehmen wir an, wir haben eine gewünschte Verteilung von 4 Werten wie {0.1, 0.4, 0.2, 0.3}
(dh wir wollen 1
4-mal so häufig sein wie 0
und doppelt so häufig wie 2
; wir wollen 3
dreimal so häufig sein wie 0
):
Wie kann man einen der vier Werte mit der gewünschten Verteilung auswählen? Wir können sie stapeln, einen gleichmäßig zufälligen Wert zwischen 0 und 1 auf der y-Achse auswählen und das Segment an diesem Punkt auswählen:
Es gibt jedoch eine andere Möglichkeit, diese Auswahl zu visualisieren. Wir könnten stattdessen jeden Wert der Verteilung durch die Akkumulation der Werte bis zu diesem Punkt ersetzen:
Und jetzt behandeln wir die oberste Zeile dieses Diagramms als Funktion f(x) = y
und invertieren sie, um eine Funktion zu erhalten , die wir auf einen einheitlich zufälligen Wert anwenden können in :g(y) = f-1(y) = x
y ∈ [0,1]
Cool, wie kann man das nutzen, um eine lineare Radienverteilung zu erzeugen? Dies ist die Distribution, die wir wollen:
Der erste Schritt besteht darin, die Werte der Verteilung zu akkumulieren. Die Verteilung ist jedoch stetig. Anstatt also alle vorherigen Werte zu addieren, nehmen wir ein Integral von 0
bis r
. Wir können leicht die analytisch lösen: . Wir möchten jedoch, dass dies normalisiert wird, dh dass es mit einer Konstanten multipliziert wird, die den Maximalwert von ergibt. Wir möchten also :∫0r r dr = 1/2 r2
1
r
r2
Und schließlich invertieren wir dies, um eine Funktion zu erhalten [0,1]
, die wir auf einen einheitlichen Wert anwenden können. Dies können wir wiederum analytisch tun: Es ist nur r = √y
, wo y
ist der Zufallswert:
Dies ist eine ziemlich nützliche Technik, die oft verwendet werden kann, um einfache Verteilungen genau zu generieren (sie funktioniert für jede Verteilung, aber für komplizierte müssen die letzten beiden Schritte möglicherweise numerisch gelöst werden). Ich würde es jedoch in diesem speziellen Fall nicht im Produktionscode verwenden, da die Quadratwurzel, der Sinus und der Cosinus unerschwinglich teuer sind: Die Verwendung eines auf Ablehnung basierenden Algorithmus ist im Durchschnitt viel schneller, da nur Addition und Multiplikation erforderlich sind.