Leí sobre círculos en alguna parte, y justo ahora aprendí sobre discos ( en realidad es un concepto bastante común ) y pensé en codegolf.
Su tarea es aleatorizar un punto / varios puntos en un disco con el radio 1.
Reglas:
- Todos los puntos deben tener la misma probabilidad de ser generados
- Se deben usar coordenadas de punto flotante; el requisito mínimo es de dos decimales (por ejemplo, los puntos
(0.12, -0.45)
o(0.00, -1.00)
son válidos) - Obtiene -20 bytes si su programa realmente muestra el círculo delimitador y los puntos generados en él. Las coordenadas aún tienen que ser válidas pero no se muestran, y la imagen generada debe tener un tamaño de al menos 201 por 201 píxeles
- Obtiene -5 bytes si su programa toma el número de puntos que se generarán como entrada en stdin
- Si decide no trazar el círculo delimitador y los puntos, su programa debe generar los puntos generados en el formato
(x, y)
o(x,y)
en stdout - Si decide tomar el número de puntos generados como entrada, pero no trazarlo, su programa debe generar todos los puntos aleatorios en el formato indicado anteriormente con o sin un espacio intermedio
¡La presentación más corta en bytes gana!
code-golf
math
graphical-output
random
patata dulce
fuente
fuente
0.3503082505747327+0.13499221288682994j
.Respuestas:
Pyth, 26 - 5 = 21 bytes
Toma el número de coordenadas para generar en stdin y las genera en stdout de la siguiente manera:
Utiliza una estrategia similar a @ MartinBüttner, que genera coordenadas polares y radios, excepto que lo hace usando exponenciación compleja.
fuente
p
, ¿no? Simplemente cambia la salida a líneas separadas.CJam,
2827 bytesEsta 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
Por que funciona Considere un anillo estrecho de radio
r
y ancho (pequeño)dr
. El área es aproximadamente2π*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, queremos1
ser 4 veces más comunes0
y el doble de comunes2
; queremos3
tres veces más comunes0
):¿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
ar
. 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 solor = √y
dóndey
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.
fuente
Mathematica,
6844-20 = 24 bytesMuchas gracias por David Carraher por informarme
RandomPoint
, que ahorró 24 (!) Bytes. Mathematica no tiene un built-in para todo.Esto traza el punto y el círculo delimitador para calificar para el bono:
El resultado es una imagen vectorial, por lo que la especificación de tamaño de 201x201 píxeles realmente no tiene sentido, pero por defecto se hace más grande que eso.
fuente
Graphics[{Circle[], Point@RandomPoint@Disk[]}]
?Graphics@{Circle[], Point@RandomPoint@Disk[]}
,
?CJam,
3126 bytesEsto funciona generando repetidamente puntos aleatorios en un cuadrado de longitud lateral 2 y manteniendo el primero que cae dentro del disco de la unidad.
¡Gracias a @ MartinBüttner por jugar golf en 3 bytes!
Pruébelo en línea en el intérprete de CJam .
Cómo funciona
fuente
iKe ,
5351 bytesNada particularmente especial, pero supongo que deberíamos tener al menos una solución gráfica:
Pruébalo en tu navegador .
Editar: puedo reducir dos bytes aplicando el enfoque de @ MartinBüttner para modificar la distribución de coordenadas polares. Creo que también es un poco más directo:
fuente
Perl, 59 Bytes
Esta es solo una solución simple, generar puntos en un cuadrado y rechazar los que están demasiado lejos. Mi truco de golf singular es incluir las tareas dentro de la condición.
Editar: En el proceso de golf, encontré una forma interesante de imprimir puntos aleatorios en un círculo .
fuente
Octava,
2453 - 20 = 33 bytesGenera 501 valores theta igualmente espaciados más un número aleatorio y los escala a todos a [0..2π]. Luego genera 501 1 para el radio del círculo, más un radio aleatorio para el punto y toma la raíz cuadrada para asegurar una distribución uniforme sobre el disco. Luego traza todos los puntos como coordenadas polares.
Aquí hay una demostración rápida de la distribución (sin el círculo unitario):
fuente
Octave / Matlab,
7464 bytesMétodo de rechazo , 64 bytes:
Método directo , 74 bytes (gracias a Martin Büttner por ayudarme a corregir dos errores):
fuente
R,
999581-20 =797561 BytesUsa la construcción de números complejos para construir las x / y a partir de coordenadas polares. Tomar la entrada fue un poco costoso y probablemente haya una mejor manera de hacerlo. El
ylim
yes para asegurar que todo el círculo se traza yxlim
asp
asegura que los puntos se muestran debajo del símbolo del círculo.Gracias a @jbaums y @flodel por los ahorros.
Pruébalo aquí
fuente
runif(9,0,1)
se puede simplificar arunif(9)
symbols(0,0,1,i=F,asp=1,ylim=c(-1,1));points(complex(,,,runif(9),runif(9,-1)*pi))
yli
funciona en lugar deylim
.Procesamiento / Java 141 bytes-20 = 121
el requisito de que 201 * 201 sea el tamaño mínimo requiere que coloque el
setup
método ya que Processing.org tiene por defecto 200x200 :(fuente
QBasic, 138 bytes - 20 - 5 = 113
Toma la entrada del usuario y dibuja el disco y los puntos. Probado en QB64 .
Esta es una estrategia bastante básica de "tirar al tablero y mantener lo que se pega". El problema es que "lo que se pega" no se determina matemáticamente sino gráficamente: se traza un disco blanco sobre un fondo negro, y luego los puntos generados aleatoriamente se rechazan hasta que no sean negros. Los puntos en sí están dibujados en azul (aunque es difícil saber cuándo son píxeles individuales; haga clic en la imagen para ampliarla).
fuente
awk - 95-5 = 90
Como no estaba muy seguro de la parte rand () <. 5, hice algunas pruebas de distribución con esto, usando este script:
que para una entrada de 1e7 me da este resultado, después de tomar una o dos veces en mi café:
lo cual creo que está bastante bien.
Una pequeña explicación:
después de garabatear durante un tiempo, resultó que si desea dividir el disco en cuatro anillos con igual área, los radios donde tendría que cortar son sqrt (1/4), sqrt (1/2 ) y sqrt (3/4). Como el radio real del punto que pruebo sería sqrt (x ^ 2 + y ^ 2), puedo omitir el enraizamiento cuadrado todos juntos. La "coincidencia" 1/4, 2/4, 3/4 podría estar relacionada con lo que M. Buettner señaló anteriormente.
fuente
HPPPL , 146 (171-20-5) bytes
Ejemplo para 10000 puntos (incluido el tiempo en segundos para el dispositivo real):
La función en sí es llamada por
r(n)
. El resto de la imagen de arriba es solo para fines de sincronización.Resultado (el diámetro del disco es de 236 píxeles):
La versión anterior no almacena las coordenadas del punto, por lo que escribí una versión que toma dos parámetros
r(n,p)
.n
es el número de puntos yp=0
devuelve los puntos al terminal,p=1
traza los puntos y el disco), en caso de que el almacenamiento de coordenadas sea obligatorio. Esta versión tiene 283 (308-20-5) bytes de longitud:La versión sin golf:
Salida de terminal para
r(10,0)
:r(10,1)
muestra el disco con los puntos, como se muestra arriba.fuente
JavaScript, 75 bytes
Basado en rechazo:
Método directo (80 bytes):
fuente
Python,
135130 bytesSe eliminó el
**0.5
agradecimiento a la sugerencia de @ jimmy23013 (debido a que es un círculo unitario, ahora estoy verificando si la distancia al cuadrado entre (x, y) y (0, 0) es igual a 1 2. Esto es lo mismo).Esto también me liberó para eliminar los paréntesis.
fuente
**0.5
.