Teoricamente ha prodotto il numero di Graham


44

Il numero di Graham Gè definito in questo modo:

u(3,n,1) = 3^n
u(3,1,m) = 3
u(3,n,m) = u(3,u(3,n-1,m),m-1)
[Knuth's up-arrow notation]
[Conway chained arrow notation]

THEN

g1 = u(3,3,4)
g2 = u(3,3,g1)
g3 = u(3,3,g2)
...
G = u(3,3,g63)

Ti viene dato questo u(3,3,2)=7625597484987per controllare il tuo codice.

Il tuo compito è quello di scrivere un programma / funzione che genererà il valore di Gdeterministicamente, data la dimensione intera sufficiente e il tempo sufficiente.

Riferimenti

Classifica



7
È consentita la casualità? Se ho appena emesso valori casuali, alla fine deve essere prodotto il numero di Graham.
miglia,

15
@miles Perché mai non è già una scappatoia standard? Chiarito.
Leaky Nun,

18
Avviso: u (3, 3, 2) = u (3, 2, 3) = 7625597484987, quindi ti consigliamo di testare anche altri valori come u (3, 5, 1) = 243 per assicurarti di avere l'ordine degli argomenti è giusto.
Anders Kaseorg,

Risposte:


48

Calcolo lambda binario , 114 bit = 14,25 byte

hexdump:

00000000: 4457 42b0 2d88 1f9d 740e 5ed0 39ce 80    DWB.-...t.^.9..

Binario:

010001000101011101000010101100000010110110001000000111111001110101110100000011100101111011010000001110011100111010

Spiegazione

01 00                                           (λx.
│    01 00                                        (λy.
│    │    01 01 01 110                              x
│    │    │  │  └─ 10                               y
│    │    │  └─ 00                                  (λm.
│    │    │       01 01 01 10                         m
│    │    │       │  │  └─ 00                         (λg.
│    │    │       │  │       00                         λn.
│    │    │       │  │         01 01 10                  n
│    │    │       │  │         │  └─ 110                 g
│    │    │       │  │         └─ 00                     (λz.
│    │    │       │  │              10                     z))
│    │    │       │  └─ 00                            (λn.
│    │    │       │       00                            λf.
│    │    │       │         01 111110                    x
│    │    │       │         └─ 01 110                    (n
│    │    │       │            └─ 10                      f))
│    │    │       └─ 1110                             x)
│    │    └─ 10                                     y)
│    └─ 00                                        (λf.
│         00                                        λz.
│           01 110                                   f
│           └─ 01 01 1110                            (x
│              │  └─ 110                              f
│              └─ 10                                  z)))
└─ 00                                           (λf.
     00                                           λz.
       01 110                                      f
       └─ 01 110                                   (f
          └─ 01 110                                 (f
             └─ 10                                   z)))

Questo è (λ x . (Λ y . X ym . Mg . Λ n . N g 1) (λ n . Λ f . X ( n f )) x ) y ) (λ f . Λ z . f ( x f z ))) 3, dove tutti i numeri sono rappresentati come numeri di Church. I numeri di chiesa sono la rappresentazione standard del calcolo lambda dei numeri naturali e sono adatti a questo problema perché un numero di chiesa è definito dall'iterazione della funzione: n g è l' iterata n della funzione g .

Ad esempio, se g è la funzione λ n . λ f . 3 ( n f ) che moltiplica 3 per un numero di Church, quindi λ n . n g 1 è la funzione che porta 3 alla potenza di un numero Chiesa. Iterare questa operazione m volte dà

mg . λ n . n g 1) (λ n . λ f . 3 ( n f )) n = u (3, n , m ).

(Usiamo la moltiplicazione u (-, -, 0) anziché esponenziazione u (-, -, 1) come caso base, perché sottrarre 1 da un numero della Chiesa è sgradevole .)

Sostituto n = 3:

mg . λ n . n g 1) (λ n . λ f . 3 ( n f )) 3 = u (3, 3, m ).

Iterando tale operazione 64 volte, a partire da m = 4, si ottiene

64 (λ m . Mg . Λ n . N g 1) (λ n . Λ f . 3 ( n f )) 3) 4 = G .

