Calcola le cifre di Pi


15

Questo è un compito un po 'diverso. Calcola 1024 cifre esadecimali di π, iniziando dalla 1024a posizione esadecimale.

Formalmente: il programma dovrebbe essere completato in meno di 1 minuto e produrre il seguente output:

25d479d8f6e8def7e3fe501ab6794c3b976ce0bd04c006bac1a94fb6409f60c45e5c9ec2196a246368fb6faf3e6c53b51339b2eb3b52ec6f6dfc511f9b30952ccc814544af5ebd09bee3d004de334afd660f2807192e4bb3c0cba85745c8740fd20b5f39b9d3fbdb5579c0bd1a60320ad6a100c6402c7279679f25fefb1fa3cc8ea5e9f8db3222f83c7516dffd616b152f501ec8ad0552ab323db5fafd23876053317b483e00df829e5c57bbca6f8ca01a87562edf1769dbd542a8f6287effc3ac6732c68c4f5573695b27b0bbca58c8e1ffa35db8f011a010fa3d98fd2183b84afcb56c2dd1d35b9a53e479b6f84565d28e49bc4bfb9790e1ddf2daa4cb7e3362fb1341cee4c6e8ef20cada36774c01d07e9efe2bf11fb495dbda4dae909198eaad8e716b93d5a0d08ed1d0afc725e08e3c5b2f8e7594b78ff6e2fbf2122b648888b812900df01c4fad5ea0688fc31cd1cff191b3a8c1ad2f2f2218be0e1777ea752dfe8b021fa1e5a0cc0fb56f74e818acf3d6ce89e299b4a84fe0fd13e0b77cc43b81d2ada8d9165fa2668095770593cc7314211a1477e6ad206577b5fa86c75442f5fb9d35cfebcdaf0c7b3e89a0d6411bd3ae1e7e4900250e2d2071b35e226800bb57b8e0af2464369bf009b91e5563911d59dfa6aa78c14389d95a537f207d5ba202e5b9c5832603766295cfa911c819684e734a41b3472dca7b14a94a

Vince il programma con la durata più breve. Devi calcolare tutte le cifre in fase di esecuzione. Non è necessario implementare l'algoritmo che calcola π; se la tua lingua fornisce già tale funzionalità, puoi usarla.


Ah, dovrebbe essere facile. (+1, ancora) Scommetto che posso farlo eseguire in meno di pochi secondi.
Mateen Ulhaq,

@muntoo: E? Dov'è la tua soluzione?
FUZxxl

Ho dimenticato di farlo. :) A proposito, velocità! = Code-golf.
Mateen Ulhaq,

@muntoo: lo so. Ma penso anche che 5 giorni siano un buon momento per un compito così semplice.
FUZxxl,

Risposte:


13

Salvia, 29 caratteri

Questo non è tecnicamente imbroglio, poiché le cifre vengono calcolate in fase di esecuzione. Detto questo, è ancora economico da morire.

hex(floor(pi*2^8192))[1025:]

1
Sicuramente non barare.
FUZxxl,

11
Mmmm, piano pi.
breadbox,

13

Utilità Shell: 48

curl -sL ow.ly/5u3hc|grep -Eom 1 '[a-f0-9]{1024}'

  • Tutto l'output viene "calcolato" in fase di esecuzione. (grazie a OP che pubblica la soluzione)
  • Corre tra meno di un minuto. (potrebbe dipendere dalla velocità della tua connessione Internet)

Di solito declasso questo tipo di soluzioni, perché sono un abuso comune delle regole e non sono più divertenti. Ma solo perché sei così subdolo da prendere la soluzione di riferimento fornita e scrivere Tutto l'output viene "calcolato" in fase di esecuzione. (grazie a OP che pubblica la soluzione) , ti do un voto;)
FUZxxl

Versione golfizzata: curl -sL ow.ly/shKGY|grep -Po \\w{99,}(37). Funziona in Dash. Bash avrebbe bisogno di un byte aggiuntivo.
Dennis,

6

J, 156, 140, 137 127

