CJam, 28 27 bytes
PP+mr_mc\ms]1.mrmqf*"(,)".\
Esta solución no está basada en el rechazo. Estoy generando los puntos en coordenadas polares, pero con una distribución no uniforme de los radios para lograr una densidad uniforme de los puntos.
Pruébalo aquí.
Explicación
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.
Por que funciona Considere un anillo estrecho de radio r
y ancho (pequeño) dr
. El área es aproximadamente 2π*r*dr
(si el anillo es angosto, la circunferencia interna y externa son casi idénticas, y la curvatura puede ignorarse, de modo que el área puede tratarse como la de un rectángulo con longitudes laterales de la circunferencia y el ancho de la circunferencia). anillo). Entonces el área aumenta linealmente con el radio. Esto significa que también queremos una distribución lineal de los radios aleatorios, para lograr una densidad constante (al doble del radio, hay el doble de área para llenar, por lo que queremos el doble de puntos allí).
¿Cómo generamos una distribución aleatoria lineal de 0 a 1? Veamos primero el caso discreto. Digamos que tenemos una distribución deseada de 4 valores, como {0.1, 0.4, 0.2, 0.3}
(es decir, queremos 1
ser 4 veces más comunes 0
y el doble de comunes 2
; queremos 3
tres veces más comunes 0
):
¿Cómo puede elegir uno de los cuatro valores con la distribución deseada? Podemos apilarlos, elegir un valor aleatorio uniforme entre 0 y 1 en el eje y y seleccionar el segmento en ese punto:
Sin embargo, hay una forma diferente de visualizar esta selección. En su lugar, podríamos reemplazar cada valor de la distribución con la acumulación de los valores hasta ese punto:
Y ahora tratamos la línea superior de este gráfico como una función f(x) = y
y la invertimos para obtener una función , que podemos aplicar a un valor aleatorio uniforme en :g(y) = f-1(y) = x
y ∈ [0,1]
Genial, entonces, ¿cómo puede hacer uso de esto para generar una distribución lineal de radios? Esta es la distribución que queremos:
El primer paso es acumular los valores de la distribución. Pero la distribución es continua, por lo que en lugar de sumar todos los valores anteriores, tomamos una integral de 0
a r
. Podemos resolver fácilmente que analíticamente: . Sin embargo, queremos que esto se normalice, es decir, que se multiplique por una constante de modo que se obtenga el valor máximo de , por lo que lo que realmente queremos es :∫0r r dr = 1/2 r2
1
r
r2
Y finalmente, invertimos esto para obtener una función que podamos aplicar a un valor uniforme [0,1]
, lo que podemos hacer analíticamente nuevamente: es solo r = √y
dónde y
está el valor aleatorio:
Esta es una técnica bastante útil que a menudo se puede utilizar para generar distribuciones simples exactamente (funciona para cualquier distribución, pero para las complicadas los dos últimos pasos pueden tener que resolverse numéricamente). Sin embargo, no lo usaría en este caso particular en el código de producción, porque la raíz cuadrada, el seno y el coseno son prohibitivamente costosos: el uso de un algoritmo basado en rechazo es, en promedio, mucho más rápido, porque solo necesita sumar y multiplicar.