Per ottimizzare questa espressione, sostituire 64 = 4 ^ 3 = 3 4:

3 4 (λ m . Mg λ. N . N g 1) (λ n . Λ f . 3 ( n f )) 3) 4 = G .

Ricorda 4 = succ 3 = λ f . λ z . f (3 f z ) come argomento lambda:

y . 3 ym . mg . λ n . n g 1) (λ n . λ f . 3 ( n f )) 3) y ) (λ f . λ z . f (3 f z )) = G .

Infine, ricorda 3 = λ f . λ z . f ( f ( f z )) come argomento lambda:

x . (λ y . x ym . mg . λ n . n g 1) (λ n . λ f . x ( n f )) x ) y ) (λ f . λ z . f ( x f z ))) 3 = G .


Dove si potrebbe trovare un interprete per questa lingua?
Dennis,


1
Questo è impressionante . questo merita una taglia generosa
gatto,

1
14.25 bytessembra incasinare la classifica. Viene analizzato come 25 bytes, e quindi sei posizionato come secondo.
Dan,

1
@Dan Ho riparato lo snippet della classifica, credo.
Anders Kaseorg,

40

Haskell, 41 byte

i=((!!).).iterate
i(($3).i(`i`1)(*3))4 64

Spiegazione:

(`i`1)f n= i f 1 ncalcola l' niterata della funzione a fpartire da 1. In particolare, (`i`1)(*3)n= 3 ^ n , e ripetendo questa costruzione m volte dà i(`i`1)(*3)m n= u (3, n , m ). Possiamo riscriverlo come (($n).i(`i`1)(*3))m= u (3, n , m ) e iterare questa costruzione k volte per ottenere i(($3).i(`i`1)(*3))4 k= g _ k .


16

Haskell, 43 byte

q=((!!).).iterate
g=q(`q`1)(3*)
q(`g`3)4$64

C'è un modo migliore per capovolgere la glinea.

46 byte:

i=iterate
n%0=3*n
n%m=i(%(m-1))1!!n
i(3%)4!!64

48 byte:

n%1=3^n
1%m=3
n%m=(n-1)%m%(m-1)
iterate(3%)4!!64

Basta scrivere le definizioni.

I casi di base hanno un backup un po 'più pulito fino a 0, anche se non salva byte. Forse renderà più facile scrivere una definizione alternativa.

n%0=3*n
0%m=1
n%m=(n-1)%m%(m-1)
z=iterate(3%)2!!1

Puoi usare un'altra funzione che ha una precedenza inferiore a +quella per rimuovere le parentesi tra m-1?
Leaky Nun,

Conto 44 byte, e cosa è successo a 4 e 64?
Leaky Nun,

Oops, ho copiato nel mio test con parametri più piccoli. Non penso di poter cambiare la precedenza dell'operatore perché sto definendo una nuova funzione e quelle hanno una precedenza predefinita. Non riesco a sovrascrivere una funzione esistente.
xnor

Voglio dire, conto 44 byte dopo averlo modificato di nuovo a 64.
Leaky Nun,

Penso che tu intenda (`g`3), no (3`g`).
Anders Kaseorg,

10

Pyth, 25 byte

M?H.UgbtH*G]3^3Gug3tG64 4

La prima parte M?H.UgbtH*G]3^3Gdefinisce un metodo g(G,H) = u(3,G,H+1).

Per provare la prima parte, verificare che 7625597484987=u(3,3,2)=g(3,1): g3 1.

La seconda parte ug3tG64 4inizia da r0 = 4e quindi calcola rn = u(3,3,r(n-1)) = g(3,r(n-1))64 volte, producendo il valore finale ( rviene scelto invece di gevitare confusione).

Per verificare questa parte, avviare da r0=2e quindi calcolare r1: ug3tG1 2.


Se g (G, H) = u (3, G, H + 1), dovresti avere r (n) = u (3, 3, r (n - 1)) = g (3, r (n - 1 ) - 1), non g (3, r (n - 1)). Penso che il tuo codice sia corretto ma alla tua spiegazione manca il - 1.
Anders Kaseorg il

