La funzione Ackermann


35

La funzione di Ackermann è nota per essere uno degli esempi più semplici di una funzione totale e calcolabile che non è ricorsiva primitiva.

Useremo la definizione di A(m,n)prendere due interi non negativi dove

A(0,n) = n+1
A(m,0) = A(m-1,1)
A(m,n) = A(m-1,A(m,n-1))

È possibile implementare

  • una funzione nominata o anonima che accetta due numeri interi come input, che restituisce un numero intero o
  • un programma che prende due interi separati da spazio o newline su STDIN, stampando un risultato su STDOUT.

Non è possibile utilizzare una funzione di Ackermann o una funzione di iperesponenziazione da una libreria, se presente, ma è possibile utilizzare qualsiasi altra funzione di qualsiasi altra libreria. È ammessa l'espiazione regolare.

La tua funzione deve essere in grado di trovare il valore di A(m,n)per m ≤ 3 e n ≤ 10 in meno di un minuto. Dovrebbe almeno teoricamente terminare su qualsiasi altro input: dato lo spazio di stack infinito, un tipo di Bigint nativo e un periodo di tempo arbitrariamente lungo, restituirebbe la risposta. Modifica: se la tua lingua ha una profondità di ricorsione predefinita troppo restrittiva, puoi riconfigurarla senza alcun costo di carattere.

Vince l'invio con il minor numero di personaggi.

Ecco alcuni valori, per verificare la tua risposta:

  A  | n=0     1     2     3     4     5     6     7     8     9    10
-----+-----------------------------------------------------------------
 m=0 |   1     2     3     4     5     6     7     8     9    10    11
   1 |   2     3     4     5     6     7     8     9    10    11    12
   2 |   3     5     7     9    11    13    15    17    19    21    23
   3 |   5    13    29    61   125   253   509  1021  2045  4093  8189
   4 |  13 65533   big   really big...

15
Come mai non è stato chiesto prima ??
Calvin's Hobbies,

9
Penso che sarebbe più divertente realizzare questo codice più veloce
Sp3000,

22
Downvoting perché non c'è sfida qui. La risposta ovvia - l'implementazione ingenua della funzione esattamente secondo la sua definizione - sarà sempre la risposta migliore. Quindi la domanda è solo "Quale lingua ha il minor numero di caratteri nell'ovvia espressione della funzione di Ackermann?" Il vero vincitore è il linguaggio di programmazione, non la persona che ha scritto l'ovvio programma in esso.
David Richerby,

1
Che cosa succede se il limite di ricorsione della mia lingua è troppo basso per essere calcolato A(3,8)e superiore in modo ingenuo come gli altri? Devo trovare una soluzione di non ricorsione o in questi casi posso anche solo "assumere uno spazio di stack infinito"? Ne sono abbastanza certo, terminerebbe entro un minuto.
Martin Ender,

5
@DavidRicherby "La risposta ovvia [...] sarà sempre la risposta migliore." Questo non è vero per tutte le lingue. Mi sento un po 'sporco solo per avere un esempio nella mia lingua madre, ma ci sono diversi modi per esprimere Ackermann e in alcune lingue puoi ottenere risparmi usando questo fatto. Questa era la mia intenzione per la sfida.
algoritmo

Risposte:


7

Pyth , 19

DaGHR?atG?aGtHH1GhH

Definisce a, che funziona come la funzione di Ackermann. Si noti che ciò richiede una profondità di ricorsione superiore rispetto al compilatore ufficiale di pyth consentito fino ad oggi per il calcolo a 3 10, quindi ho aumentato la profondità di ricorsione. Questa non è una modifica alla lingua, ma solo al compilatore.

Test:

$ time pyth -c "DaGHR?atG?aGtHH1GhH           ;a 3 10"
8189

real    0m0.092s
user    0m0.088s
sys     0m0.000s

Spiegazione:

