¡Feliz Día de Pi a todos! Sin ninguna razón, estoy tratando de construir un estimador de Pi de Monte Carlo que sea lo más corto posible. ¿Podemos construir uno que pueda caber en un tweet?
Para aclarar, lo que tengo en mente es el enfoque típico de dibujar puntos aleatorios del cuadrado de la unidad y calcular la relación que cae dentro del círculo de la unidad. El número de muestras puede estar codificado o no. Si los codifica, debe usar al menos 1000 muestras. El resultado puede ser devuelto o impreso como punto flotante, punto fijo o número racional.
Sin funciones trigonométricas o constantes Pi, debe ser un enfoque de Monte Carlo.
Este es el código de golf, por lo que gana el envío más corto (en bytes).
code-golf
random
pi
approximation
keegan
fuente
fuente
((0..4e9).map{rand**2+rand**2<1}.to_s.sub(/./,"$1.")
map
te da una serie detrue
yfalse
?.filter{...}.size
Sin embargo, debería funcionar.Respuestas:
80386 código máquina,
4038 bytesHexdump del código:
Cómo obtener este código (del lenguaje ensamblador):
Esta es una función que utiliza la
fastcall
convención de llamada de MS (el número de iteraciones se pasa en el registroecx
). Devuelve el resultado en elst
registro.Cosas divertidas sobre este código:
rdrand
- ¡solo 3 bytes para generar un número aleatorio!D
) con el radio al cuadrado (2^32
) se realiza automáticamente: la bandera de acarreo contiene el resultado.fuente
eax
; elmul
comando lo multiplica por sí mismo y pone la parte alta enedx
; la parte bajaeax
se descarta.Matlab / Octave, 27 bytes
Sé que ya hay una respuesta Matlab / Octave, pero probé mi propio enfoque. Usé el hecho de que la integral de
4/(1+x^2)
entre 0 y 1 es pi.fuente
R, 40 (o 28 o 24 usando otros métodos)
Pitón 2, 56
Otro Python, si está permitido numpy, pero bastante similar a Matlab / Octave:
fuente
Mathematica,
424039 bytes (¿o 31/29?)Tengo tres soluciones, todas a 42 bytes:
Todas son funciones sin nombre que toman el número de muestras
n
yd devuelven una aproximación racional π. Primero todos generann
puntos en el cuadrado de la unidad en el cuadrante positivo. Luego determinan el número de esas muestras que se encuentran dentro del círculo unitario, y luego se dividen por el número de muestras y se multiplican por4
. La única diferencia está en cómo determinan el número de muestras dentro del círculo unitario:Count
con la condición de queNorm[p] < 1
.1
y luego lo redondea. Esto convierte a los números dentro del círculo unidad a1
y a los que están fuera0
. Después solo los sumo a todosTr
.1.5
, por lo que puedo usarlo enRound
lugar deCeiling
.Aaaaa, y mientras escribía esto, se me ocurrió que existe una solución más corta, si solo resta
2
y luego usoFloor
:o guardar otro byte utilizando los operadores de piso o techo Unicode:
Tenga en cuenta que las tres soluciones basadas en redondeo también se pueden escribir con, en
Mean
lugar deTr
y sin/#
, nuevamente, para los mismos bytes.Si otros enfoques basados en Monte Carlo están bien (específicamente, el que Peter ha elegido), puedo hacer 31 bytes estimando la integral de o 29 usando la integral de , esta vez dada como un número de coma flotante:
√(1-x2)
1/(1+x2)
fuente
CJam,
27 2322 o 20 bytes2 bytes guardados gracias a Runner112, 1 byte guardado gracias a Sp3000
Toma el recuento de iteraciones de STDIN como entrada.
Esto es tan sencillo como parece. Estos son los principales pasos involucrados:
Expansión de código :
Pruébalo en línea aquí
Si el valor promedio de
1/(1+x^2)
también se considera como Monte Carlo, entonces esto se puede hacer en 20 bytes:Pruébalo aquí
fuente
1dmr
lugar deKmrK/
, y verificar si la suma de los cuadrados es mayor que 1 con eni
lugar de1>
(pensé que esta era particularmente inteligente) .i
truco es realmente genial! Y maldita sea la falta de documentación para1dmr
Python 2,
7775 bytesUtiliza 4000 muestras para guardar bytes con
1e3
.fuente
...*8000;print a/2e3
.Commodore 64 Basic, 45 bytes
Sustituciones de PETSCII:
─
=SHIFT+E
,/
=SHIFT+N
,┌
=SHIFT+O
Genera 1000 puntos en el primer cuadrante; para cada uno, agrega la veracidad de "x ^ 2 + y ^ 2 <1" a una cuenta corriente, luego divide la cuenta por 250 para obtener
pi
. (La presencia de un signo menos se debe a que en el C64, "verdadero" = -1.)fuente
(1)
hacer?/
no es el símbolo de división, es el personaje producido al escribirSHIFT+N
en un teclado Commodore 64.R/(1)
es la forma de acceso directo paraRND(1)
, es decir. "producir un número aleatorio entre 0 y 1 utilizando la semilla RNG actual".J, 17 bytes
Calcula el valor medio de los valores de
40000
muestra de la función4*sqrt(1-sqr(x))
en el rango[0,1]
.Prácticamente
0 o.x
regresasqrt(1-sqr(x))
.fuente
> <> (Pescado) , 114 bytes
Ahora,> <> no tiene un generador de números aleatorios incorporado. Sin embargo, tiene una función que envía el puntero en una dirección aleatoria. El generador de números aleatorios en mi código:
Básicamente genera bits aleatorios que forman un número binario y luego convierte ese número binario aleatorio a decimal.
El resto son solo los puntos regulares en el enfoque cuadrado.
Uso: cuando ejecuta el código, debe asegurarse de rellenar previamente la pila (-v en el intérprete de Python) con el número de muestras, por ejemplo
devoluciones
fuente
Matlab u Octave 29 bytes (¡gracias a flawr!)
(No estoy muy seguro si <1 está bien. Leí que debería ser <= 1. Pero, ¿qué tan grande es la probabilidad de sacar exactamente 1 ...?)
Matlab u Octave 31 bytes
fuente
mean(sum(rand(2,4e6).^2)<1)*4
.Java, 108 bytes
Cuatro mil iteraciones, agregando 0.001 cada vez que el punto está dentro del círculo unitario. Cosas bastante básicas.
Nota: Sí, sé que puedo eliminar cuatro bytes cambiando
π
a un carácter de un solo byte. Me gusta así.fuente
Javascript: 62 bytes
Utilicé la respuesta de JavaScript anterior (ahora eliminada) y afeité 5 bytes.
fuente
GolfScript (34 caracteres)
Demostración en línea
Esto usa punto fijo porque GS realmente no tiene punto flotante. Abusa un poco del uso del punto fijo, por lo que si desea cambiar el recuento de iteraciones asegúrese de que sea el doble de una potencia de diez.
Crédito a xnor por el método particular de Monte Carlo empleado.
fuente
Python 2,
908581 bytesvuelve
3.14120037157
por ejemplo. El recuento de la muestra es 4782969 (9 ^ 7). Puede obtener una mejor pi con 9 ^ 9 pero tendrá que ser paciente.fuente
range(9**7)
con[0]*9**7
o algo así, ya que no lo usai
. Y la lista no es demasiado larga para encontrarse con problemas de memoria.range()
pero había olvidado por completo ese truco.[0]9**7
que no es una sintaxis válida.Ruby, 39 bytes
Uno de los aspectos más destacados es que este puede usar
8e5
notación, lo que lo hace extensible hasta ~ 8e9 muestras en el mismo conteo de bytes del programa.fuente
Perl 6 , 33 bytes
Pruébalo en línea!
Esta es una función que toma el número de muestras como argumento.
fuente
Scala,
877766 bytesfuente
1000
con8000
y250d
con2e4
ambos, guarde un byte y aumente el número de muestras en un factor de 8.Pure Bash, 65 bytes
Toma un único parámetro de línea de comandos que se multiplica por 4 para dar el número de muestras. La aritmética de Bash es solo de enteros, por lo que se genera un racional. Esto se puede canalizar
bc -l
para la división final:fuente
Joe ,
2019 bytesNota: esta respuesta no es competitiva, porque la versión 0.1.2, que agregó aleatoriedad, se lanzó después de este desafío.
Función denominada F:
Función sin nombre:
Ambos toman el recuento de muestra como argumento y devuelven el resultado. ¿Cómo trabajan?
Ejecuciones de ejemplo:
fuente
dc, 59 caracteres (se ignora el espacio en blanco)
Probé esto en Plan 9 y OpenBSD, así que imagino que funcionará en Linux (GNU?)
dc
.Explicación por línea:
i
si 1 es mayor que la suma de sus cuadrados] en el registrou
.x
en 1] en el registroi
.u
, incrementar registrom
y luego ejecutar registroz
si el registrom
es mayor que el registron
] en el registroz
.Establezca la escala a 5 puntos decimales.
z
.x
(el número de visitas) por el registron
(el número de puntos), multiplique el resultado por 4 e imprima.Sin embargo, hice trampa:
El programa necesita un suministro de flotadores aleatorios entre 0 y 1.
Uso:
Prueba de funcionamiento:
Ahora con menos trampa (100 bytes)
Alguien señaló que podría incluir un simple prng.
http://en.wikipedia.org/wiki/RANDU
Sin golf
Prueba de funcionamiento:
fuente
Pyth, 19
Dé el número deseado de iteraciones como entrada.
Demostración
Como Pyth no tiene una función de "número flotante aleatorio", tuve que improvisar. El programa elige dos enteros positivos aleatorios menores que la entrada, cuadrados, sumas y en comparación con la entrada al cuadrado. Esto se realizó varias veces igual a la entrada, luego el resultado se multiplica por 4 y se divide por la entrada.
En noticias relacionadas, agregaré una operación de números aleatorios de coma flotante a Pyth en breve. Sin embargo, este programa no usa esa función.
Si interpretamos "El resultado puede ser devuelto o impreso como punto flotante, punto fijo o número racional". generosamente, luego imprimir el numerador y el denominador de la fracción resultante debería ser suficiente. En ese caso:
Pyth, 18
Este es un programa idéntico, con la operación de división de coma flotante (
c
) eliminada.fuente
Julia, 37 bytes
El número de muestras es 65536 (= 4 ^ 8).
Una variante ligeramente más larga: una función con número de muestras
s
como único argumento:fuente
C, 130 bytes
Sin golf:
fuente
f()
. ¿Qué compilador usaste? Ver tio.run/##Pc49C4JAHIDx3U9xGMG9ZdYgwWkgtNbQ1BZ6L/UHO8M07hA/…En realidad , 14 bytes (no competitivos)
Pruébalo en línea!
Esta solución no es competitiva porque el lenguaje es posterior al desafío. La cantidad de muestras se proporciona como entrada (en lugar de codificada).
Explicación:
fuente
Raqueta 63 bytes
Usando el método de respuesta en lenguaje R por @Matt:
Sin golf:
Pruebas:
Salida (fracción):
Como decimal:
fuente
Fortran (GFortran) ,
8483 bytesPruébalo en línea!
Este código está muy mal escrito. Fallará si gfortran decide inicializar la variable
A
con otro valor que no sea 0 (que ocurre aproximadamente en el 50% de las compilaciones) y, siA
se inicializa como 0, siempre generará la misma secuencia aleatoria para la semilla dada. Entonces, siempre se imprime el mismo valor para Pi.Este es un programa mucho mejor:
Fortran (GFortran) ,
10099 bytesPruébalo en línea!
(Un byte guardado en cada versión; gracias Penguino).
fuente
Japt , 26 o 18 bytes
Pruébalo en línea!
Análogo a la respuesta de Optimizer , principalmente tratando de aprender Japt.
Toma el número de iteraciones para ejecutar como entrada implícita
U
.Si
1/(1+x^2)
está permitido (en lugar de dos randoms separados), entonces podemos lograr 18 bytes con la misma lógica.fuente
Mh
calcular la hipotenusa en lugar de hacerlo usted mismo ;-) Además, puede usarx
para tomar la suma de una matriz, en lugar de reducirla mediante la adición:o x@MhMr Mr)<1Ã*4/U
Mh
así, ¡gracias! Su respuesta aleatoria es casi tan corta como mi respuesta con solo una aleatoria, eso es genial. Recordaréx
que tiendo a usar mucho la reducción cuando intento jugar golf, por lo que esto será muy útil.F #, 149 bytes
Pruébalo en línea!
Por lo que puedo entender, para hacer este tipo de total acumulado en F # es más corto crear una matriz de números y usar el
Seq.sumBy
método que usar unfor..to..do
bloque.Lo que hace este código es que crea una colección de números de punto flotante del 1 al
s
, realiza la funciónfun x->...
para el número de elementos en la colección y suma el resultado. Hays
elementos en la colección, por lo que la prueba aleatoria se realizas
veces. Los números reales en la colección se ignoran (fun x->
, perox
no se usan).También significa que la aplicación primero debe crear y completar la matriz, y luego iterar sobre ella. Por lo tanto, es probablemente el doble de lento que un
for..to..do
bucle. ¡Y con la creación de la matriz, el uso de la memoria está en la región de O (f ** k)!Para la prueba en sí misma, en lugar de usar una
if then else
declaración, lo que hace es calcular la distancia (q()+q()|>Math.Sqrt
) y redondearla hacia abajo conMath.Floor
. Si la distancia está dentro del círculo, se redondeará hacia abajo a 0. Si la distancia está fuera del círculo, se redondeará hacia abajo a 1. ElSeq.sumBy
método totalizará estos resultados.Tenga en cuenta entonces que lo que
Seq.sumBy
ha totalizado no son los puntos dentro del círculo, sino los puntos fuera de él. Entonces, para el resultado que se necesitas
(nuestro tamaño de muestra) y resta el total de él.También parece que tomar un tamaño de muestra como parámetro es más corto que codificar el valor. Así que estoy haciendo trampa un poco ...
fuente
Haskell,
11611411096 bytesDebido a que tratar
import System.Random; r=randoms(mkStdGen 2)
tomaría demasiados bytes preciosos, genero una lista infinita de números aleatorios con el generador lineal congruencial que algunos dicen que es casi criptográficamente fuerte:x↦x*9+1 mod 8^9
que según el Teorema de Hull-Dobell tiene el período completo8^9
.g
produce4
si el punto de número aleatorio está dentro del círculo para pares de números aleatorios en[0..8^9-1]
porque esto elimina una multiplicación en la fórmula utilizada.Uso:
Pruébalo en línea!
fuente
Perl 5, 34 bytes
El número de muestras se toma de stdin. Requiere
-p
.Funciona porque:
Pruébalo en línea!
fuente