Stimatore Monte Carlo di Pi


25

Buon Pi Day a tutti! Per nessun motivo, sto cercando di costruire uno stimatore Monte Pi di Pi il più corto possibile. Possiamo costruirne uno che si inserisce in un tweet?

Per chiarire, quello che ho in mente è l'approccio tipico di disegnare punti casuali dal quadrato dell'unità e calcolare il rapporto che rientra nel cerchio dell'unità. Il numero di campioni può essere codificato o meno. Se li hardcode, è necessario utilizzare almeno 1000 campioni. Il risultato può essere restituito o stampato come punto mobile, punto fisso o numero razionale.

Nessuna funzione trig o costanti Pi, deve essere un approccio Monte Carlo.

Questo è il golf del codice, quindi vince l'invio più breve (in byte).


2
sono consentite le funzioni di attivazione? Ti suggerisco di vietarli esplicitamente.
Level River St

((0..4e9).map{rand**2+rand**2<1}.to_s.sub(/./,"$1.")
John Dvorak,

@JanDvorak Come dovrebbe funzionare? Non ti mapdà una serie di truee false?
Martin Ender,

@ MartinBüttner Ah, oops, scusa. .filter{...}.sizedovrebbe funzionare, però.
John Dvorak,

@JanDvorak Indeed. È davvero pulito :)
Martin Ender

Risposte:


17

80386 codice macchina, 40 38 byte

Hexdump del codice:

60 33 db 51 0f c7 f0 f7 e0 52 0f c7 f0 f7 e0 58
03 d0 72 03 83 c3 04 e2 eb 53 db 04 24 58 db 04
24 58 de f9 61 c3

Come ottenere questo codice (dal linguaggio assembly):

    // ecx = n (number of iterations)
    pushad;
    xor ebx, ebx; // counter
    push ecx; // save n for later
myloop:
    rdrand eax; // make a random number x (range 0...2^32)
    mul eax; // calculate x^2 / 2^32
    push edx;
    rdrand eax; // make another random number y
    mul eax; // calculate y^2 / 2^32
    pop eax;
    add edx, eax; // calculate D = x^2+y^2 / 2^32 (range 0...2^33)
    jc skip; // skip the following if outside the circle
    add ebx, 4; // accumulate the result multiplied by 4
skip:
    loop myloop;
    push ebx; // convert the result
    fild dword ptr [esp]; // to floating-point
    pop eax;
    fild dword ptr [esp]; // convert n to floating-point
    pop eax;
    fdivp st(1), st; // divide

    popad;
    ret;

Questa è una funzione che utilizza la fastcallconvenzione di chiamata MS (il numero di iterazioni viene passato nel registro ecx). Restituisce il risultato nel stregistro.

Cose divertenti su questo codice:

  • rdrand - solo 3 byte per generare un numero casuale!
  • Usa l'aritmetica intera (senza segno) fino alla divisione finale.
  • Il confronto della distanza al quadrato ( D) con il raggio al quadrato ( 2^32) viene eseguito automaticamente - la bandiera di trasporto contiene il risultato.
  • Per moltiplicare il conteggio per 4, conta i campioni in passi di 4.

Il commento dovrebbe essere "Calcola x ^ 2% 2 ^ 32"
Cole Johnson

@ColeJohnson No - il numero casuale è in eax; il mulcomando lo moltiplica da solo e inserisce la parte alta edx; la parte bassa in eaxviene scartata.
Anatolyg

11

Matlab / Octave, 27 byte

So che esiste già una risposta Matlab / Octave, ma ho provato il mio approccio. Ho usato il fatto che l'integrale 4/(1+x^2)tra 0 e 1 è pi.

mean(4./(1+rand(1,1e5).^2))

Un algoritmo diverso è sempre fantastico! Inoltre, più efficiente!
Anatolyg

7

R, 40 (o 28 o 24 usando altri metodi)

mean(4*replicate(1e5,sum(runif(2)^2)<1))

mean(4*sqrt(1-runif(1e7)^2))

mean(4/(1+runif(1e7)^2))

Python 2, 56

Un altro Python, se è consentito il numpy, ma abbastanza simile a Matlab / Octave:

import numpy;sum(sum(numpy.random.rand(2,8e5)**2)<1)/2e5

6