DaGH                     def a(G,H):
    R                    return
    ?          G                (if G:
     atG                              (a(G-1,
        ?    H                               (if H:
         aGtH                                      a(G,H-1)
              1                               else:1)
                hH               else:H+1)

In sostanza, per prima cosa condiziona il valore della verità Gse ricorrere o restituire H + 1. Se ricorre, il primo argomento è sempre G-1, e condiziona il valore di verità Hse usare a(G,H-1)come secondo argomento o usare 1come secondo argomento.


Nel moderno Pyth (suppongo che sia stato aggiunto dopo questa sfida) penso che tu possa più o meno cambiare DaGHRda Me averso g. (L'ordine degli argomenti per ?cambiare è cambiato?)
Lynn il

@Mauris Sì, è possibile utilizzare Minvece, e sì, l' ?ordine degli argomenti è cambiato. Ora è condizione, vero, falso. Era vero, condizione, falso.
isaacg,

@Lynn Fun Fatti sulla storia di Pyth: questa domanda ha effettivamente influenzato isaacg a cambiare (almeno) due cose su Pyth: il limite di ricorsione e il passaggio aM !
FryAmTheEggman

23

Haskell, 35 anni

0%n=1+n
m%n=iterate((m-1)%)1!!(n+1)

questo definisce la funzione dell'operatore %.

questo funziona notando che m%n(dove aè la funzione ackerman) per non zero mviene (m-1)%applicato n+1volte a 1. per esempio, 3%2è definito come 2%(3%1)è 2%(2%(3%0)), e questo è2%(2%(2%1))


0%nn+1
peccato


wow, questo è stato sbagliato per così tanto tempo, e nessuno, incluso me stesso, ha notato? buon lavoro. quindi sembra che ho copiato per errore la prima versione della risposta, che era difettosa, forse per errore o perché pensavo che funzionasse.
orgoglioso haskeller il

12

GolfScript (30)

{1$1>{1\){1$(\A}*\;}{+)}if}:A;

Demo online

Senza i 1>(quali casi speciali A(1, n)) ci vogliono 9 minuti per calcolare A(3, 10)sul computer su cui l'ho provato. Con quel caso speciale è abbastanza veloce che la demo online impiega meno di 10 secondi.

Nota che questa non è una traduzione ingenua della definizione. La profondità di ricorsione è limitata da m.

Dissezione

{             # Function boilerplate
  1$          # Get a copy of m: stack holds m n m
  1>{         # (Optimisation): if m is greater than 1
    1         #   Take this as the value of A(m, -1)
    \){       #   Repeat n+1 times:
              #     Stack: m A(m, i-1)
      1$(\    #     Stack: m m-1 A(m, i-1)
      A       #     Stack: m A(m, i)
    }*
    \;        #   Lose that unwanted copy of m
  }{          # Else
    +)        #   A(m in {0, 1}, n) = m + n + 1
  }if
}:A;          # Function boilerplate

In CJam, non ne avresti bisogno 1>. Dopo la rimozione (e il passaggio ifa ?), l'elaborazione 3 10 Arichiede 110 secondi con l'interprete online e sei secondi con l'interprete Java.
Dennis,

7

Calcolo lambda binario , 54 bit = 6,75 byte

hexdump:

00000000: 1607 2d88 072f 68                        ..-../h

Binario:

000101100000011100101101100010000000011100101111011010

Questo è λ m . mg . λ n . g ( n g 1)) (λ n . λ f . λ x . f ( n f x )), dove tutti i numeri sono rappresentati come numeri di Church .


6

JavaScript, ES6, 41 34 byte

f=(m,n)=>m?f(m-1,!n||f(m,n-1)):n+1

Esegui questo in una versione più recente di Firefox Console e creerà una funzione chiamata fche puoi chiamare con valori diversi me nsimili

f(3,2) // returns 29

O

prova il codice qui sotto in un ultimo Firefox

f=(m,n)=>m?f(m-1,!n||f(m,n-1)):n+1

B.onclick=_=>alert(f(+M.value, +N.value))
#M,#N{max-width:15px;border: 1px solid;border-width:0 0 1px 0}
<div>f(<input id=M />,<input id=N />)</div><br><button id=B>Evaluate</button>


Testare questo con 0,1 in Chrome non dà alcun risultato.
Nzall,

3
Si prega di leggere, questo funziona solo nell'ultimo Firefox grazie a ES6
Optimizer,

Wow ... abbiamo 4 soluzioni JS praticamente identiche, tutte a 34 byte. Non l'ho mai visto prima.
ETHproductions

6

Python 2.7.8 - 80, 54, 48, 46 45

A=lambda m,n:m and A(m-1,n<1or A(m,n-1))or-~n

(Crediti a xnor!)

Più leggibile, ma con 1 carattere in più:

A=lambda m,n:n+(m<1or A(m-1,n<1or A(m,n-1))-n)