È possibile salvare un byte utilizzando gli argomenti u non ^3impostati ( ↦ *3, tGG) e un altro byte con .UgbtH*G]3e.ugNtHG1.
Anders Kaseorg,

Un modo alternativo per salvare quel secondo byte è *G]3ShG.
Anders Kaseorg,

8

Sesos , 30 byte

0000000: 286997 2449f0 6f5d10 07f83a 06fffa f941bb ee1f33  (i.$I.o]...:....A...3
0000015: 065333 07dd3e 769c7b                              .S3..>v.{

smontato

set numout
add 4
rwd 2
add 64
jmp
    sub 1
    fwd 3
    add 3
    rwd 1
    add 1
    jmp
        sub 1
        jmp
            fwd 1
            jmp
                jmp
                    sub 1
                    fwd 1
                    add 1
                    rwd 1
                jnz
                rwd 1
                jmp
                    sub 1
                    fwd 3
                    add 1
                    rwd 3
                jnz
                fwd 3
                jmp
                    sub 1
                    rwd 2
                    add 1
                    rwd 1
                    add 1
                    fwd 3
                jnz
                rwd 1
                sub 1
            jnz
            rwd 1
            jmp
                sub 1
            jnz
            add 1
            rwd 1
            sub 1
        jnz
        fwd 1
        jmp
            sub 1
            rwd 1
            add 3
            fwd 1
        jnz
        rwd 2
    jnz
    rwd 1
jnz
fwd 2
put

O nella notazione Brainfuck:

++++<<++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
[->>>+++<+[-[>[[->+<]<[->>>+<<<]>>>[-<<+<+>>>]<-]<[-]+<-]>[-<+++>]<<]<]>>.

analisi

Per calcolare u (3, n , u (3, n , ... u (3, n , m ) ...)) con k chiamate nidificate per u , sostituire le prime tre addistruzioni add 4, add 64, add 3con add m, add k, add nrispettivamente. Poiché Sesos non può costruire numeri più velocemente che nel tempo lineare, sei praticamente limitato a piccoli valori come u (3, 2, 2) = 27, u (3, 5, 1) = 243 e u (3, 1 , u (3, 1,… u (3, 1, m )…)) = 3.


Puoi sostituirlo [-]con ,EOF 0.
mbomb007,

6

JavaScript (ES7), 63 byte

u=(n,m)=>n>1&m>1?u(u(n-1,m),m-1):3**n
g=n=>n?u(3,g(n-1)):4
g(64)

@AndersKaseorg Ugh, in quel caso potrei anche annullare quel cambiamento.
Neil,

Ciò provoca un overflow dello stack, potrebbe essere necessario ricontrollare il modello di ricorsione.
NodeNodeNode

Questo non è semplice ES7. Questo è ES7 illimitato (una variante immaginaria di ES7 ma con bignum, in grado di oracolare all'infinito e sta usando il decimale con / # xE ^ come scorciatoia).
user75200

5

Brachylog , 57 byte

4:64:1iw
:3{[1:N],3:N^.|t1,3.|hM:1-X,?t:1-:Mr:2&:Xr:2&.}.

Non si aspetta input né output e scrive il risultato in STDOUT. Ciò produrrà un overflow dello stack in un punto.

Per verificare che funzioni con valori piccoli (ad es. u(3,3,2)) Puoi sostituire 4il valore con me 64con 1.

Spiegazione

Questa è sostanzialmente un'implementazione diretta del modo spiegato di calcolare il numero.

  • Predicato principale:

    4:64:1i                    Call Predicate 1 64 times with 4 as initial input (the second
                               call takes the output of the first as input, etc. 64 times).
           w                   Write the final output to STDOUT
    
  • Predicato 1:

    :3{...}.                   Call predicate 2 with input [Input, 3]. Its output is the 
                               output of predicate 1.
    
  • Predicato 2:

    [1:N],                     M = 1
          3:N^.                Output = 3^N
    |                          Or
    t1,                        N = 1
       3.                      Output = 3
    |                          Or
    hM:1-X,                    X is M - 1
           ?t:1-:Mr:2&         Unify an implicit variable with u(3,N-1,M)
                      :Xr:2&.  Unify Output with u(3,u(3,N-1,M),X)
    

5

Caramello , 38 byte

(64 ((f->(f,1)),(n f->(3 (n f))),3) 4)

Questo è zucchero sintattico per l'espressione del calcolo lambda 64 (λ m . Mf . Λ n . N f 1) (λ n . Λ f . 3 ( n f )) 3) 4, dove tutti i numeri sono rappresentati come Chiesa numeri .


(n f->3 (n f))non dovrebbe leggere n-1?
Leaky Nun,

@LeakyNun No. (n f->3 (n f))è una funzione per la moltiplicazione per tre nei numeri della Chiesa .
Anders Kaseorg,

2
Questa sfida sembra eccessivamente semplice nel calcolo lambda. Perché?
gatto,

3

Prolog (SWIPL), 129/137 byte

g(1,R):-u(3,4,R).
g(L,R):-M is L-1,g(M,P),u(3,P,R).
u(N,1,R):-R is 3**N.
u(1,_,3).
u(N,M,R):-K is N-1,L is M-1,u(K,M,Y),u(Y,L,R).

Per generare il numero di Graham, g(64,G).eseguire una query per (se si devono contare gli 8 byte di questa query, la lunghezza è 137 byte):

?- g(64, G).
ERROR: Out of local stack

Ma come ci si può aspettare, questo si esaurisce.

Test

?- u(3, 2, X).
X = 7625597484987

Il backtracking fa sì che si esaurisca lo stack:

?- u(3, 2, X).
X = 7625597484987 ;
ERROR: Out of local stack

Ungolfed

La versione ungolf aggiunge la notazione generale con la freccia in su, non solo per 3, e usa tagli e controlli per evitare backtracking e situazioni indefinite.

% up-arrow notation
u(X, 1, _M, X) :- !.
u(X, N, 1, R) :-
    R is X**N, !.
u(X, N, M, R) :-
    N > 1,
    M > 1,
    N1 is N - 1,
    M1 is M - 1,
    u(X, N1, M, R1),
    u(X, R1, M1, R).

% graham's number
g(1,R) :- u(3, 3, 4, R), !.
g(L,R) :-
    L > 1,
    L1 is L - 1,
    g(L1,G1),
    u(3, G1, R).

Come sei riuscito a farlo senza avere il numero 64ovunque nel tuo codice?
Leaky Nun,

@LeakyNun Ho modificato per chiarire; meglio?
SQB,

Bene, quindi aggiungilo nel tuo codice e nel conteggio dei byte.
Leaky Nun,

3

C, 161 byte

u(int a, int b){if(a==1)return 3;if(b==1)return pow(3,a);return u(u(a-1,b),b-1);}
g(int a){if(a==1)return u(3,4);return u(3,g(a-1));}
main(){printf("%d",g(64));}

EDIT: salvato 11 byte rimuovendo le schede e le nuove righe. EDIT: grazie auhmann salvato un altro byte e risolto il mio programma


1
Potresti rimuovere g(int a){if(a==1)return u(3,4);return g(a-1);}dal momento che non viene utilizzato affatto ... O stai dimenticando qualcosa?
auhmaan,

@auhmaan oops mi dispiace, ho usato quel numero per i test e ho dimenticato di cambiarlo. Grazie!!
thepiercingarrow

Il tuo return g(a-1)dovrebbe essere return u(3,g(a-1)).
Anders Kaseorg,

1
Non so se dovrei dare una risposta corretta o semplicemente commentare questo, ma puoi ottenere questa soluzione fino a 114 byte abbastanza facilmente realizzando: Le nuove linee tra le funzioni possono essere omesse. Se si omettono i tipi per tutti gli argumen, vengono impostati automaticamente su int (si pensi a K&R). Se dichiarazioni come queste possono essere scritte con operazioni ternarie nidificate. Codice:u(a,b){return a<2?3:b<2?pow(3,a):u(u(a-1,b),b-1);}g(a){return a<2?u(3,4):u(3,g(a-1));}main(){printf("%d",g(64));}
algmyr,

@algmyr Eeeek !!! dovresti pubblicare la tua risposta XD.
thepiercingarrow,

2

Mathematica, 59 byte

n_ ±1:=3^n
1 ±m_:=3
n_ ±m_:=((n-1)±m)±(m-1)
Nest[3±#&,4,64]

Utilizza un operatore infix indefinito ±che richiede solo 1 byte se codificato in ISO 8859-1. Vedi il post di @ Martin per maggiori informazioni. Le funzioni di Mathematica supportano il pattern matching per i loro argomenti, in modo tale che i due casi base possano essere definiti separatamente.


1
Da quando Mathematica utilizza ISO 8859-1?
Leaky Nun,

n_ ±m_:=Nest[#±(m-1)&,3,n]
Leaky Nun,

2

C, 114 109 byte

Sulla base della risposta di @thepiercingarrow ( link ), ho risolto un po 'la risposta. La maggior parte dei risparmi è dovuta all'abuso della tipizzazione predefinita di argomenti quando si eseguono funzioni di stile K&R e alla sostituzione di istruzioni if ​​con operatori ternari. Aggiunti newline opzionali tra le funzioni per la leggibilità.

Migliorato a 109 grazie a @LeakyNun.

u(a,b){return a<2?3:b<2?pow(3,a):u(u(a-1,b),b-1);}
g(a){return u(3,a<2?4:g(a-1));}
main(){printf("%d",g(64));}

g(a){return u(3,a<2?4:g(a-1));}
Leaky Nun,

@LeakyNun È davvero bello. Grazie.
algmyr,

1

Python, 85 byte

v=lambda n,m:n*m and v(v(n-1,m)-1,m-1)or 3**-~n
g=lambda n=63:v(2,n and g(n-1)-1or 3)

La vfunzione definisce la stessa funzione di quello trovato nella risposta di Dennis : v(n,m) = u(3,n+1,m+1). La gfunzione è una versione zero indicizzata dell'iterazione tradizionale: g(0) = v(2,3), g(n) = v(2,g(n-1)). Quindi, g(63)è il numero di Graham. Impostando il valore predefinito del nparametro della gfunzione su 63, è possibile ottenere l'output richiesto chiamando g()(senza parametri), soddisfacendo così i nostri requisiti per l'invio di una funzione che non accetta input.

Verificare le v(2,1) = u(3,3,2)e v(4,0) = u(3,5,1)casi di test on-line: Python 2 , Python 3


1
È un po 'difficile da verificare, ma la tua funzione gsembra disattivata. Non dovrebbe v(2,n-1)essere g(n-1)o qualcosa di simile?
Dennis,

@Dennis Buona cattura. Lo aggiusterò.
Mego

In realtà l'offset tra ue vsignifica che dovrebbe essere g(n-1)-1.
Anders Kaseorg,

@AndersKaseorg Non dovrei fare la programmazione mentre ho sonno. Devo riapprenderlo ogni pochi giorni.
Mego

@AndersKaseorg In futuro, ti preghiamo di non modificare gli invii di altre persone, anche se si tratta di correggere un errore in un miglioramento / correzione che hai suggerito.
Mego

1

Dyalog APL, 41 byte

u←{1=⍺:3⋄1=⍵:3*⍺⋄(⍵∇⍨⍺-1)∇⍵-1}
3u 3u⍣64⊣4

Caso di prova:

      3u 2
7625597484987

Dovresti essere in grado di convertire 1=⍺:3⋄1=⍵:3*⍺in just 1=⍵:3*⍺( 3=3*1)
Zacharý


0

J, 107 byte

u=:4 :0
if.y=1 do.3^x
elseif.x=1 do.3
elseif.1 do.x:(y u~<:x)u<:y
end.
)
(g=:(3 u 4[[)`(3 u$:@<:)@.(1&<))64

Sto lavorando alla conversione uin un'agenda, ma per ora lo farà.


Qualcosa di simile u=:3^[`[:(3$:])/[#<:@]@.*@](non testato)
Leaky Nun,

0

F #, 111 108 byte

modificare

Questo sta usando la seguente funzione per confermare il numero di Graham

let rec u=function|b,1->int<|3I**b|1,c->3|b,c->u(u(b-1,c),c-1)
and g=function|1->u(3.,4.)|a->u(3.,g (a-1))
g 63

Ecco la mia risposta precedente che, beh, non ha:

Abbastanza diretto. Solo una definizione della ufunzione.

let rec u=function|a,b,1->a**b|a,1.,c->a|a,b,c->u(a,u(a,b-1.,c),c-1)

Uso:

u(3.,3.,2)
val it : float = 7.625597485e+12

Se assumessi 3 come valore per a, potrei tagliarlo a 60:

let rec u=function|b,1->3.**b|1.,c->3.|b,c->u(u(b-1.,c),c-1)

Uso:

u(3.,2)
val it : float = 7.625597485e+12

La sfida è scrivere il numero di Graham, no u. Ovviamente puoi includere qualsiasi funzione intermedia di cui hai bisogno, come ucon o senza il suo primo argomento fissato a 3.
Anders Kaseorg

@AndersKaseorg lo ha modificato in. Grazie. Il mio commento precedente sembra essere scomparso.
asibahi,

0

R, 154 142 128 126 118 byte

u=function(n,b)return(if(n&!b)1 else if(n)u(n-1,u(n,b-1))else 3*b)
g=function(x)return(u(if(x-1)g(x-1)else 4,3))
g(64)

Ho usato la definizione di Wikipedia di questa funzione ricorsiva perché per qualche strana ragione quella suggerita non ha funzionato ... o faccio schifo al golf.

UPD: rasato 12 + 14 = 26 byte grazie a un suggerimento di Leaky Nun . La versione precedente utilizzava l'ingombrante e meno efficiente

u=function(n,b)if(n==0)return(3*b)else if(n>0&b==0)return(1)else return(u(n-1,u(n,b-1)))
g=function(x)if(x==1)return(u(4,3))else return(u(g(x-1),3))

UPD: rasato altri 2 + 6 + 2 byte (di nuovo, complimenti a Leaky Nun ) a causa di una geniale sostituzione con "if (x)" invece di "if (x == 0)" perché x <0 non viene mai inserito la funzione ... giusto?


@LeakyNun Grazie, ho aggiornato la risposta con riconoscimento.
Andreï Kostyrka,

Solo un secondo ... Oggi è il mio primo giorno di golf a codice, c'è molto da imparare!
Andreï Kostyrka,

Sei invitato a unirti alla nostra chat .
Leaky Nun,

Più golf, si prega di vedere il miglioramento.
Andreï Kostyrka,

Ta-dam, fatto, ha cambiato la funzione ucon lo stesso tasto del tuo ge ha salvato altri 6 byte - fantastico!
Andreï Kostyrka,

0

PHP, 114 byte

ignora le interruzioni di riga; sono solo per leggibilità.

function u($n,$m){return$m>1&$n>1?u(u($n-1,$m),$m-1):3**$n;}
function g($x){return u(3,$x>1?g($x-1):4);}
echo g(63);

È possibile integrare il secondo caso nel primo: for n=1, 3^nuguale a 3.
Ciò consentirà di risparmiare alcuni byte su - per quanto posso vedere - tutte le risposte esistenti; salvato due byte sul mio

versione precedente, 62 + 43 + 11 = 116 byte

function u($n,$m){return$m>1?$n>1?u(u($n-1,$m),$m-1):3:3**$n;}

L'associatività sinistra del ternario da parte di PHP richiede parentesi ... o un ordine specifico di prove.
Ciò ha salvato due byte sull'espressione tra parentesi.


Probabilmente esiste un approccio iterativo, che può consentire un ulteriore gioco del golf ...
ma non posso prendermi il tempo adesso.


vorrei conoscere Sesos o aver avuto il tempo di impararlo e tradurre in questo momento
Tito

@Leaky Nun: l'ho suddiviso in soli loop e aggiunte. C'è un modo in Sesos per aggiungere il valore di una cella a un'altra?
Tito

@AndersKaseorg: Probabilmente hai ragione ... Ho avuto vesciche sui miei occhi guardando quell'algoritmo. Lo guarderò di nuovo presto.
Tito,
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.