Mathematica, 42 40 39 byte (o 31/29?)

Ho tre soluzioni tutte a 42 byte:

4Count[1~RandomReal~{#,2},p_/;Norm@p<1]/#&
4Tr@Ceiling[1-Norm/@1~RandomReal~{#,2}]/#&
4Tr@Round[1.5-Norm/@1~RandomReal~{#,2}]/#&

Sono tutte funzioni senza nome che prendono il numero di campioni ne restituiscono un razionale approssimativo π. Innanzitutto generano tutti npunti nel quadrato dell'unità nel quadrante positivo. Quindi determinano il numero di quei campioni che si trovano all'interno del cerchio unitario, quindi si dividono per il numero di campioni e si moltiplicano per 4. L'unica differenza è nel modo in cui determinano il numero di sampple all'interno del cerchio unitario:

  • Il primo usa Countcon la condizione che Norm[p] < 1.
  • Il secondo sottrae la norma di ciascun punto da 1e quindi arrotonda per eccesso. Questo trasforma i numeri all'interno del cerchio unitario in 1e quelli esterni a 0. In seguito li riassumo con Tr.
  • Il terzo fa essenzialmente lo stesso, ma sottrae il da 1.5, quindi posso usare Roundinvece di Ceiling.

Aaaaa e mentre scrivevo questo, mi è venuto in mente che esiste davvero una soluzione più breve, se solo sottraggo 2e quindi uso Floor:

4Tr@Floor[2-Norm/@1~RandomReal~{#,2}]/#&

o salvando un altro byte utilizzando gli operatori di pavimentazione o soffitto Unicode:

4Tr@⌊2-Norm/@1~RandomReal~{#,2}⌋/#&
4Tr@⌈1-Norm/@1~RandomReal~{#,2}⌉/#&

Si noti che le tre soluzioni basate sull'arrotondamento possono anche essere scritte con Meaninvece Tre senza il /#, sempre per gli stessi byte.


Se altri approcci basati su Monte Carlo vanno bene (in particolare, quello scelto da Peter), posso fare 31 byte stimando l'integrale di o 29 usando l'integrale di , questa volta dato come un numero in virgola mobile:√(1-x2)1/(1+x2)

4Mean@Sqrt[1-1~RandomReal~#^2]&
Mean[4/(1+1~RandomReal~#^2)]&

9
Hai tre soluzioni per la vita, l'universo e tutto e decidi di rovinarlo? Eresia.
Seequ,


6

CJam, 27 23 22 o 20 byte

4rd__{{1dmr}2*mhi-}*//

2 byte salvati grazie a Runner112, 1 byte risparmiati grazie a Sp3000

Prende il conteggio delle iterazioni da STDIN come input.

Questo è diretto. Questi sono i passaggi principali coinvolti:

  • Leggi l'input ed esegui le iterazioni Monte Carlo più volte
  • In ogni iterazione, ottieni la somma del quadrato di due float casuali da 0 a 1 e vedi se è inferiore a 1
  • Ottieni il rapporto di quante volte abbiamo ottenuto meno di 1 per iterazioni totali e moltiplicalo per 4 per ottenere PI

Espansione del codice :

4rd                     "Put 4 on stack, read input and convert it to a double";
   __{            }*    "Take two copies, one of them determines the iteration"
                        "count for this code block";
      {1dmr}2*          "Generate 2 random doubles from 0 to 1 and put them on stack";
              mh        "Take hypot (sqrt(x^2 + y^2)) where x & y are the above two numbers";
                i       "Convert the hypot to 0 if its less than 1, 1 otherwise";
                 -      "Subtract it from the total sum of input (the first copy of input)";
                    //  "This is essentially taking the ratio of iterations where hypot";
                        "is less than 1 by total iterations and then multiplying by 4";

Provalo online qui


Se il valore medio di 1/(1+x^2)è anche considerato Monte Carlo, ciò può essere fatto in 20 byte:

Urd:K{4Xdmr_*)/+}*K/

Provalo qui


2
Ho provato anche una risposta CJam e sono riuscito a ottenere 2 byte sotto il tuo punteggio. Ma il mio codice è uscito in modo simile al tuo, mi sentirei sporco pubblicandolo come una risposta separata. Tutto era lo stesso, tranne per la scelta della variabile e queste due ottimizzazioni: ottenere un numero casuale da 0 a 1 con 1dmrinvece di KmrK/e verificare se la somma dei quadrati è maggiore di 1 con iinvece di 1>(ho pensato che questo fosse particolarmente intelligente) .
Runer112

@ Runer112 Grazie. il itrucco è davvero pulito! E dannatamente la mancanza di documentazione per1dmr
Optimizer,

5

Python 2, 77 75 byte

from random import*;r=random;a=0;exec"a+=r()**2+r()**2<1;"*4000;print a/1e3

Utilizza 4000 campioni con cui salvare i byte 1e3.


5
Potresti ottenere un po 'più di precisione senza costi ...*8000;print a/2e3.
Logic Knight,

5

Commodore 64 Basic, 45 byte

1F┌I=1TO1E3:C=C-(R/(1)↑2+R/(1)↑2<1):N─:?C/250

Sostituzioni PETSCII: = SHIFT+E, /= SHIFT+N, =SHIFT+O

Genera 1000 punti nel primo quadrante; per ciascuno, aggiunge la verità di "x ^ 2 + y ^ 2 <1" a un conteggio progressivo, quindi divide il conteggio per 250 per ottenere pi. (La presenza di un segno meno è perché sul C64, "true" = -1.)


Cosa fa (1)?
ecristopherson

@echristopherson, lo stai leggendo male. /non è il simbolo di divisione, è il personaggio prodotto digitando SHIFT+Nsu una tastiera Commodore 64. R/(1)è il modulo di scelta rapida per RND(1), ad es. msgstr "produce un numero casuale compreso tra 0 e 1 usando l'attuale seme RNG".
Segna il

Oh, hai ragione! Buoni vecchi personaggi grafici PETSCII.
ecristopherson

5

J, 17 byte

Calcola il valore medio dei 40000valori campione della funzione 4*sqrt(1-sqr(x))nell'intervallo [0,1].

Facilmente 0 o.xritorna sqrt(1-sqr(x)).

   1e4%~+/0 o.?4e4$0
3.14915

4

> <> (Pesce) , 114 byte

:00[2>d1[   01v
1-:?!vr:@>x|  >r
c]~$~< |+!/$2*^.3
 .41~/?:-1r
|]:*!r$:*+! \
r+)*: *:*8 8/v?:-1
;n*4, $-{:~ /\r10.

Ora,> <> non ha un generatore di numeri casuali incorporato. Tuttavia ha una funzione che invia il puntatore in una direzione casuale. Il generatore di numeri casuali nel mio codice:

______d1[   01v
1-:?!vr:@>x|  >r
_]~$~< |+!/$2*^__
 __________
___________ _
_____ ____ _______
_____ ____~ ______

Generalmente genera bit casuali che compongono un numero binario e quindi converte quel numero binario casuale in decimale.

Il resto sono solo i punti regolari nell'approccio quadrato.

Utilizzo: quando si esegue il codice è necessario assicurarsi di prepopolare lo stack (-v nell'interprete python) con il numero di campioni, ad esempio

pi.fish -v 1000

ritorna

3.164

4

Matlab o Octave 29 byte (grazie a flawr!)

mean(sum(rand(2,4e6).^2)<1)*4

(Non sono del tutto sicuro che <1 sia OK. Ho letto che dovrebbe essere <= 1. Ma quanto è grande la probabilità di disegnare esattamente 1 ...)

Matlab o Octave 31 byte

sum(sum(rand(2,4e3).^2)<=1)/1e3

1
Ottima idea! È possibile salvare due byte aggiuntivi con mean(sum(rand(2,4e6).^2)<1)*4.
flawr

4

Java, 108 byte

double π(){double π=0,x,i=0;for(;i++<4e5;)π+=(x=Math.random())*x+(x=Math.random())*x<1?1e-5:0;return π;}

Quattromila iterazioni, aggiungendo 0,001 ogni volta che il punto si trova all'interno del cerchio unitario. Roba piuttosto semplice.

Nota: Sì, so di poter eliminare quattro byte passando πa un carattere a byte singolo. Mi piace così.


perché non 9999 iterazioni?
Ottimizzatore

1
@Optimizer Rende la somma più breve. Per 9999 iterazioni, dovrei aggiungere ogni volta un numero più preciso, il che mi costa cifre.
Geobits

1
È possibile salvare un altro byte e migliorare la precisione utilizzando "4e5" e "1e-5" per i numeri.
Vilmantas Baranauskas,

@VilmantasBaranauskas Grazie! Me ne dimentico sempre :) È allettante usare invece 4e9 e 1e-9, ma ci vuole un bel po 'di tempo ...
Geobits

Protip: quando giochi a golf, dovresti effettivamente ridurre i byte, non aumentarli artificialmente
Limone distruttibile

3

Javascript: 62 byte

for(r=Math.random,t=c=8e4;t--;c-=r()**2+r()**2|0);alert(c/2e4)

Ho usato la risposta javascript precedente (ora eliminata) e ho rasato 5 byte.


È possibile collegarsi alla risposta di cfern per dare correttamente credito.
Jonathan Frech,

La risposta sembra essere un frammento che viene annullato I / O . Correggi o elimina il tuo post.
Jonathan Frech,

Siamo spiacenti, sono nuovo, non sapevo come inserire il collegamento alla soluzione precedente che ora appare sono stati eliminati. Per quanto riguarda lo snippet: sono completamente d'accordo, ma quello era il codice della precedente soluzione javascript che ritengo anche non valida questa ragione. Ho modificato il mio per essere un programma.
Guzman Tierno,

Sì; la risposta precedente è stata cancellata perché non valida - ho visto la tua risposta prima di raccomandare la cancellazione, quindi il commento. +1 per l'invio di una risposta valida; benvenuto in PPCG!
Jonathan Frech,

2

GolfScript (34 caratteri)

0{^3?^rand.*^.*+/+}2000:^*`1/('.'@

Demo online

Questo utilizza un punto fisso perché GS non ha davvero un virgola mobile. Abusa leggermente dell'uso del punto fisso, quindi se vuoi cambiare il conteggio delle iterazioni assicurati che sia due volte una potenza di dieci.

Ringraziamo xnor per il particolare metodo Monte Carlo impiegato.


2

Python 2, 90 85 81 byte

from random import*;r=random;print sum(4.for i in[0]*9**7if r()**2+r()**2<1)/9**7

ritorna 3.14120037157per esempio. Il conteggio dei campioni è 4782969 (9 ^ 7). Puoi ottenere un pi migliore con 9 ^ 9 ma dovrai essere paziente.


Puoi salvare 3 sostituendolo range(9**7)con [0]*9**7o qualcosa del genere, poiché non lo usi i. E l'elenco non è troppo lungo per incorrere in problemi di memoria.
Sp3000,

Grazie. Volevo liberarmene, range()ma avevo completamente dimenticato quel trucco.
Logic Knight,

Ho la sensazione che la [0]9**7sintassi non sia valida.
Seequ,

Hai ragione. Ho ricollegato l'asterisco perduto (era sotto la mia scrivania).
Logic Knight,

2

Rubino, 39 byte

p (1..8e5).count{rand**2+rand**2<1}/2e5

Uno dei punti salienti è che questo è in grado di usare la 8e5notazione, il che lo rende estendibile fino a ~ 8e9 campioni nello stesso conteggio dei byte del programma.



1

Scala, 87 77 66 byte

def s=math.pow(math.random,2);Seq.fill(1000)(s+s).count(_<1)/250d

Se si sostituisce 1000con 8000e 250dcon 2e4entrambi si salva un byte e si aumenta il numero di campioni di un fattore 8.
Dave Swartz

1

Pure Bash, 65 byte

for((;i++<$1*4;a+=RANDOM**2+RANDOM**2<32767**2));{ :;}
echo $a/$1

Accetta un singolo parametro della riga di comando che viene moltiplicato per 4 per fornire il numero di campioni. L'aritmetica di Bash è solo intera, quindi viene emesso un razionale. Questo può essere convalidato bc -lper la divisione finale:

$ ./montepi.sh 10000
31477/10000
$ ./montepi.sh 10000|bc -l
3.13410000000000000000
$ 

1

Joe , 20 19 byte

Nota: questa risposta non è competitiva, perché la versione 0.1.2, che ha aggiunto casualità, è stata rilasciata dopo questa sfida.

Funzione denominata F:

:%$,(4*/+1>/+*,?2~;

Funzione senza nome:

%$,(4*/+1>/+*,?2~;)

Entrambi prendono il conteggio dei campioni come argomento e restituiscono il risultato. Come funzionano?

%$,(4*/+1>/+*,?2~;)
   (4*/+1>/+*,?2~;) defines a chain, where functions are called right-to-left
               2~;  appends 2 to the argument, giving [x, 2]
              ?     create a table of random values from 0 to 1 with that shape
            *,      take square of every value
          /+         sum rows, giving a list of (x**2+y**2) values
        1>           check if a value is less than 1, per atom
      /+             sum the results
    4*               multiply by four
%$,                  divide the result by the original parameter

Esempi di esecuzione:

   :%$,(4*/+1>/+*,?2~;
   F400000
3.14154
   F400000
3.14302

1

dc, 59 caratteri (lo spazio bianco viene ignorato)

[? 2^ ? 2^ + 1>i]su
[lx 1+ sx]si
[lu x lm 1+ d sm ln>z]sz

5k
?sn
lzx
lx ln / 4* p
q

Ho provato questo su Plan 9 e OpenBSD, quindi immagino che funzionerà su Linux (GNU?) dc.

Spiegazione per riga:

  1. Memorizza il codice per [leggere e quadrare due float; esegue il registro ise 1 è maggiore della somma dei loro quadrati] nel registrou .
  2. Memorizza il codice in [registro incrementale xdi 1] nel registro i.
  3. Memorizza il codice [esegui registro u, incrementa registro m, quindi esegui registro zse il registro mè maggiore del registro n] nel registro z.
  4. Impostare la scala su 5 punti decimali.

  5. Leggi il numero di punti da campionare dalla prima riga di input.
  6. Eseguire il registro z.
  7. Dividi il registro x(il numero di risultati) per registro n(il numero di punti), moltiplica il risultato per 4 e stampa.
  8. Smettere.

Tuttavia, ho tradito:

Il programma richiede una fornitura di float casuali tra 0 e 1.

/* frand.c */
#include <u.h>
#include <libc.h>

void
main(void)
{
    srand(time(0));

    for(;;)
        print("%f\n", frand());
}

Uso:

#!/bin/rc
# runpi <number of samples>

{ echo $1; frand } | dc pi.dc

Prova:

% runpi 10000
3.14840

Ora con meno imbrogli (100 byte)

Qualcuno ha sottolineato che potrei includere un semplice prng.
http://en.wikipedia.org/wiki/RANDU

[lrx2^lrx2^+1>i]su[lx1+sx]si[luxlm1+dsmln>z]sz[0kls65539*2 31^%dsslkk2 31^/]sr?sn5dksk1sslzxlxlm/4*p

Ungolfed

[
Registers:
u - routine : execute i if sum of squares less than 1
i - routine : increment register x
z - routine : iterator - execute u while n > m++
r - routine : RANDU PRNG
m - variable: number of samples
x - variable: number of samples inside circle
s - variable: seed for r
k - variable: scale for division
n - variable: number of iterations (user input)
]c
[lrx 2^ lrx 2^ + 1>i]su
[lx 1+ sx]si
[lu x lm 1+ d sm ln>z]sz
[0k ls 65539 * 2 31^ % d ss lkk 2 31 ^ /]sr
? sn
5dksk
1 ss
lzx
lx lm / 4*
p

Prova:

$ echo 10000 | dc pigolf.dc
3.13640

1

Pyth, 19

c*4sm<sm^OQ2 2*QQQQ

Fornire il numero desiderato di iterazioni come input.

Dimostrazione

Dato che Pyth non ha una funzione "Numero mobile casuale", ho dovuto improvvisare. Il programma sceglie due numeri interi casuali positivi in ​​meno dell'input, dei quadrati, delle somme e confrontati con l'input al quadrato. Ciò è stato eseguito un numero di volte uguale all'input, quindi il risultato viene moltiplicato per 4 e diviso per l'input.

Nelle notizie correlate, aggiungerò tra breve un'operazione di numero in virgola mobile casuale a Pyth. Questo programma non utilizza questa funzionalità, tuttavia.


Se interpretiamo "Il risultato può essere restituito o stampato come punto mobile, punto fisso o numero razionale". liberamente, quindi stampare il numeratore e il denominatore della frazione risultante dovrebbe essere sufficiente. In quel caso:

Pyth, 18 anni

*4sm<sm^OQ2 2*QQQQ

Questo è un programma identico, con l'operazione di divisione in virgola mobile ( c) rimossa.


1

Julia, 37 byte

4mean(1-floor(sum(rand(4^8,2).^2,2)))

Il numero di campioni è 65536 (= 4 ^ 8).

Una variante leggermente più lunga: una funzione con numero di campioni scome unico argomento:

s->4mean(1-floor(sum(rand(s,2).^2,2)))

1

C, 130 byte

#include<stdlib.h>f(){double x,y,c=0;for(int i=0;i<8e6;++i)x=rand(),y=rand(),c+=x*x+y*y<1.0*RAND_MAX*RAND_MAX;printf("%f",c/2e6);}

Ungolfed:

#include <stdlib.h>
f(){
 double x,y,c=0;
 for(int i=0; i<8e6; ++i) x=rand(), y=rand(), c+=x*x+y*y<1.0*RAND_MAX*RAND_MAX;
 printf("%f",c/2e6);
}

ovviamente, probabilmente dovresti comunque pubblicare la versione senza spazi bianchi (mantieni la versione corrente con l'intestazione "ungolfed / with whitespace" o qualcosa del genere)
Destructible Lemon

@DestructibleWatermelon done!
Karl Napf,

La soluzione non funziona in GCC senza una nuova riga prima f(). Quale compilatore hai usato? Vedi tio.run/##Pc49C4JAHIDx3U9xGMG9ZdYgwWkgtNbQ1BZ6L/UHO8M07hA/…
eush77


1

In realtà , 14 byte (non concorrenti)

`G²G²+1>`nkæ4*

Provalo online!

Questa soluzione non è competitiva perché la lingua post-data la sfida. Il numero di campioni viene fornito come input (piuttosto che hardcoded).

Spiegazione:

`G²G²+1>`nkæ4*
`G²G²+1>`n      do the following N times:
 G²G²+            rand()**2 + rand()**2
      1>          is 1 greater?
          kæ    mean of results
            4*  multiply by 4

2
Perché il downvote?
Destructible Lemon,

1

Racchetta 63 byte

Utilizzando il metodo di risposta in lingua R di @Matt:

(/(for/sum((i n))(define a(/(random 11)10))(/ 4(+ 1(* a a))))n)

Ungolfed:

(define(f n)
   (/
    (for/sum ((i n))
      (define a (/(random 11)10))
      (/ 4(+ 1(* a a))))
    n))

test:

(f 10000)

Uscita (frazione):

3 31491308966059784/243801776017028125

Come decimale:

(exact->inexact(f 10000))

3.13583200307849

1

Fortran (GFortran) , 84 83 byte

CALL SRAND(0)
DO I=1,4E3
X=RAND()
Y=RAND()
IF(X*X+Y*Y<1)A=A+1E-3
ENDDO
PRINT*,A
END

Provalo online!

Questo codice è scritto molto male. Fallirà se gfortran deciderà di inizializzare la variabile Acon un valore diverso da 0 (che si verifica approssimativamente il 50% delle compilazioni) e, se Aviene inizializzato come 0, genererà sempre la stessa sequenza casuale per il seme dato. Quindi, lo stesso valore per Pi viene stampato sempre.

Questo è un programma molto migliore:

Fortran (GFortran) , 100 99 byte

A=0
DO I=1,4E3
CALL RANDOM_NUMBER(X)
CALL RANDOM_NUMBER(Y)
IF(X*X+Y*Y<1)A=A+1E-3
ENDDO
PRINT*,A
END

Provalo online!

(Un byte salvato in ogni versione; grazie Penguino).


1
In ogni versione è possibile salvare un byte modificando 'DO I = 1,1E3' in 'DO I = 1,4E3', cambiando 'A = A + 1' in 'A = A + 1E-3' e cambiando ' STAMPA *, A / 250 'a' STAMPA *, A '
Penguino

Sì, sei sicuro! Grazie per il suggerimento!
rafa11111,

1

Japt , 26 o 18 byte

o r_+ÂMhMr p +Mr p <1Ã*4/U

Provalo online!

Analogo alla risposta di Optimizer , principalmente solo cercando di imparare Japt.
Prende il numero di iterazioni da eseguire come input implicito U.

o                           Take the input and turn it into a range [0, U),
                            essentially a cheap way to get a large array.
  r_                        Reduce it with the default initial value of 0.
    +Â                      On each iteration, add one if
      MhMr p +Mr p          the hypotenuse of a random [0,1)x[0,1) right triangle
                   <1       is smaller than one.
                     Ã*4/U  Multiply the whole result by four and divide by input.

Se 1/(1+x^2)è consentito (invece di due randoms separati), possiamo ottenere 18 byte con la stessa logica.

o r_Ä/(1+Mr pÃ*4/U

1
Puoi salvare qualche byte lasciando Mhcalcolare l'ipotenusa piuttosto che farlo da solo ;-) Inoltre, puoi usare xper prendere la somma di un array, piuttosto che ridurlo per addizione:o x@MhMr Mr)<1Ã*4/U
ETHproductions

@ETHproductions Bene, non sapevo che si potesse usare Mhcosì, grazie! La tua risposta a due casuali è quasi breve quanto la mia risposta con un solo casuale, è piuttosto interessante. Terrò xa mente, tendo a usare molto la riduzione quando provo a giocare a golf, quindi questo sarà molto utile.
Nit

1

F #, 149 byte

open System;
let r=new Random()
let q()=
 let b=r.NextDouble()
 b*b
let m(s:float)=(s-Seq.sumBy(fun x->q()+q()|>Math.Sqrt|>Math.Floor)[1.0..s])*4.0/s

Provalo online!

Per quanto ne so, per fare questo tipo di totale parziale in F # è più breve creare una matrice di numeri e usare il Seq.sumBy metodo piuttosto che usare un for..to..doblocco.

Ciò che questo codice fa che crea una raccolta di numeri in virgola mobile da 1 a s, esegue la funzione fun x->...per il numero di elementi nella raccolta e somma il risultato. Ci sono selementi nella raccolta, quindi il test casuale viene eseguito svolte. I numeri effettivi nella raccolta vengono ignorati ( fun x->ma xnon vengono utilizzati).

Significa anche che l'applicazione deve prima creare e riempire l'array e quindi iterare su di esso. Quindi probabilmente è due volte più lento di un for..to..doloop. E con la memoria di creazione dell'array l'utilizzo è nella regione di O (f ** k)!

Per il test vero e proprio, invece di usare if then elseun'istruzione ciò che fa è che calcola la distanza ( q()+q()|>Math.Sqrt) e la arrotonda per difetto Math.Floor. Se la distanza è all'interno del cerchio, verrà arrotondata per difetto a 0. Se la distanza è al di fuori del cerchio, verrà arrotondata per difetto a 1. Il Seq.sumBymetodo sommerà quindi questi risultati.

Nota quindi che ciò che Seq.sumByha totalizzato non sono i punti all'interno del cerchio, ma i punti al di fuori di esso. Quindi per il risultato ci vuole s(la nostra dimensione del campione) e sottrae il totale da esso.

Sembra anche che prendere una dimensione del campione come parametro sia più breve di codificare il valore. Quindi sto barando un po '...


1

Haskell, 116 114 110 96 byte

d=8^9
g[a,b]=sum[4|a*a+b*b<d*d]
p n=(sum.take(floor n)$g<$>iterate((\x->mod(9*x+1)d)<$>)[0,6])/n

Poiché occuparsi import System.Random; r=randoms(mkStdGen 2)richiederebbe troppi byte preziosi, io generi un infinito elenco di numeri casuali con il generatore di congruenza lineare che alcuni dicono sia quasi crittograficamente forte: di x↦x*9+1 mod 8^9cui il Teorema di Hull-Dobell ha l'intero periodo di 8^9.

gproduce 4se il punto di numero casuale è all'interno del cerchio per coppie di numeri casuali [0..8^9-1]perché ciò elimina una moltiplicazione nella formula utilizzata.

Uso:

> p 100000
3.14208

Provalo online!


1

Perl 5, 34 byte

$_=$a/map$a+=4/(1+(rand)**2),1..$_

Il numero di campioni viene prelevato dallo stdin. Richiede -p.

Funziona perché:

Provalo online!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.