Non che dovevo impostare sys.setrecursionlimit(10000)per ottenere un risultato A(3,10). Ulteriore golfing utilizzando l'indicizzazione logica non ha funzionato a causa della profondità di ricorsione drammaticamente crescente.


Ottengo un errore di sintassi sul 1else. La lettera iniziale ecausa problemi al parser perché i numeri possono essere scritti come 1e3.
xnor

and/orA=lambda m,n:m and A(m-1,n<1or A(m,n-1))or-~n
Ho

@xnor: grazie per il suggerimento! Vedi questa discussione per il problema di analisi. Python 2.7.8 accetta 1else, la maggior parte delle altre versioni no.
Falko,

Grazie per il puntatore 1else; mi permette di spremere un personaggio qui e probabilmente in altri posti. Ma dannazione è specifico per la versione! Python 2.7.4 non lo consente. Stai usando una versione online con 2.7.8 o dovrei scaricarla?
xnor

@xnor: è un'installazione offline. Anche ideone.com , ad esempio, non riesce ad analizzare 1else.
Falko,

6

J - 26 caratteri

($:^:(<:@[`]`1:)^:(0<[)>:)

Esiste una definizione alternativa e più funzionale di Ackermann:

Ack 0 n = n+1
Ack m n = Iter (Ack (m-1)) n
Iter f 0 = f 1
Iter f n = f (Iter f (n-1))

Accade così che Itersia molto facile scrivere in J, perché J ha un modo per passare m-1al Acke anche per definire il valore iniziale di Iteressere 1. Spiegato dall'esplosione:

(                      >:)  NB. increment n
                ^:(0<[)     NB. if m=0, do nothing to n+1; else:
   ^:                       NB. iterate...
($:                      )  NB.   self ($: is recursion)
     (<:@[     )            NB.   with left arg m-1
          `]                NB.   n+1 times
            `1:             NB.   starting on 1

Questo si basa su ciò che J chiama la forma ^:gerundia di - sostanzialmente un modo per avere un maggiore controllo su tutti i limiti in modo tacito (senza punti).

Alla REPL:

   3 ($:^:(<:@[`]`1:)^:(0<[)>:) 3
61
   ack =: ($:^:(<:@[`]`1:)^:(0<[)>:)
   (i.4) ack"0 table (i.11)
+-----+------------------------------------------+
|ack"0|0  1  2  3   4   5   6    7    8    9   10|
+-----+------------------------------------------+
|0    |1  2  3  4   5   6   7    8    9   10   11|
|1    |2  3  4  5   6   7   8    9   10   11   12|
|2    |3  5  7  9  11  13  15   17   19   21   23|
|3    |5 13 29 61 125 253 509 1021 2045 4093 8189|
+-----+------------------------------------------+
   6!:2 '3 ($:^:(<:@[`]`1:)^:(0<[)>:) 10'  NB. snugly fits in a minute
58.5831

Dobbiamo definire ackper nome per essere in grado di metterlo in un tavolo, perché $:è una brutta bestia orribile e si lancia contro chiunque tenti di capirlo. È auto-riferimento, dove auto è definito come la più grande frase verbale che lo contiene. tableè un avverbio e quindi mi piacerebbe diventare parte della frase verbo se gli dai la possibilità, quindi devi intercettare $:una definizione con nome per usarla.


Modifica: 24 caratteri?

Anni dopo, ho trovato una soluzione più corta di due personaggi.

(0&<~(<:@#~$:/@,1:^:)>:)

È molto più lento, però: 3 ack 8impiega più di un minuto sulla mia macchina. Questo perché (1) uso una piega /invece dell'iterazione, quindi J probabilmente deve ricordare più cose del solito, e (2) mentre 0&<~esegue lo stesso calcolo come (0<[), in realtà viene eseguito i n+1tempi prima di fare il passo ricorsivo quando si invoca m ack n- 0&<succede essere idempotente, quindi non rovina il calcolo, ma ndiventa molto veloce ed ackè altamente ricorsivo.

Sono dubbioso che una macchina più potente potrebbe spingere il nuovo codice in meno di un minuto, perché si tratta di un computer in cui il vecchio codice può essere trovato 3 ack 10in meno di 15 secondi.


5

C - 41 byte

Niente da fare: i piccoli limiti indicano che tutti i valori richiesti possono essere calcolati in meno di 1 secondo seguendo ingenuamente la definizione della funzione.

A(m,n){return!m?n+1:A(m-1,n?A(m,n-1):1);}


int main()
{
    int m,n;
    for(m = 0; m <= 3; m++)
    for(n = 0; n <= 10; n++)
    printf("%d %d %d\n", m,n,A(m,n));
    return 0;
}

5

Javascript ES6 (34)

a=(m,n)=>m?a(m-1,n?a(m,n-1):1):n+1

Implementazione:

a=(m,n)=>m?a(m-1,n?a(m,n-1):1):n+1
td[colspan="2"] input{width: 100%;}
<table><tbody><tr><td>m=</td><td><input id="m" type="number" value="0" /></td></tr><tr><td>n=</td><td><input id="n" type="number" value="0" /></td></tr><tr><td colspan="2"><input type="button" value="Calculate!" onclick="document.getElementById('out').value=a(document.getElementById('m').value, document.getElementById('n').value)" /></td></tr><tr><td colspan="2"><input id="out" disabled="disabled" type="text" /></td></tr></tbody></table>


4

JavaScript (ES6) - 34

A=(m,n)=>m?A(m-1,!n||A(m,n-1)):n+1

E un test:

> A=(m,n)=>m?A(m-1,!n||A(m,n-1)):n+1;s=new Date().getTime();console.log(A(3,10),(new Date().getTime() - s)/1000)
8189 16.441

3

Coq, 40

nat_rec _ S(fun _ b n=>nat_iter(S n)b 1)

Questa è una funzione di tipo nat -> nat -> nat. Poiché Coq consente solo la costruzione di funzioni totali, serve anche come prova formale che la ricorrenza di Ackermann è fondata.

demo:

Welcome to Coq 8.4pl6 (November 2015)

Coq < Compute nat_rec _ S(fun _ b n=>nat_iter(S n)b 1) 3 10.
     = 8189
     : nat

Nota: Coq 8.5, rilasciato dopo questa sfida, rinominato nat_iterin Nat.iter.



2

Mathematica, 46 byte

0~a~n_:=n+1
m_~a~n_:=a[m-1,If[n<1,1,a[m,n-1]]]

Richiede praticamente esattamente un minuto per a[3,10]. Si noti che il limite di ricorsione predefinito di Mathematica è troppo piccolo per a[3,8]e oltre (almeno sulla mia macchina), ma che può essere risolto configurando

$RecursionLimit = Infinity

1
Wow, quindi stai dicendo che JS è più di 25 volte più veloce di Mathematica?
Ottimizzatore

@Optimizer Almeno quando si tratta di ricorsione ... Immagino che sia una cosa che deve capire ogni volta quale definizione usare, ed Ifessere una funzione è ancora più lento.
Martin Ender,

1
Con la memoization, ci vogliono 0,07 secondi. Vale a dire m_~a~n_:=m~a~n=...
Mark Adler,

@MarkAdler È davvero un bel modo di fare memoria in Mathematica!
Martin Ender,

2

Javascript con lambdas, 34

A=(m,n)=>m?A(m-1,n?A(m,n-1):1):n+1

Una risposta tipica, non posso accorciare nulla.


2

Haskell, 48 44 caratteri (36 per l'elenco)

Sebbene non sia breve come l'altra soluzione di Haskell, questa è notevole perché esprime la funzione di Ackermann come un elenco infinito, che penso sia un po 'pulito. Il risultato è un elenco infinito (di elenchi infiniti) tale che nella posizione [m, n] contiene il valore A (m, n) .

L'elenco infinito stesso:

iterate(tail.(`iterate`1).(!!))[1..]

Come funzione (per rispettare le specifiche):

i=iterate;m%n=i(tail.(`i`1).(!!))[1..]!!m!!n

La formulazione è stata derivata osservando che il caso generale / comune per la funzione Ackermann è usare il valore a sinistra come indice nella riga sopra. Il caso base di questa ricorsione (cioè la colonna più a sinistra di una riga, ovvero A (m, 0) ) è usare il secondo valore più a sinistra nella riga sopra. Il caso base per quella ricorsione è il caso A (0, n) = n + 1 , ovvero la prima riga è [1..].

Quindi otteniamo

let a0 = [1..]
let a1 = tail $ iterate (a0 !!) 1  -- 'tail' because iterate starts by applying
let a2 = tail $ iterate (a1 !!) 1  -- the function 0 times
-- etc

Quindi aggiungiamo semplicemente un altro livello di iterazione basato su quel modello e facciamo qualche giocoleria inutile .


Si potrebbe alias iteratea un singolo nome lettera per esempioi=iterate;ack=i ...
haskeller orgogliosi

@proudhaskeller oh yeah, non ci ho pensato. Grazie! Prendendo in prestito anche il nome dell'operatore.
FireFly,

2

Tiny Lisp , 70 (fuori concorso)

Questo esaurisce la concorrenza, poiché la lingua è più recente della domanda e inoltre non riesce a eseguirla (A 3 10)come richiesto nella domanda, a causa di un overflow dello stack.

(d A(q((m n)(i m(i n(A(s m 1)(A m(s n 1)))(A(s m 1)1))(s n(s 0 1))))))

Questo definisce una funzione Ache calcola la funzione di Ackermann. formattato:

(d A
   (q( (m n)
       (i m
          (i n
             (A (s m 1)
                (A m
                   (s n 1)
                 )
              ) 
             (A (s m 1)
                1
              )
           )
          (s n
             (s 0 1)
           )
        )
    ) )
 )

Stiamo usando tutte le macro incorporate ( d(define) e q(quote) e i(if)) e una funzione built-in ( s- sottrarre) qui.

i esegue la sua parte vera quando la condizione è un numero> 0 (e altrimenti la parte falsa), quindi non dobbiamo fare un confronto esplicito qui.

sè l'unica operazione aritmetica disponibile, la usiamo per n-1/ m-1, oltre che (s n (s 0 1))per n+1.

Tiny lisp utilizza l'ottimizzazione della ricorsione della coda, ma questo aiuta solo per la Achiamata esterna nel risultato, non per la A(m, n-1)chiamata utilizzata per i parametri.

Con la mia piccola implementazione lisp in Ceylon su JVM, funziona fino a (A 3 5) = 253, ma sembra fallire quando provo a calcolare (A 2 125)direttamente (che dovrebbe dare lo stesso risultato). Se lo calcolo dopo (A 3 4) = 125, la JVM sembra aver ottimizzato le funzioni abbastanza da includere alcune chiamate di funzioni intermedie nel mio interprete, consentendo una maggiore profondità di ricorsione. Strano.

L' implementazione di riferimento arriva (A 3 5) = 253e anche (A 2 163) = 329, ma non ci riesce (A 2 164), e quindi anche meno (A 3 6) = (A 2 253).


questo potrebbe essere competitivo a parte lo spazio bianco e la parentesi;)
cat

2

Vai, 260 243 240 122 byte

Non ho visto che la domanda consentiva ad Anon Function.

lungi dall'essere competitivo ma sto imparando questa lingua e volevo provarla.

func (m,n int)int{r:=0
switch{case m==0&&n!=0:r=n+1
case m!=0&&n==0:r=a(m-1,1)
case m!=0&&n!=0:r=a(m-1,a(m,n-1))}
return r}

usalo come go run ack.go e poi fornisci due numeri me n. se m> 4 o n> 30, il tempo di esecuzione può essere superiore a mezzo minuto.

per m=3 n=11 :

$ time go run ack
16381
real    0m1.434s
user    0m1.432s
sys     0m0.004s

modifica : ha salvato un totale di 17 byte passando a switchover if/elsee dot-import


1
Puoi fare ancora meglio! switch 0 {case m:r=n+1 case n:r=a(m-1,1) default:r=a(m-1,a(m,n-1))}La switchdichiarazione di Go è meravigliosamente flessibile!
EMBLEMA

@EMBLEM Grazie, è passato tanto tempo da quando ho scritto una riga di Go, ma sono felice di vedere che ci sono altri Go-golfisti su: D
cat

1

Haskell: 81 69 byte

a::Int->Int->Int
a 0 n=n+1
a m 0=a (m-1) 1
a m n=a (m-1) a m (n-1)

a 3 10 dura circa 45 secondi.


1
questo è il codice golf, quindi dovresti provare ad avere il codice più corto possibile. per esempio, rimuovi gli spazi non necessari e il tipo esplicito
orgoglioso haskeller il

ti mancano anche i genitori sulla quarta riga
orgoglioso haskeller il


1

(non concorrenziale) UGL , 31 30 byte

iiRuldr%l%lR$d%rd:u%d:%+uRu:ro

Input separato da newline.

Provalo online!

(È stato implementato come esempio standard nell'interprete.)



1

R - 54 52

L'ho usato come una scusa per cercare di aggirare la mia testa su R, quindi probabilmente questo è davvero mal fatto :)

a=function(m,n)"if"(m,a(m-1,"if"(n,a(m,n-1),1)),n+1)

Esempio di esecuzione

> a(3,8)
[1] 2045

Ottengo un overflow dello stack per qualsiasi cosa oltre a ciò

T-SQL- 222

Ho pensato di provare anche a far funzionare T-SQL. Utilizzato un metodo diverso perché la ricorsione non è così piacevole in SQL. Qualunque cosa oltre 4,2 bombe.

DECLARE @m INT=4,@n INT=1;WITH R AS(SELECT 2 C, 1 X UNION ALL   SELECT POWER(2,C),X+1FROM R)SELECT IIF(@m=0,@n+1,IIF(@m=1,@n+2,IIF(@m=2,2*@n+3,IIF(@m=3,POWER(2,@n+3)-3,IIF(@m=4,(SELECT TOP(1)C FROM R WHERE x= @n+3)-3,-1)))))

per la tua sottomissione R, sembra che non ti serva, {}anche se non c'è aiuto per il limite di overflow dello stack, dal momento che R non ha TCO ...
Giuseppe

@Giuseppe grazie ... a mia difesa, ero nuovo allora :)
MickyT

1

Brainfuck , 90 byte

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

Provalo online!

Presuppone un'implementazione con dimensioni delle celle di dimensioni arbitrarie, con IO come numeri. -6 byte se non ti dispiace usare le celle negative.

Termina in circa 30 secondi per 3,8 nell'interprete collegato, a condizione che si spuntino le impostazioni corrette. Digita numeri immessi anteporre con \s, per esempio 3,9fa \3\9.


1

Tcl , 67 byte

proc tcl::mathfunc::A m\ n {expr {$m?A($m-1,$n?A($m,$n-1):1):$n+1}}

Provalo online!


Tcl , 77 byte

proc A m\ n {expr {$m?[A [expr $m-1] [expr {$n?[A $m [expr $n-1]]:1}]]:$n+1}}

Provalo online!

Nel compilatore online non riesce a funzionare a causa del timeout, ma in un interprete Tcl locale funziona bene. Ho profilato di ogni chiamata di root per Afunzionare, per vedere quanto tempo ha impiegato il calcolo per ciascuna coppia {m,n}oggetto da testare:

m=0, n=0, A=1, time=3.5e-5 seconds
m=0, n=1, A=2, time=2e-6 seconds
m=0, n=2, A=3, time=8e-6 seconds
m=0, n=3, A=4, time=1e-6 seconds
m=0, n=4, A=5, time=2e-6 seconds
m=0, n=5, A=6, time=1e-6 seconds
m=0, n=6, A=7, time=1e-6 seconds
m=0, n=7, A=8, time=1e-6 seconds
m=0, n=8, A=9, time=1e-6 seconds
m=0, n=9, A=10, time=0.0 seconds
m=0, n=10, A=11, time=1e-6 seconds
m=1, n=0, A=2, time=4e-6 seconds
m=1, n=1, A=3, time=6e-6 seconds
m=1, n=2, A=4, time=1e-5 seconds
m=1, n=3, A=5, time=1.2e-5 seconds
m=1, n=4, A=6, time=1.5e-5 seconds
m=1, n=5, A=7, time=2e-5 seconds
m=1, n=6, A=8, time=2e-5 seconds
m=1, n=7, A=9, time=2.6e-5 seconds
m=1, n=8, A=10, time=3e-5 seconds
m=1, n=9, A=11, time=3e-5 seconds
m=1, n=10, A=12, time=3.3e-5 seconds
m=2, n=0, A=3, time=8e-6 seconds
m=2, n=1, A=5, time=2.2e-5 seconds
m=2, n=2, A=7, time=3.9e-5 seconds
m=2, n=3, A=9, time=6.3e-5 seconds
m=2, n=4, A=11, time=9.1e-5 seconds
m=2, n=5, A=13, time=0.000124 seconds
m=2, n=6, A=15, time=0.000163 seconds
m=2, n=7, A=17, time=0.000213 seconds
m=2, n=8, A=19, time=0.000262 seconds
m=2, n=9, A=21, time=0.000316 seconds
m=2, n=10, A=23, time=0.000377 seconds
m=3, n=0, A=5, time=2.2e-5 seconds
m=3, n=1, A=13, time=0.000145 seconds
m=3, n=2, A=29, time=0.000745 seconds
m=3, n=3, A=61, time=0.003345 seconds
m=3, n=4, A=125, time=0.015048 seconds
m=3, n=5, A=253, time=0.059836 seconds
m=3, n=6, A=509, time=0.241431 seconds
m=3, n=7, A=1021, time=0.971836 seconds
m=3, n=8, A=2045, time=3.908884 seconds
m=3, n=9, A=4093, time=15.926341 seconds
m=3, n=10, A=8189, time=63.734713 seconds

Non riesce per l'ultima coppia {m,n}={3,10}, poiché richiede poco più di un minuto.

Per valori più alti di m, sarà necessario aumentare il recursionlimitvalore.


Posso ottenere un valore inferiore a 65 byte, ma non soddisferà il requisito della domanda "La tua funzione deve essere in grado di trovare il valore di A (m, n) per m ≤ 3 e n ≤ 10 in meno di un minuto.". Senza il {}timeout su TIO non eseguirà la demo delle ultime due voci.

Tcl , 65 byte

proc tcl::mathfunc::A m\ n {expr $m?A($m-1,$n?A($m,$n-1):1):$n+1}

Provalo online!


0

J: 50

>:@]`(1$:~<:@[)`(<:@[$:[$:_1+])@.(0>.[:<:@#.,&*)M.

Restituisce in una frazione di secondo per 0 ... 3 vs 0 ... 10:

   A=:>:@]`(1$:~<:@[)`(<:@[$:[$:_1+])@.(0>.[:<:@#.,&*)M.
   timespacex 'res=:(i.4) A"0 table (i.11)'
0.0336829 3.54035e6
   res
┌───┬──────────────────────────────────────────┐
│A"0│0  1  2  3   4   5   6    7    8    9   10│
├───┼──────────────────────────────────────────┤
│0  │1  2  3  4   5   6   7    8    9   10   11│
│1  │2  3  4  5   6   7   8    9   10   11   12│
│2  │3  5  7  9  11  13  15   17   19   21   23│
│3  │5 13 29 61 125 253 509 1021 2045 4093 8189│
└───┴──────────────────────────────────────────┘

PS: lo "0 serve a far funzionare A su ogni singolo elemento, invece di divorare l'array sinistro e destro e generare errori di lunghezza. Ma non è necessario per es. 9 = 2 A 3.



0

APL, 31

{⍺=0:⍵+1⋄⍵=0:1∇⍨⍺-1⋄(⍺-1)∇⍺∇⍵-1}

Abbastanza diretto. Utilizza il carattere once una volta per salvare un byte invertendo gli argomenti. Prende m come argomento sinistro e n come argomento destro.

TryAPL.org


0

Ruby, 65 anni

h,a={},->m,n{h[[m,n]]||=m<1?(n+1):(n<1?a[m-1,1]:a[m-1,a[m,n-1]])}

Spiegazione

Questa è una traduzione piuttosto semplice dell'algoritmo fornito nella descrizione del problema.

  • L'input viene preso come argomento per un lambda. Sono Integerprevisti due secondi.
  • Per la velocità ed evitare errori di overflow dello stack, le risposte sono memorizzate in Hash h. L' ||=operatore viene utilizzato per calcolare un valore che non era stato precedentemente calcolato.

a[3,10] viene calcolato in ~ 0,1 secondi sulla mia macchina.

Ecco una versione non golfata

h = {}
a = lambda do |m,n|
  h[[m,n]] ||= if m < 1 
    n + 1
  elsif n < 1
    a[m-1,1]
  else
    a[m-1,a[m,n-1]]
  end
end

a[3,10]lancio un SystemStackError sulla mia macchina ...
TuxCrafting

Golf nitpicks: potresti passare m<1?(n+1):(n<1?a[m-1,1]:a[m-1,a[m,n-1]])am<1?n+1:a[m-1,n<1?1:a[m,n-1]]
Simply Beautiful Art,

0

Mouse-2002 , 99 83 byte

$Y1%j:j.0=m:2%k:k.0=n:m.n.>[k.1+!|m.n.<[#Y,j.1-,1;|m.n.*0=[#Y,j.1-,#Y,j.,k.1+;;]]]@

0

Java, 274 byte

import java.math.*;class a{BigInteger A(BigInteger b,BigInteger B){if(b.equals(BigInteger.ZERO))return B.add(BigInteger.ONE);if(B.equals(BigInteger.ZERO))return A(b.subtract(BigInteger.ONE),BigInteger.ONE);return A(b.subtract(BigInteger.ONE),A(b,B.subtract(BigInteger.ONE)));}}

Calcola A(3,10)in pochi secondi e, data la memoria infinita e lo spazio dello stack, può calcolare qualsiasi combinazione di be Bpurché il risultato sia inferiore a 2 2147483647 -1.


So che è passato un po 'di tempo, ma puoi giocare a 185 byte :import java.math.*;BigInteger A(BigInteger b,BigInteger B){return b.equals(B.ZERO)?B.add(B.ONE):B.equals(B.ZERO)?A(b.subtract(B.ONE),B.ONE):A(b.subtract(B.ONE),A(b,B.subtract(B.ONE)));}
Kevin Cruijssen,

0

Ceylon, 88 87 85

alias I=>Integer;I a(I m,I n)=>m<1then n+1else(n<1then a(m-1,1)else a(m-1,a(m,n-1)));

Questa è un'implementazione semplice. formattato:

alias I => Integer;
I a(I m, I n) =>
        m < 1
        then n + 1
        else (n < 1
            then a(m - 1, 1)
            else a(m - 1, a(m, n - 1)));

L'alias salva solo un byte, senza di esso (con la scrittura Integerinvece di I) arriveremmo a 86 byte. Altri due byte possono essere salvati sostituendoli == 0con< 1 due volte.

Con le impostazioni predefinite di ceylon run, funzionerà fino a A(3,12) = 32765(e A(4,0) = 13), ma A(3,13)(e quindi anche A(4,1)) genererà un errore di overflow dello stack. ( A(3,12)dura circa 5 secondi, A(3,11)circa 3 sul mio computer.)

L'uso ceylon run-js(ovvero l'esecuzione del risultato della compilazione in JavaScript su node.js) è molto più lento (richiede 1 minuto e 19 secondi per A(3,10)) e si interrompe già A(3, 11)con una »Dimensione massima dello stack di chiamate superata« (utilizzando le impostazioni predefinite) dopo l'esecuzione per 1 min 30 s.


Ceylon senza ricorsione, 228

Come bonus, ecco una versione non ricorsiva (più a lungo, ovviamente, ma immune agli overflow dello stack - potrebbe avere un errore di memoria insufficiente ad un certo punto).

import ceylon.collection{A=ArrayList}Integer a(Integer[2]r){value s=A{*r};value p=s.addAll;while(true){if(exists m=s.pop()){if(exists n=s.pop()){if(n<1){p([m+1]);}else if(m<1){p([n-1,1]);}else{p([n-1,n,m-1]);}}else{return m;}}}}

formattato:

import ceylon.collection {
    A=ArrayList
}

Integer a(Integer[2] r) {
    value s = A { *r };
    value p = s.addAll;
    while (true) {
        if (exists m = s.pop()) {
            if (exists n = s.pop()) {
                if (n < 1) {
                    p([m + 1]);
                } else if (m < 1) {
                    p([n - 1, 1]);
                } else {
                    p([n - 1, n, m - 1]);
                }
            } else {
                // stack is empty
                return m;
            }
        }
    }
}

Sul mio computer è piuttosto lento rispetto alla versione ricorsiva: A(3,11)impiega 9,5 secondi, A(3,12)impiega 34 secondi, A(3,13)impiega 2:08 minuti, A(3,14)impiega 8:25 minuti. (Inizialmente avevo una versione che utilizzava iterables pigri invece delle tuple che ho ora, che era anche molto più lenta, con le stesse dimensioni).

Un po 'più veloce (21 secondi per A(3,12)) (ma anche un byte più lungo) è una versione che utilizza s.pushinvece di s.addAll, ma che doveva essere chiamata più volte per aggiungere più numeri, in quanto richiede un solo intero ciascuno. L'uso di una LinkedList invece di una ArrayList è molto più lento.

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.