d=:3 :'1|+/4 _2 _1 _1*+/(y&(16^-)%1 4 5 6+8*])"0 i.y+9'
,1([:}.'0123456789abcdef'{~[:|.[:<.[:(],~16*1|{.)^:8 d)"0\1024x+8*i.128

Utilizzando la formula BBP.

Does NON eseguito in meno di un minuto (ma abbiamo una J risposta: p)

Esempio per le prime 104 cifre di π (questo corre veloce):

,1([:}.'0123456789abcdef'{~[:|.[:<.[:(],~16*1|{.)^:8 d)"0\8*i.13x

243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c89
452821e638d01377be5466cf34e90c6cc0ac29b7

Perché non usi #: per convertire i numeri in esadecimali?
FUZxxl,

Non sono sicuro di cosa intendi. #:non genererà cifre esadecimali.
Eelvex,

IMHO è più facile da usare #: e un rimodellamento per generare cifre esadecimali rispetto al tuo approccio attuale.
FUZxxl,

Intendi qualcosa del genere (... 16 #:) Pi? Penso che non abbiamo abbastanza cifre, quindi dobbiamo comunque generarle.
Eelvex,

1
A proposito, ho scoperto che esiste il verbo hfdper convertire i numeri in esadecimali.
FUZxxl,

5

JavaScript, 536

(Interruzioni di riga e rientri solo per leggibilità)

var d='0123456789abcdef',p='',o='',l=3e3,c=0,e='length';d=d+d;
function $(n,r){return n[e]<=r?0:d.indexOf(n[r])}
function g(a,b){for(i=0,t='',s=16;i<l;i++,t+=d[~~(s/b)],s=(s%b)*16);
for(;a--;t=_(t,t,1));return t}
function _(a,b,s){for(i=(a[e]>b[e]?a[e]:b[e])-1,r='',c=0;i>=0;r=(s?
  function(k){c=k>15;return d[k]}($(a,i)+$(b,i)+c):
  function(k){c=k<0;return d[k+16]}($(a,i)-$(b,i)-c))+r,i--);return r}
for(i=0;i<l;i++,p+='2');
for(j=1;j<l;p=_(p,(o+='0')+_(_(_(g(2,8*j+1),g(1,8*j+4)),g(0,8*j+5)),g(0,8*j+6)),1),j++);
console.log(p.slice(1024,2048))

Ci vogliono circa 25 secondi, su Google Chrome 14 sul mio laptop usando Intel i5 core. Qualcun altro può giocare a golf questo codice? Non so giocare a golf bene .. :(

Di seguito è non golf. Ho appena rimosso tutti i commenti e modificato per passare al golf.

Non menzionarlo for(;s>=b;s-=b);s*=16;. L'ho cambiato in s=(s%b)*16. : P

/**
Calculate PI-3 to 3000 (3e3) digits.
a : a
b : b
c : carry
d : digits
e : length
f : get from d
g : calculate (2^a)/b.
i,j, : for looping
l : length to calculate
p : pi
r,t : return value
*/
var d='0123456789abcdef',p='',o='',l=3e3,c=0,e='length';
d=d+d;//for carring

function $(n,r){return n[e]<=r?0:d.indexOf(n[r])}
/*
Calculate (2^a)/b. Assume that 2^a < b.
*/
function g(a,b){
    for(i=0,t='',s=16;i<l;i++){t+=d[~~(s/b)];for(;s>=b;s-=b);s*=16;}
    for(;a--;t=_(t,t,1));return t}
/*
Calculate a±b. (+ when s=1, - when s=0) When calculating minus, assume that 1>b>a>0.
*/
function _(a,b,s){
    for(i=(a[e]>b[e]?a[e]:b[e])-1,r='',c=0;i>=0;
        r=(s?function(k){c=k>15;return d[k]}($(a,i)+$(b,i)+c):
            function(k){c=k<0;return d[k+16]}($(a,i)-$(b,i)-c))+r,i--);return r;
}
/*
Using BBP formula. Calc when j=0...
4/1 - 2/4 - 1/5 - 1/6 = 3.22222222.... (b16)
*/
for(i=0;i<l;i++,p+='2');
//Calc when j>0
for(j=1;j<l;p=_(p,(o+='0')+_(_(_(g(2,8*j+1),g(1,8*j+4)),g(0,8*j+5)),g(0,8*j+6)),1),j++);
console.log(p.slice(1024,2048));

EDIT: funzione totalmente inutilizzata rimossa. (Perché l'ho tenuto?: /)

PS. Prime 100 cifre di PI

243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c89452821e638d01377be5466cf34e90c6cc0ab


@FUZxxl: il codice non golfato non era abbastanza? .. :(
JiminP

Lo era davvero. Ma IMHO ha un aspetto migliore, se si utilizza la formattazione del codice anziché utilizzare la sintassi backtick. Come ho scritto, sentiti libero di tornare se non ti piace.
FUZxxl

d='0123456789abcdef',l=3e3,p=Array(l+1).join(2),o='',c=0,e='length';d+=d;function _(a,b,s){for(i=(a[e]>b[e]?a[e]:b[e])-1,r='',c=0;i+1;r=d[Z=F(b,i,1)+c,k=F(a,i,1)+(s?Z:16-Z),c=s?k>15:k<16,k]+r,i--);return r}function F(a,b,f){if(f)f=a[e]>b?d.indexOf(a[b]):0;else{for(i=0,f='',s=16;i++<l;f+=d[~~(s/b)],s=(s%b)*16);while(a--)f=_(f,f,1)}return f}for(j=0;++j<l;p=_(p,(o+='0')+_(_(_(F(2,z=8*j+1),F(1,z+3)),F(0,z+4)),F(0,z+5)),1));console.log(p.slice(1024,2048))
Peter Taylor,

Sono davvero tutte micro-ottimizzazioni, anche se alcune sembrano piuttosto grandi. Il più grande risparmio deriva dall'eliminazione delle due funzioni anonime nel mezzo _a favore ,dell'operatore. La più complicata è la fusione di $e gin una funzione, con un argomento facoltativo per selezionarle. functione returnsono entrambi piuttosto costosi, quindi un if(f)...elsepaio di ,1è un compromesso ragionevole.
Peter Taylor,

4

PHP 116 114 byte

<?for(;$g?$d=0|($$g=$g--/2*$d+($$g?:2)%$g*$f)/$g--:4613^printf($i++>257?'%04x':'',$e+$d/$f=4*$g=16384)^$e=$d%$f;);

Questa soluzione calcola tutte le cifre esadecimali fino a 2048, quattro cifre esadecimali alla volta e ne genera l'ultima metà. Il tempo di esecuzione è inferiore a 5 secondi. La formula utilizzata per il calcolo è la seguente:

pi = 2 + 1/3*(2 + 2/5*(2 + 3/7*(2 + 4/9*(2 + 5/11*(2 + 6/13*(2 + 7/15*(2 + ... )))))))

La precisione si ottiene memorizzando i resti in un array e continuando in modo incrementale ciascuna delle 2 ^ 14 divisioni.

Python 64 byte

x=p=16385
while~-p:x=p/2*x/p+2*2**8192;p-=2
print('%x'%x)[1025:]

Stesso metodo di cui sopra. Funziona in circa 0,2 secondi.

O come una riga in 73 byte :

print('%x'%reduce(lambda x,p:p/2*x/p+2*2**8192,range(16387,1,-2)))[1025:]

3

PARI / GP-2.4, 141

forstep(d=1024,2047,8,y=frac(apply(x->sum(k=0,d+30,16^(d-k)/(8*k+x)),[1,4,5,6])*[4,-2,-1,-1]~);for(i=0,7,y=16*frac(y);printf("%X",floor(y))))

Usando la formula Bailey – Borwein – Plouffe (ovviamente).

Funziona bene in meno di un minuto.


3

Codice C:

long ki,k,e,d=1024;
int  dig,tD=0,c,Co=0,j,js[4]  ={1,4,5,6};
double res=0.0,tres=0.0,gT,ans[4] ={0.0};
while(tD < 1024)
{while(Co<4){ j= js[Co],gT=0.0,ki= 0;
 for(; ki < d+1;ki++){ k = 8*ki+j,e= d-ki,c=1; while(e--) c = 16*c % k; gT+=((double)(c)/(double)k);}
 ans[Co] = (gT - (int)gT),++Co;}
 double gA = 4*ans[0]-2*ans[1]-ans[2]-ans[3];
 gA = (gA<0) ? gA + -1*(int)gA +1 : gA -(int)gA;
 dig=0;while(dig++ < 6 && tD++ < 1024) gA *=16, printf("%X",gA),gA -= (int)gA;
 d+=6,Co = 0;}

tempo di esecuzione = 8,06 secondi su un quad core Intel


Questo è il codice golf. Prova a comprimere il codice il più possibile usando nomi di variabili brevi ed evitando spazi bianchi. Ad esempio, è possibile salvare molti caratteri utilizzando printf("%X",(int)gA)invece di quel lungo elenco.
FUZxxl,

1

PARI / GP - 40 byte

Questa versione "tradisce" usando \xper visualizzare le cifre esadecimali del risultato.

\p8197
x=Pi<<4^6;x-=x\1;x=(x<<4^6)\1
\xx

Questa versione richiede 87 byte per la conversione in esadecimale nel solito modo.

\p8197
x=Pi<<4^6;x-=x\1;concat([Vec("0123456789abcdef")[n+1]|n<-digits((x<<4^6)\1,16)])

Entrambe le versioni funzionano in una piccola frazione di secondo.


1

Perl - 59

use ntheory"Pi";say substr int(Pi(3000)<<8192)->as_hex,1027

Meno di 0,1 s.


0

Shell 68

strumenti: bc -l, tr, cut

echo "scale=2468;obase=16;4*a(1)"|bc -l|tr -d '\\\n'|cut -c1027-2051

Shell 64, strumenti: bc -l, tr, tail, differisce nell'arrotondamento dell'ultimo posto

echo "scale=2466;obase=16;4*a(1)"|bc -l|tr -d '\\\n'|tail -c1024

Potrebbe essere considerato un imbroglio, poiché la conoscenza su come calcolare PI è in 4 * a (1), e che 1 deve usare scale = 2466 è stato studiato in modo iterativo.

Grazie a breadbox per l'idea di usare il taglio.


Non vedo come si possa considerare un imbroglio; le cifre vengono calcolate in fase di esecuzione. Anche se dovrei notare che quando lo eseguo, l'output differisce sull'ultima cifra (7 invece di A). A proposito, penso che puoi sostituire il ddcomando con tail -c1024per salvare alcuni caratteri.
breadbox,

Sì, ho osservato anche la differenza (e ci dedico mezz'ora :)). Se dico a bc di usare una scala di x cifre, si arrotonda a quella cifra in modalità decimale e successivamente esegue la conversione esadecimale. Quindi, se prendo un'altra cifra, produce un 69, non un 7. Tuttavia, lo stile di arrotondamento o il troncamento non sono stati specificati nella domanda. E grazie per l'idea della coda. :)
utente sconosciuto

La domanda specifica: termina e produce un output in modo identico a quanto specificato.
FUZxxl,

@FUZxxl: "should ...", not "must ..." - Ho pensato che dovesse essere di aiuto controllare se la conversione esadecimale sta andando bene e il conteggio dei caratteri da saltare, non come parte delle specifiche , per conformarmi all'ultima cifra di 1024. Ma ho ceduto e ho aggiunto 16 caratteri per sostituirne uno.
utente sconosciuto

1
Dato che la frase inizia con la parola "Formalmente", concordo sul fatto che l'OP probabilmente la intendesse nel senso della parola RFC . Inoltre, puoi ancora migliorare la tua nuova soluzione sostituendo l'uso di ddcon cut -c1027-2051. (La shell ha molti strumenti per manipolare i flussi di testo.)
breadbox
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.