El reto
Escriba un programa o función que no tome entrada y genere un vector de longitud en una dirección aleatoria teóricamente uniforme .
Esto es equivalente a un punto aleatorio en la esfera descrita por
resultando en una distribución como tal
Salida
Tres flotadores de una distribución aleatoria teóricamente uniforme para la cual la ecuación mantiene fiel a los límites de precisión.
Observaciones de desafío
- La distribución aleatoria debe ser teóricamente uniforme . Es decir, si el generador de números pseudoaleatorios fuera reemplazado por un RNG verdadero de los números reales , daría como resultado una distribución aleatoria uniforme de puntos en la esfera.
- Generar tres números aleatorios a partir de una distribución uniforme y normalizarlos no es válido: habrá un sesgo hacia las esquinas del espacio tridimensional.
- Del mismo modo, generar dos números aleatorios a partir de una distribución uniforme y usarlos como coordenadas esféricas no es válido: habrá un sesgo hacia los polos de la esfera.
- La uniformidad adecuada se puede lograr mediante algoritmos que incluyen, entre otros:
- Genere tres números aleatorios , y partir de una distribución normal (gaussiana) alrededor de y normalícelos. 0
- Genere tres números aleatorios , y partir de una distribución uniforme en el rango . Calcule la longitud del vector por . Entonces, si , rechaza el vector y genera un nuevo conjunto de números. De lo contrario, si , normalice el vector y devuelva el resultado. ( - 1 , 1 ) l = √
- Genere dos números aleatorios y de una distribución uniforme en el rango y conviértalos a coordenadas esféricas de la siguiente manera: para que , y puedan calcularse mediante( 0 , 1 ) θ
- Proporcione en su respuesta una breve descripción del algoritmo que está utilizando.
- Lea más sobre la selección de puntos de esfera en MathWorld .
Ejemplos de salida
[ 0.72422852 -0.58643067 0.36275628]
[-0.79158628 -0.17595886 0.58517488]
[-0.16428481 -0.90804027 0.38532243]
[ 0.61238768 0.75123833 -0.24621596]
[-0.81111161 -0.46269121 0.35779156]
Observaciones generales
- Este es el código de golf , por lo que gana la respuesta con la menor cantidad de bytes en cada idioma.
- Se aplican reglas estándar , reglas de E / S y reglas de escapatoria .
- Incluya un enlace Probar en línea o equivalente para demostrar que su código funciona.
- Motive su respuesta con una explicación de su código.
pi/6 ≈ 0.5236
de producir una salida. Esa es el área de la esfera inscrita en el cubo de área unitariaRespuestas:
Wolfram Language (Mathematica) , 20 bytes
Pruébalo en línea!
Hace exactamente lo que dice en la lata.
fuente
R , 23 bytes
Pruébalo en línea!
Genera 3 realizaciones de la distribuciónN(0,1) y normaliza el vector resultante.
Parcela de 1000 realizaciones:
fuente
Código de máquina x86-64 -
63 62 5549 bytesUtiliza el segundo algoritmo, modificado. Devuelve el vector de
[x, y, z, 0]
en xmm0.Explicación:
Empuja el valor de 1 y 2 ^ 31 como flotante a la pila. Los datos se superponen debido a la extensión del signo, ahorrando unos pocos bytes.
vbroadcastss xmm1,dword ptr [rsp+5]
Carga el valor de 2 ^ 31 en 4 posiciones de xmm1.Genera un entero aleatorio de 32 bits y lo carga en la parte inferior de xmm0.
Genera un entero aleatorio de 32 bits, conviértalo en flotante (con signo) y divídalo entre 2 ^ 31 para obtener números entre -1 y 1.
vdpps xmm2,xmm0,xmm0,7Fh
agrega los cuadrados de los 3 flotadores inferiores usando un producto de punto por sí mismo, enmascarando el flotador superior. Esto le da la longitudCompara la longitud al cuadrado con 1 y rechaza los valores si no es igual a 1. Si la longitud al cuadrado es uno, entonces la longitud también es uno. Eso significa que el vector ya está normalizado y guarda una raíz cuadrada y divide.
Restaurar la pila.
ret
devuelve valor en xmm0Pruébalo en línea .
fuente
aesenc
para producir 128 bits "aleatorios" es simplemente hermoso.Python 2 , 86 bytes
Pruébalo en línea!
Genera la coordenada z uniformemente de -1 a 1. Luego, las coordenadas xey se muestrean uniformemente en un círculo de radio
(1-z*z)**.5
.Puede que no sea obvio que la distribución esférica es uniforme en factor sobre la coordenada z (y así sobre cada coordenada). Esto es algo especial para la dimensión 3. Vea esta prueba de que el área de superficie de un corte horizontal de una esfera es proporcional a su altura. Aunque las rebanadas cercanas al ecuador tienen un radio mayor, las rebanadas cercanas al polo se titulan más hacia adentro, y resulta que estos dos efectos se cancelan exactamente.
Para generar un ángulo aleatorio en este círculo, elevamos la unidad imaginaria
1j
a una potencia aleatoria uniforme entre 0 y 4, lo que nos ahorra la necesidad de necesitar funciones trigonométricas, pi o e, cualquiera de las cuales necesitaría una importación. Luego extraemos la parte imaginaria real. Si podemos generar un número complejo para dos de las coordenadas, la última línea podría serprint a,z
.86 bytes
Pruébalo en línea!
Genera tres normales y escala el resultado.
Python 2 con numpy, 57 bytes
Pruébalo en línea!
sum(a*a)**.5
es más corto quelinalg.norm(a)
. También podríamos hacerdot(a,a)
lo mismo quesum(a*a)
. En Python 3, esto se puede acortar paraa@a
usar el nuevo operador@
.fuente
z
, desde una distribución uniforme, no se modifica.z
, y lo arreglé por unos pocos bytes.Octava ,
40 3322 bytesMuestramos una distribución normal estándar 3d y normalizamos el vector:
Pruébalo en línea!
fuente
disp
:)Unidad C # , 34 bytes
La unidad tiene un valor incorporado para los valores aleatorios de la esfera de la unidad, así que pensé en publicarlo.
fuente
f=>Random.onUnitSphere
f
el Tipo; usandovar
solo funciona dentro de un método ySystem.Func<Vector3>
fue más largo.f=>Random.onUnitSphere
es una presentación perfectamente válidaf=>UnityEngine.Random.onUnitSphere
te salva elusing
MATL , 10 bytes
Pruébalo en línea!
Explicación
Esto utiliza el primer enfoque descrito en el desafío.
fuente
Ruby ,
34 5049 bytesPruébalo en línea!
Devuelve una matriz de 3 números
[z,y,x]
.x
yy
se generan al elevari
(raíz cuadrada de -1) a una potencia aleatoria entre 0 y 4. Este número complejo debe escalarse adecuadamente de acuerdo con elz
valor de acuerdo con el teorema de Pitágoras:(x**2 + y**2) + z**2 = 1.
La
z
coordenada (que se genera primero) es simplemente un número distribuido uniformemente entre -1 y 1. Aunque no es inmediatamente obvio, dA / dz para un corte a través de una esfera es constante (e igual al perímetro de un círculo del mismo radio que toda la esfera).Aparentemente, esto fue descubierto por Arquímedes, quien lo describió de una manera muy poco parecida al cálculo, y se conoce como el teorema de la Arqueta de Arquímedes. Ver https://brilliant.org/wiki/surface-area-sphere/
Otra referencia de los comentarios sobre la respuesta de xnor. Una URL sorprendentemente corta, que describe una fórmula sorprendentemente simple: http://mathworld.wolfram.com/Zone.html
fuente
[z, x+yi]
. Lo dejaré como está a menos que diga que está bien.z*z
lugar dez**2
?z*z
. Lo he editado ahora. La otra cosa que podría hacer es reemplazarrand*4
con algo comoz*99
ox*9E9
(limitando efectivamente los posibles valores a una espiral muy fina en la esfera), pero creo que eso reduce la calidad del azar.05AB1E ,
2322 bytesImplementa el segundo algoritmo.
Pruébelo en línea u obtenga algunas salidas aleatorias más .
Explicación:
5
9
fuente
TI-BASIC, 15 bytes *
Usando el algoritmo "genera 3 valores normalmente distribuidos y normaliza ese vector".
Al finalizar un programa con una expresión, se imprime automáticamente el resultado en la pantalla de inicio después de que el programa finaliza, por lo que el resultado se muestra, no solo se genera y se oculta.
*:
randNorm(
es un token de dos bytes , el resto son tokens de un byte . He contado el inicial (inevitable):
, sin eso serían 14 bytes. Guardado como un programa con un nombre de una letra, ocupa 24 bytes de memoria, que incluye los 9 bytes de sobrecarga del sistema de archivos.fuente
JavaScript (ES7),
77 7675 bytesPruébalo en línea!
Comentado
JavaScript (ES6), 79 bytes
Implementa el 2º algoritmo.
Pruébalo en línea!
Comentado
fuente
Procesando 26 bytes
Programa completo
Esta es la implementación https://github.com/processing/processing/blob/master/core/src/processing/core/PVector.java
fuente
Python 2 , 86 bytes
Pruébalo en línea!
Implementa el primer algoritmo.
Python 2 ,
107103bytesPruébalo en línea!
Implementa el segundo algoritmo.
fuente
Haskell ,
125123119118 bytesPruébalo en línea!
Hace tres uniformes randoms y muestras de rechazo.
fuente
JavaScript, 95 bytes
Usted
nonecesita no a la entradaa
.fuente
Julia 1.0 , 24 bytes
Pruébalo en línea!
Dibuja un vector de 3 valores, extraídos de una distribución normal alrededor de 0 con desviación estándar 1. Luego, simplemente los normaliza.
fuente
randn()
, de un par de pruebas rápidas, no parece estar limitado al rango requerido. Además, esto no incluye una verificación parahypot()
devolver un valor>1
, que debe ser rechazado.randn
simular a partir de una distribución normal estándar en lugar de una uniforme (0,1), por lo que este enfoque es idéntico al R.[-1,1)
dividirlos por el hipotenusa, que será>1
, compensa eso? Eso me lleva a preguntarme si el ternario en mi solución es necesario ...MathGolf ,
211918 bytesImplementación del segundo algoritmo.
Pruébelo en línea o vea algunas salidas más al mismo tiempo .
Explicación:
fuente
Java 8 ( @Arnauld 's tercera algoritmo modificado),
131126119111109 bytesPuerto de la respuesta de JavaScript de @Arnauld , ¡así que asegúrese de votarlo!
-2 bytes gracias a @ OlivierGrégoire .
Esto se implementa como:
Pruébalo en línea.
Implementación previa del 3er algoritmo (
131126119 bytes):Implementado como:
Pruébalo en línea.
Explicación:
Java 8 (segundo algoritmo),
153143 bytesPruébalo en línea.
2do algoritmo:
fuente
sqrt(1-k*k)
realmente ahorra más bytes en Java que en JS. :)M.sin
, 1xM.cos
y 1xM.acos
, su enfoque utiliza 2xM.sin
y 1xM.sqrt
, que es de donde provienen principalmente los bytes adicionales guardados. :)double[]
ya que eso no cambia el conteo de bytes).Japt , 20 bytes
Implementación del puerto de Arnauld del segundo algoritmo.
Pruébalo
fuente
Pyth , 24 bytes
Pruébalo en línea!
Utiliza el algoritmo n. ° 2
fuente
OCaml ,
1109995 byteslet ... in
fun
()
Pruébalo en línea
Solución original:
Primero defino:
La
Random.float
función de OCaml incluye los límites. Luego,fuente
0
y1
directamente como coordenadas esféricas. Esto es incorrecto, como se muestra en los comentarios 3 y 4 del desafío, ya que terminas con un sesgo hacia los polos de la esfera. Puede corregir esto aplicando el método que se muestra en el comentario 4.