Ackermann function: Difference between revisions
No edit summary |
|||
(176 intermediate revisions by 81 users not shown) | |||
Line 20: | Line 20: | ||
<!-- <table><tr><td width=12><td><td><math>n+1</math><td>if <math>m=0</math> <tr><td> <td><math>A(m, n) =</math> <td><math>A(m-1, 1)</math> <td>if <math>m>0</math> and <math>n=0</math> <tr><td><td><td><math>A(m-1, A(m, n-1))</math> <td> if <math>m>0</math> and <math>n>0</math></table> --> |
<!-- <table><tr><td width=12><td><td><math>n+1</math><td>if <math>m=0</math> <tr><td> <td><math>A(m, n) =</math> <td><math>A(m-1, 1)</math> <td>if <math>m>0</math> and <math>n=0</math> <tr><td><td><td><math>A(m-1, A(m, n-1))</math> <td> if <math>m>0</math> and <math>n>0</math></table> --> |
||
Its arguments are never negative and it always terminates |
Its arguments are never negative and it always terminates. |
||
;Task: |
|||
Write a function which returns the value of <math>A(m, n)</math>. Arbitrary precision is preferred (since the function grows so quickly), but not required. |
|||
Line 26: | Line 30: | ||
* [[wp:Conway_chained_arrow_notation#Ackermann_function|Conway chained arrow notation]] for the Ackermann function. |
* [[wp:Conway_chained_arrow_notation#Ackermann_function|Conway chained arrow notation]] for the Ackermann function. |
||
<br><br> |
<br><br> |
||
=={{header|11l}}== |
|||
{{trans|Python}} |
|||
<syntaxhighlight lang="11l">F ack2(m, n) -> Int |
|||
R I m == 0 {(n + 1) |
|||
} E I m == 1 {(n + 2) |
|||
} E I m == 2 {(2 * n + 3) |
|||
} E I m == 3 {(8 * (2 ^ n - 1) + 5) |
|||
} E I n == 0 {ack2(m - 1, 1) |
|||
} E ack2(m - 1, ack2(m, n - 1)) |
|||
print(ack2(0, 0)) |
|||
print(ack2(3, 4)) |
|||
print(ack2(4, 1))</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1 |
|||
125 |
|||
65533 |
|||
</pre> |
|||
=={{header|360 Assembly}}== |
=={{header|360 Assembly}}== |
||
Line 31: | Line 57: | ||
The OS/360 linkage is a bit tricky with the S/360 basic instruction set. |
The OS/360 linkage is a bit tricky with the S/360 basic instruction set. |
||
To simplify, the program is recursive not reentrant. |
To simplify, the program is recursive not reentrant. |
||
< |
<syntaxhighlight lang="360asm">* Ackermann function 07/09/2015 |
||
&LAB XDECO ®,&TARGET |
|||
.*-----------------------------------------------------------------* |
|||
.* THIS MACRO DISPLAYS THE REGISTER CONTENTS AS A TRUE * |
|||
.* DECIMAL VALUE. XDECO IS NOT PART OF STANDARD S360 MACROS! * |
|||
*------------------------------------------------------------------* |
|||
AIF (T'® EQ 'O').NOREG |
|||
AIF (T'&TARGET EQ 'O').NODEST |
|||
&LAB B I&SYSNDX BRANCH AROUND WORK AREA |
|||
W&SYSNDX DS XL8 CONVERSION WORK AREA |
|||
I&SYSNDX CVD ®,W&SYSNDX CONVERT TO DECIMAL |
|||
MVC &TARGET,=XL12'402120202020202020202020' |
|||
ED &TARGET,W&SYSNDX+2 MAKE FIELD PRINTABLE |
|||
BC 2,*+12 BYPASS NEGATIVE |
|||
MVI &TARGET+12,C'-' INSERT NEGATIVE SIGN |
|||
B *+8 BYPASS POSITIVE |
|||
MVI &TARGET+12,C'+' INSERT POSITIVE SIGN |
|||
MEXIT |
|||
.NOREG MNOTE 8,'INPUT REGISTER OMITTED' |
|||
MEXIT |
|||
.NODEST MNOTE 8,'TARGET FIELD OMITTED' |
|||
MEXIT |
|||
MEND |
|||
ACKERMAN CSECT |
ACKERMAN CSECT |
||
USING ACKERMAN,R12 r12 : base register |
USING ACKERMAN,R12 r12 : base register |
||
Line 107: | Line 155: | ||
STACKLEN EQU *-STACK |
STACKLEN EQU *-STACK |
||
YREGS |
YREGS |
||
END ACKERMAN</ |
END ACKERMAN</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre style="height:20ex"> |
<pre style="height:20ex"> |
||
Line 151: | Line 199: | ||
This implementation is based on the code shown in the computerphile episode in the youtube link at the top of this page (time index 5:00). |
This implementation is based on the code shown in the computerphile episode in the youtube link at the top of this page (time index 5:00). |
||
< |
<syntaxhighlight lang="68000devpac">; |
||
; Ackermann function for Motorola 68000 under AmigaOs 2+ by Thorham |
; Ackermann function for Motorola 68000 under AmigaOs 2+ by Thorham |
||
; |
; |
||
Line 262: | Line 310: | ||
outString |
outString |
||
dc.b "ackermann (%ld,%ld) is: %ld",10,0</ |
dc.b "ackermann (%ld,%ld) is: %ld",10,0</syntaxhighlight> |
||
=={{header|8080 Assembly}}== |
|||
This function does 16-bit math. The test code prints a table of <code>ack(m,n)</code> for <code>m ∊ [0,4)</code> |
|||
and <code>n ∊ [0,9)</code>, on a real 8080 this takes a little over two minutes. |
|||
<syntaxhighlight lang="8080asm"> org 100h |
|||
jmp demo |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; ACK(M,N); DE=M, HL=N, return value in HL. |
|||
ack: mov a,d ; M=0? |
|||
ora e |
|||
jnz ackm |
|||
inx h ; If so, N+1. |
|||
ret |
|||
ackm: mov a,h ; N=0? |
|||
ora l |
|||
jnz ackmn |
|||
lxi h,1 ; If so, N=1, |
|||
dcx d ; N-=1, |
|||
jmp ack ; A(M,N) - tail recursion |
|||
ackmn: push d ; M>0 and N>0: store M on the stack |
|||
dcx h ; N-=1 |
|||
call ack ; N = ACK(M,N-1) |
|||
pop d ; Restore previous M |
|||
dcx d ; M-=1 |
|||
jmp ack ; A(M,N) - tail recursion |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Print table of ack(m,n) |
|||
MMAX: equ 4 ; Size of table to print. Note that math is done in |
|||
NMAX: equ 9 ; 16 bits. |
|||
demo: lhld 6 ; Put stack pointer at top of available memory |
|||
sphl |
|||
lxi b,0 ; let B,C hold 8-bit M and N. |
|||
acknum: xra a ; Set high bit of M and N to zero |
|||
mov d,a ; DE = B (M) |
|||
mov e,b |
|||
mov h,a ; HL = C (N) |
|||
mov l,c |
|||
call ack ; HL = ack(DE,HL) |
|||
call prhl ; Print the number |
|||
inr c ; N += 1 |
|||
mvi a,NMAX ; Time for next line? |
|||
cmp c |
|||
jnz acknum ; If not, print next number |
|||
push b ; Otherwise, save BC |
|||
mvi c,9 ; Print newline |
|||
lxi d,nl |
|||
call 5 |
|||
pop b ; Restore BC |
|||
mvi c,0 ; Set N to 0 |
|||
inr b ; M += 1 |
|||
mvi a,MMAX ; Time to stop? |
|||
cmp b |
|||
jnz acknum ; If not, print next number |
|||
rst 0 |
|||
;;; Print HL as ASCII number. |
|||
prhl: push h ; Save all registers |
|||
push d |
|||
push b |
|||
lxi b,pnum ; Store pointer to num string on stack |
|||
push b |
|||
lxi b,-10 ; Divisor |
|||
prdgt: lxi d,-1 |
|||
prdgtl: inx d ; Divide by 10 through trial subtraction |
|||
dad b |
|||
jc prdgtl |
|||
mvi a,'0'+10 |
|||
add l ; L = remainder - 10 |
|||
pop h ; Get pointer from stack |
|||
dcx h ; Store digit |
|||
mov m,a |
|||
push h ; Put pointer back on stack |
|||
xchg ; Put quotient in HL |
|||
mov a,h ; Check if zero |
|||
ora l |
|||
jnz prdgt ; If not, next digit |
|||
pop d ; Get pointer and put in DE |
|||
mvi c,9 ; CP/M print string |
|||
call 5 |
|||
pop b ; Restore registers |
|||
pop d |
|||
pop h |
|||
ret |
|||
db '*****' ; Placeholder for number |
|||
pnum: db 9,'$' |
|||
nl: db 13,10,'$'</syntaxhighlight> |
|||
{{out}} |
|||
<pre>1 2 3 4 5 6 7 8 9 |
|||
2 3 4 5 6 7 8 9 10 |
|||
3 5 7 9 11 13 15 17 19 |
|||
5 13 29 61 125 253 509 1021 2045</pre> |
|||
=={{header|8086 Assembly}}== |
|||
This code does 16-bit math just like the 8080 version. |
|||
<syntaxhighlight lang="asm"> cpu 8086 |
|||
bits 16 |
|||
org 100h |
|||
section .text |
|||
jmp demo |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; ACK(M,N); DX=M, AX=N, return value in AX. |
|||
ack: and dx,dx ; N=0? |
|||
jnz .m |
|||
inc ax ; If so, return N+1 |
|||
ret |
|||
.m: and ax,ax ; M=0? |
|||
jnz .mn |
|||
mov ax,1 ; If so, N=1, |
|||
dec dx ; M -= 1 |
|||
jmp ack ; ACK(M-1,1) - tail recursion |
|||
.mn: push dx ; Keep M on the stack |
|||
dec ax ; N-=1 |
|||
call ack ; N = ACK(M,N-1) |
|||
pop dx ; Restore M |
|||
dec dx ; M -= 1 |
|||
jmp ack ; ACK(M-1,ACK(M,N-1)) - tail recursion |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Print table of ack(m,n) |
|||
MMAX: equ 4 ; Size of table to print. Noe that math is done |
|||
NMAX: equ 9 ; in 16 bits. |
|||
demo: xor si,si ; Let SI hold M, |
|||
xor di,di ; and DI hold N. |
|||
acknum: mov dx,si ; Calculate ack(M,N) |
|||
mov ax,di |
|||
call ack |
|||
call prax ; Print number |
|||
inc di ; N += 1 |
|||
cmp di,NMAX ; Row done? |
|||
jb acknum ; If not, print next number on row |
|||
xor di,di ; Otherwise, N=0, |
|||
inc si ; M += 1 |
|||
mov dx,nl ; Print newline |
|||
call prstr |
|||
cmp si,MMAX ; Done? |
|||
jb acknum ; If not, start next row |
|||
ret ; Otherwise, stop. |
|||
;;; Print AX as ASCII number. |
|||
prax: mov bx,pnum ; Pointer to number string |
|||
mov cx,10 ; Divisor |
|||
.dgt: xor dx,dx ; Divide AX by ten |
|||
div cx |
|||
add dl,'0' ; DX holds remainder - add ASCII 0 |
|||
dec bx ; Move pointer backwards |
|||
mov [bx],dl ; Save digit in string |
|||
and ax,ax ; Are we done yet? |
|||
jnz .dgt ; If not, next digit |
|||
mov dx,bx ; Tell DOS to print the string |
|||
prstr: mov ah,9 |
|||
int 21h |
|||
ret |
|||
section .data |
|||
db '*****' ; Placeholder for ASCII number |
|||
pnum: db 9,'$' |
|||
nl: db 13,10,'$'</syntaxhighlight> |
|||
{{out}} |
|||
<pre>1 2 3 4 5 6 7 8 9 |
|||
2 3 4 5 6 7 8 9 10 |
|||
3 5 7 9 11 13 15 17 19 |
|||
5 13 29 61 125 253 509 1021 2045</pre> |
|||
=={{header|8th}}== |
=={{header|8th}}== |
||
<syntaxhighlight lang="forth"> |
|||
<lang Forth> |
|||
\ Ackermann function, illustrating use of "memoization". |
\ Ackermann function, illustrating use of "memoization". |
||
Line 340: | Line 554: | ||
4 1 ackOf |
4 1 ackOf |
||
bye</ |
bye</syntaxhighlight> |
||
{{out|The output}} |
{{out|The output}} |
||
Line 355: | Line 569: | ||
Ack(4, 1) = 65533 |
Ack(4, 1) = 65533 |
||
</pre> |
</pre> |
||
=={{header|AArch64 Assembly}}== |
|||
{{works with|as|Raspberry Pi 3B version Buster 64 bits <br> or android 64 bits with application Termux }} |
|||
<syntaxhighlight lang="aarch64 assembly"> |
|||
/* ARM assembly AARCH64 Raspberry PI 3B or android 64 bits */ |
|||
/* program ackermann64.s */ |
|||
/*******************************************/ |
|||
/* Constantes file */ |
|||
/*******************************************/ |
|||
/* for this file see task include a file in language AArch64 assembly*/ |
|||
.include "../includeConstantesARM64.inc" |
|||
.equ MMAXI, 4 |
|||
.equ NMAXI, 10 |
|||
/*********************************/ |
|||
/* Initialized data */ |
|||
/*********************************/ |
|||
.data |
|||
sMessResult: .asciz "Result for @ @ : @ \n" |
|||
szMessError: .asciz "Overflow !!.\n" |
|||
szCarriageReturn: .asciz "\n" |
|||
/*********************************/ |
|||
/* UnInitialized data */ |
|||
/*********************************/ |
|||
.bss |
|||
sZoneConv: .skip 24 |
|||
/*********************************/ |
|||
/* code section */ |
|||
/*********************************/ |
|||
.text |
|||
.global main |
|||
main: // entry of program |
|||
mov x3,#0 |
|||
mov x4,#0 |
|||
1: |
|||
mov x0,x3 |
|||
mov x1,x4 |
|||
bl ackermann |
|||
mov x5,x0 |
|||
mov x0,x3 |
|||
ldr x1,qAdrsZoneConv // else display odd message |
|||
bl conversion10 // call decimal conversion |
|||
ldr x0,qAdrsMessResult |
|||
ldr x1,qAdrsZoneConv // insert value conversion in message |
|||
bl strInsertAtCharInc |
|||
mov x6,x0 |
|||
mov x0,x4 |
|||
ldr x1,qAdrsZoneConv // else display odd message |
|||
bl conversion10 // call decimal conversion |
|||
mov x0,x6 |
|||
ldr x1,qAdrsZoneConv // insert value conversion in message |
|||
bl strInsertAtCharInc |
|||
mov x6,x0 |
|||
mov x0,x5 |
|||
ldr x1,qAdrsZoneConv // else display odd message |
|||
bl conversion10 // call decimal conversion |
|||
mov x0,x6 |
|||
ldr x1,qAdrsZoneConv // insert value conversion in message |
|||
bl strInsertAtCharInc |
|||
bl affichageMess |
|||
add x4,x4,#1 |
|||
cmp x4,#NMAXI |
|||
blt 1b |
|||
mov x4,#0 |
|||
add x3,x3,#1 |
|||
cmp x3,#MMAXI |
|||
blt 1b |
|||
100: // standard end of the program |
|||
mov x0, #0 // return code |
|||
mov x8, #EXIT // request to exit program |
|||
svc #0 // perform the system call |
|||
qAdrszCarriageReturn: .quad szCarriageReturn |
|||
qAdrsMessResult: .quad sMessResult |
|||
qAdrsZoneConv: .quad sZoneConv |
|||
/***************************************************/ |
|||
/* fonction ackermann */ |
|||
/***************************************************/ |
|||
// x0 contains a number m |
|||
// x1 contains a number n |
|||
// x0 return résult |
|||
ackermann: |
|||
stp x1,lr,[sp,-16]! // save registres |
|||
stp x2,x3,[sp,-16]! // save registres |
|||
cmp x0,0 |
|||
beq 5f |
|||
mov x3,-1 |
|||
csel x0,x3,x0,lt // error |
|||
blt 100f |
|||
cmp x1,#0 |
|||
csel x0,x3,x0,lt // error |
|||
blt 100f |
|||
bgt 1f |
|||
sub x0,x0,#1 |
|||
mov x1,#1 |
|||
bl ackermann |
|||
b 100f |
|||
1: |
|||
mov x2,x0 |
|||
sub x1,x1,#1 |
|||
bl ackermann |
|||
mov x1,x0 |
|||
sub x0,x2,#1 |
|||
bl ackermann |
|||
b 100f |
|||
5: |
|||
adds x0,x1,#1 |
|||
bcc 100f |
|||
ldr x0,qAdrszMessError |
|||
bl affichageMess |
|||
mov x0,-1 |
|||
100: |
|||
ldp x2,x3,[sp],16 // restaur des 2 registres |
|||
ldp x1,lr,[sp],16 // restaur des 2 registres |
|||
ret |
|||
qAdrszMessError: .quad szMessError |
|||
/********************************************************/ |
|||
/* File Include fonctions */ |
|||
/********************************************************/ |
|||
/* for this file see task include a file in language AArch64 assembly */ |
|||
.include "../includeARM64.inc" |
|||
</syntaxhighlight> |
|||
{{Output}} |
|||
<pre> |
|||
Result for 0 0 : 1 |
|||
Result for 0 1 : 2 |
|||
Result for 0 2 : 3 |
|||
Result for 0 3 : 4 |
|||
Result for 0 4 : 5 |
|||
Result for 0 5 : 6 |
|||
Result for 0 6 : 7 |
|||
Result for 0 7 : 8 |
|||
Result for 0 8 : 9 |
|||
Result for 0 9 : 10 |
|||
Result for 1 0 : 2 |
|||
Result for 1 1 : 3 |
|||
Result for 1 2 : 4 |
|||
Result for 1 3 : 5 |
|||
Result for 1 4 : 6 |
|||
Result for 1 5 : 7 |
|||
Result for 1 6 : 8 |
|||
Result for 1 7 : 9 |
|||
Result for 1 8 : 10 |
|||
Result for 1 9 : 11 |
|||
Result for 2 0 : 3 |
|||
Result for 2 1 : 5 |
|||
Result for 2 2 : 7 |
|||
Result for 2 3 : 9 |
|||
Result for 2 4 : 11 |
|||
Result for 2 5 : 13 |
|||
Result for 2 6 : 15 |
|||
Result for 2 7 : 17 |
|||
Result for 2 8 : 19 |
|||
Result for 2 9 : 21 |
|||
Result for 3 0 : 5 |
|||
Result for 3 1 : 13 |
|||
Result for 3 2 : 29 |
|||
Result for 3 3 : 61 |
|||
Result for 3 4 : 125 |
|||
Result for 3 5 : 253 |
|||
Result for 3 6 : 509 |
|||
Result for 3 7 : 1021 |
|||
Result for 3 8 : 2045 |
|||
Result for 3 9 : 4093 |
|||
</pre> |
|||
=={{header|ABAP}}== |
=={{header|ABAP}}== |
||
<syntaxhighlight lang="abap"> |
|||
<lang ABAP> |
|||
REPORT zhuberv_ackermann. |
REPORT zhuberv_ackermann. |
||
Line 404: | Line 785: | ||
lv_result = zcl_ackermann=>ackermann( m = pa_m n = pa_n ). |
lv_result = zcl_ackermann=>ackermann( m = pa_m n = pa_n ). |
||
WRITE: / lv_result. |
WRITE: / lv_result. |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|ABC}}== |
|||
<syntaxhighlight lang="ABC">HOW TO RETURN m ack n: |
|||
SELECT: |
|||
m=0: RETURN n+1 |
|||
m>0 AND n=0: RETURN (m-1) ack 1 |
|||
m>0 AND n>0: RETURN (m-1) ack (m ack (n-1)) |
|||
FOR m IN {0..3}: |
|||
FOR n IN {0..8}: |
|||
WRITE (m ack n)>>6 |
|||
WRITE /</syntaxhighlight> |
|||
{{out}} |
|||
<pre> 1 2 3 4 5 6 7 8 9 |
|||
2 3 4 5 6 7 8 9 10 |
|||
3 5 7 9 11 13 15 17 19 |
|||
5 13 29 61 125 253 509 1021 2045</pre> |
|||
=={{header|Acornsoft Lisp}}== |
|||
{{trans|Common Lisp}} |
|||
<syntaxhighlight lang="lisp"> |
|||
(defun ack (m n) |
|||
(cond ((zerop m) (add1 n)) |
|||
((zerop n) (ack (sub1 m) 1)) |
|||
(t (ack (sub1 m) (ack m (sub1 n)))))) |
|||
</syntaxhighlight> |
|||
{{Out}} |
|||
<pre> |
|||
Evaluate : (ack 3 5) |
|||
Value is : 253 |
|||
</pre> |
|||
=={{header|Action!}}== |
|||
Action! language does not support recursion. Therefore an iterative approach with a stack has been proposed. |
|||
<syntaxhighlight lang="action!">DEFINE MAXSIZE="1000" |
|||
CARD ARRAY stack(MAXSIZE) |
|||
CARD stacksize=[0] |
|||
BYTE FUNC IsEmpty() |
|||
IF stacksize=0 THEN |
|||
RETURN (1) |
|||
FI |
|||
RETURN (0) |
|||
PROC Push(BYTE v) |
|||
IF stacksize=maxsize THEN |
|||
PrintE("Error: stack is full!") |
|||
Break() |
|||
FI |
|||
stack(stacksize)=v |
|||
stacksize==+1 |
|||
RETURN |
|||
BYTE FUNC Pop() |
|||
IF IsEmpty() THEN |
|||
PrintE("Error: stack is empty!") |
|||
Break() |
|||
FI |
|||
stacksize==-1 |
|||
RETURN (stack(stacksize)) |
|||
CARD FUNC Ackermann(CARD m,n) |
|||
Push(m) |
|||
WHILE IsEmpty()=0 |
|||
DO |
|||
m=Pop() |
|||
IF m=0 THEN |
|||
n==+1 |
|||
ELSEIF n=0 THEN |
|||
n=1 |
|||
Push(m-1) |
|||
ELSE |
|||
n==-1 |
|||
Push(m-1) |
|||
Push(m) |
|||
FI |
|||
OD |
|||
RETURN (n) |
|||
PROC Main() |
|||
CARD m,n,res |
|||
FOR m=0 TO 3 |
|||
DO |
|||
FOR n=0 TO 4 |
|||
DO |
|||
res=Ackermann(m,n) |
|||
PrintF("Ack(%U,%U)=%U%E",m,n,res) |
|||
OD |
|||
OD |
|||
RETURN</syntaxhighlight> |
|||
{{out}} |
|||
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Ackermann_function.png Screenshot from Atari 8-bit computer] |
|||
<pre> |
|||
Ack(0,0)=1 |
|||
Ack(0,1)=2 |
|||
Ack(0,2)=3 |
|||
Ack(0,3)=4 |
|||
Ack(0,4)=5 |
|||
Ack(1,0)=2 |
|||
Ack(1,1)=3 |
|||
Ack(1,2)=4 |
|||
Ack(1,3)=5 |
|||
Ack(1,4)=6 |
|||
Ack(2,0)=3 |
|||
Ack(2,1)=5 |
|||
Ack(2,2)=7 |
|||
Ack(2,3)=9 |
|||
Ack(2,4)=11 |
|||
Ack(3,0)=5 |
|||
Ack(3,1)=13 |
|||
Ack(3,2)=29 |
|||
Ack(3,3)=61 |
|||
Ack(3,4)=125 |
|||
</pre> |
|||
=={{header|ActionScript}}== |
=={{header|ActionScript}}== |
||
< |
<syntaxhighlight lang="actionscript">public function ackermann(m:uint, n:uint):uint |
||
{ |
{ |
||
if (m == 0) |
if (m == 0) |
||
Line 419: | Line 919: | ||
return ackermann(m - 1, ackermann(m, n - 1)); |
return ackermann(m - 1, ackermann(m, n - 1)); |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Ada}}== |
=={{header|Ada}}== |
||
< |
<syntaxhighlight lang="ada">with Ada.Text_IO; use Ada.Text_IO; |
||
procedure Test_Ackermann is |
procedure Test_Ackermann is |
||
Line 442: | Line 942: | ||
New_Line; |
New_Line; |
||
end loop; |
end loop; |
||
end Test_Ackermann;</ |
end Test_Ackermann;</syntaxhighlight> |
||
The implementation does not care about arbitrary precision numbers because the Ackermann function does not only grow, but also slow quickly, when computed recursively. |
The implementation does not care about arbitrary precision numbers because the Ackermann function does not only grow, but also slow quickly, when computed recursively. |
||
{{out}} the first 4x7 Ackermann's numbers: |
{{out}} the first 4x7 Ackermann's numbers: |
||
Line 451: | Line 951: | ||
=={{header|Agda}}== |
=={{header|Agda}}== |
||
{{works with|Agda|2. |
{{works with|Agda|2.6.3}} |
||
{{libheader|agda-stdlib |
{{libheader|agda-stdlib v1.7}} |
||
< |
<syntaxhighlight lang="agda"> |
||
open import Data.Nat |
|||
open import Data.Nat.Show |
|||
open import IO |
|||
module Ackermann where |
module Ackermann where |
||
open import Data.Nat using (ℕ ; zero ; suc ; _+_) |
|||
ack : ℕ -> ℕ -> ℕ |
|||
ack : ℕ → ℕ → ℕ |
|||
ack zero n = n + 1 |
ack zero n = n + 1 |
||
ack (suc m) zero = ack m 1 |
ack (suc m) zero = ack m 1 |
||
ack (suc m) (suc n) = ack m (ack (suc m) n) |
ack (suc m) (suc n) = ack m (ack (suc m) n) |
||
main = run (putStrLn (show (ack 3 9))) |
|||
</lang> |
|||
open import Agda.Builtin.IO using (IO) |
|||
Note the unicode ℕ characters, they can be input in emacs agda mode using "\bN". Running in bash: |
|||
open import Agda.Builtin.Unit using (⊤) |
|||
open import Agda.Builtin.String using (String) |
|||
open import Data.Nat.Show using (show) |
|||
postulate putStrLn : String → IO ⊤ |
|||
<lang bash> |
|||
{-# FOREIGN GHC import qualified Data.Text as T #-} |
|||
{-# COMPILE GHC putStrLn = putStrLn . T.unpack #-} |
|||
main : IO ⊤ |
|||
main = putStrLn (show (ack 3 9)) |
|||
-- Output: |
|||
-- 4093 |
|||
</syntaxhighlight> |
|||
The Unicode characters can be entered in Emacs Agda as follows: |
|||
* ℕ : \bN |
|||
* → : \to |
|||
* ⊤ : \top |
|||
Running in Bash: |
|||
<syntaxhighlight lang="bash"> |
|||
agda --compile Ackermann.agda |
agda --compile Ackermann.agda |
||
./Ackermann |
./Ackermann |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
4093 |
4093 |
||
</pre> |
|||
=={{header|ALGOL 60}}== |
|||
{{works with|A60}} |
|||
<syntaxhighlight lang="algol60">begin |
|||
integer procedure ackermann(m,n);value m,n;integer m,n; |
|||
ackermann:=if m=0 then n+1 |
|||
else if n=0 then ackermann(m-1,1) |
|||
else ackermann(m-1,ackermann(m,n-1)); |
|||
integer m,n; |
|||
for m:=0 step 1 until 3 do begin |
|||
for n:=0 step 1 until 6 do |
|||
outinteger(1,ackermann(m,n)); |
|||
outstring(1,"\n") |
|||
end |
|||
end </syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1 2 3 4 5 6 7 |
|||
2 3 4 5 6 7 8 |
|||
3 5 7 9 11 13 15 |
|||
5 13 29 61 125 253 509 |
|||
</pre> |
</pre> |
||
Line 485: | Line 1,025: | ||
{{works with|ALGOL 68G|Any - tested with release mk15-0.8b.fc9.i386}} |
{{works with|ALGOL 68G|Any - tested with release mk15-0.8b.fc9.i386}} |
||
{{works with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release 1.8.8d.fc9.i386}} |
{{works with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release 1.8.8d.fc9.i386}} |
||
< |
<syntaxhighlight lang="algol68">PROC test ackermann = VOID: |
||
BEGIN |
BEGIN |
||
PROC ackermann = (INT m, n)INT: |
PROC ackermann = (INT m, n)INT: |
||
Line 505: | Line 1,045: | ||
OD |
OD |
||
END # test ackermann #; |
END # test ackermann #; |
||
test ackermann</ |
test ackermann</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 512: | Line 1,052: | ||
+3 +5 +7 +9 +11 +13 +15 |
+3 +5 +7 +9 +11 +13 +15 |
||
+5 +13 +29 +61 +125 +253 +509 |
+5 +13 +29 +61 +125 +253 +509 |
||
</pre> |
|||
=={{header|ALGOL W}}== |
|||
{{Trans|ALGOL 60}} |
|||
<syntaxhighlight lang="algolw">begin |
|||
integer procedure ackermann( integer value m,n ) ; |
|||
if m=0 then n+1 |
|||
else if n=0 then ackermann(m-1,1) |
|||
else ackermann(m-1,ackermann(m,n-1)); |
|||
for m := 0 until 3 do begin |
|||
write( ackermann( m, 0 ) ); |
|||
for n := 1 until 6 do writeon( ackermann( m, n ) ); |
|||
end for_m |
|||
end.</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1 2 3 4 5 6 7 |
|||
2 3 4 5 6 7 8 |
|||
3 5 7 9 11 13 15 |
|||
5 13 29 61 125 253 509 |
|||
</pre> |
</pre> |
||
=={{header|APL}}== |
=={{header|APL}}== |
||
{{works with|Dyalog APL}} |
{{works with|Dyalog APL}} |
||
< |
<syntaxhighlight lang="apl">ackermann←{ |
||
0=1⊃⍵:1+2⊃⍵ |
0=1⊃⍵:1+2⊃⍵ |
||
0=2⊃⍵:∇(¯1+1⊃⍵)1 |
0=2⊃⍵:∇(¯1+1⊃⍵)1 |
||
∇(¯1+1⊃⍵),∇(1⊃⍵),¯1+2⊃⍵ |
∇(¯1+1⊃⍵),∇(1⊃⍵),¯1+2⊃⍵ |
||
}</ |
}</syntaxhighlight> |
||
=={{header|AppleScript}}== |
=={{header|AppleScript}}== |
||
<syntaxhighlight lang="applescript">on ackermann(m, n) |
|||
<lang AppleScript>on ackermann(m, n) |
|||
if m is equal to 0 then return n + 1 |
if m is equal to 0 then return n + 1 |
||
if n is equal to 0 then return ackermann(m - 1, 1) |
if n is equal to 0 then return ackermann(m - 1, 1) |
||
return ackermann(m - 1, ackermann(m, n - 1)) |
return ackermann(m - 1, ackermann(m, n - 1)) |
||
end ackermann</ |
end ackermann</syntaxhighlight> |
||
=={{header|Argile}}== |
=={{header|Argile}}== |
||
{{works with|Argile|1.0.0}} |
{{works with|Argile|1.0.0}} |
||
< |
<syntaxhighlight lang="argile">use std |
||
for each (val nat n) from 0 to 6 |
for each (val nat n) from 0 to 6 |
||
Line 541: | Line 1,100: | ||
return (n+1) if m == 0 |
return (n+1) if m == 0 |
||
return (A (m - 1) 1) if n == 0 |
return (A (m - 1) 1) if n == 0 |
||
A (m - 1) (A m (n - 1))</ |
A (m - 1) (A m (n - 1))</syntaxhighlight> |
||
=={{header|ARM Assembly}}== |
|||
{{works with|as|Raspberry Pi <br> or android 32 bits with application Termux}} |
|||
<syntaxhighlight lang="arm assembly"> |
|||
/* ARM assembly Raspberry PI or android 32 bits */ |
|||
/* program ackermann.s */ |
|||
/* REMARK 1 : this program use routines in a include file |
|||
see task Include a file language arm assembly |
|||
for the routine affichageMess conversion10 |
|||
see at end of this program the instruction include */ |
|||
/* for constantes see task include a file in arm assembly */ |
|||
/************************************/ |
|||
/* Constantes */ |
|||
/************************************/ |
|||
.include "../constantes.inc" |
|||
.equ MMAXI, 4 |
|||
.equ NMAXI, 10 |
|||
/*********************************/ |
|||
/* Initialized data */ |
|||
/*********************************/ |
|||
.data |
|||
sMessResult: .asciz "Result for @ @ : @ \n" |
|||
szMessError: .asciz "Overflow !!.\n" |
|||
szCarriageReturn: .asciz "\n" |
|||
/*********************************/ |
|||
/* UnInitialized data */ |
|||
/*********************************/ |
|||
.bss |
|||
sZoneConv: .skip 24 |
|||
/*********************************/ |
|||
/* code section */ |
|||
/*********************************/ |
|||
.text |
|||
.global main |
|||
main: @ entry of program |
|||
mov r3,#0 |
|||
mov r4,#0 |
|||
1: |
|||
mov r0,r3 |
|||
mov r1,r4 |
|||
bl ackermann |
|||
mov r5,r0 |
|||
mov r0,r3 |
|||
ldr r1,iAdrsZoneConv @ else display odd message |
|||
bl conversion10 @ call decimal conversion |
|||
ldr r0,iAdrsMessResult |
|||
ldr r1,iAdrsZoneConv @ insert value conversion in message |
|||
bl strInsertAtCharInc |
|||
mov r6,r0 |
|||
mov r0,r4 |
|||
ldr r1,iAdrsZoneConv @ else display odd message |
|||
bl conversion10 @ call decimal conversion |
|||
mov r0,r6 |
|||
ldr r1,iAdrsZoneConv @ insert value conversion in message |
|||
bl strInsertAtCharInc |
|||
mov r6,r0 |
|||
mov r0,r5 |
|||
ldr r1,iAdrsZoneConv @ else display odd message |
|||
bl conversion10 @ call decimal conversion |
|||
mov r0,r6 |
|||
ldr r1,iAdrsZoneConv @ insert value conversion in message |
|||
bl strInsertAtCharInc |
|||
bl affichageMess |
|||
add r4,#1 |
|||
cmp r4,#NMAXI |
|||
blt 1b |
|||
mov r4,#0 |
|||
add r3,#1 |
|||
cmp r3,#MMAXI |
|||
blt 1b |
|||
100: @ standard end of the program |
|||
mov r0, #0 @ return code |
|||
mov r7, #EXIT @ request to exit program |
|||
svc #0 @ perform the system call |
|||
iAdrszCarriageReturn: .int szCarriageReturn |
|||
iAdrsMessResult: .int sMessResult |
|||
iAdrsZoneConv: .int sZoneConv |
|||
/***************************************************/ |
|||
/* fonction ackermann */ |
|||
/***************************************************/ |
|||
// r0 contains a number m |
|||
// r1 contains a number n |
|||
// r0 return résult |
|||
ackermann: |
|||
push {r1-r2,lr} @ save registers |
|||
cmp r0,#0 |
|||
beq 5f |
|||
movlt r0,#-1 @ error |
|||
blt 100f |
|||
cmp r1,#0 |
|||
movlt r0,#-1 @ error |
|||
blt 100f |
|||
bgt 1f |
|||
sub r0,r0,#1 |
|||
mov r1,#1 |
|||
bl ackermann |
|||
b 100f |
|||
1: |
|||
mov r2,r0 |
|||
sub r1,r1,#1 |
|||
bl ackermann |
|||
mov r1,r0 |
|||
sub r0,r2,#1 |
|||
bl ackermann |
|||
b 100f |
|||
5: |
|||
adds r0,r1,#1 |
|||
bcc 100f |
|||
ldr r0,iAdrszMessError |
|||
bl affichageMess |
|||
bkpt |
|||
100: |
|||
pop {r1-r2,lr} @ restaur registers |
|||
bx lr @ return |
|||
iAdrszMessError: .int szMessError |
|||
/***************************************************/ |
|||
/* ROUTINES INCLUDE */ |
|||
/***************************************************/ |
|||
.include "../affichage.inc" |
|||
</syntaxhighlight> |
|||
{{Output}} |
|||
<pre> |
|||
Result for 0 0 : 1 |
|||
Result for 0 1 : 2 |
|||
Result for 0 2 : 3 |
|||
Result for 0 3 : 4 |
|||
Result for 0 4 : 5 |
|||
Result for 0 5 : 6 |
|||
Result for 0 6 : 7 |
|||
Result for 0 7 : 8 |
|||
Result for 0 8 : 9 |
|||
Result for 0 9 : 10 |
|||
Result for 1 0 : 2 |
|||
Result for 1 1 : 3 |
|||
Result for 1 2 : 4 |
|||
Result for 1 3 : 5 |
|||
Result for 1 4 : 6 |
|||
Result for 1 5 : 7 |
|||
Result for 1 6 : 8 |
|||
Result for 1 7 : 9 |
|||
Result for 1 8 : 10 |
|||
Result for 1 9 : 11 |
|||
Result for 2 0 : 3 |
|||
Result for 2 1 : 5 |
|||
Result for 2 2 : 7 |
|||
Result for 2 3 : 9 |
|||
Result for 2 4 : 11 |
|||
Result for 2 5 : 13 |
|||
Result for 2 6 : 15 |
|||
Result for 2 7 : 17 |
|||
Result for 2 8 : 19 |
|||
Result for 2 9 : 21 |
|||
Result for 3 0 : 5 |
|||
Result for 3 1 : 13 |
|||
Result for 3 2 : 29 |
|||
Result for 3 3 : 61 |
|||
Result for 3 4 : 125 |
|||
Result for 3 5 : 253 |
|||
Result for 3 6 : 509 |
|||
Result for 3 7 : 1021 |
|||
Result for 3 8 : 2045 |
|||
Result for 3 9 : 4093 |
|||
</pre> |
|||
=={{header|Arturo}}== |
|||
<syntaxhighlight lang="rebol">ackermann: function [m,n][ |
|||
(m=0)? -> n+1 [ |
|||
(n=0)? -> ackermann m-1 1 |
|||
-> ackermann m-1 ackermann m n-1 |
|||
] |
|||
] |
|||
loop 0..3 'a [ |
|||
loop 0..4 'b [ |
|||
print ["ackermann" a b "=>" ackermann a b] |
|||
] |
|||
]</syntaxhighlight> |
|||
{{out}} |
|||
<pre>ackermann 0 0 => 1 |
|||
ackermann 0 1 => 2 |
|||
ackermann 0 2 => 3 |
|||
ackermann 0 3 => 4 |
|||
ackermann 0 4 => 5 |
|||
ackermann 1 0 => 2 |
|||
ackermann 1 1 => 3 |
|||
ackermann 1 2 => 4 |
|||
ackermann 1 3 => 5 |
|||
ackermann 1 4 => 6 |
|||
ackermann 2 0 => 3 |
|||
ackermann 2 1 => 5 |
|||
ackermann 2 2 => 7 |
|||
ackermann 2 3 => 9 |
|||
ackermann 2 4 => 11 |
|||
ackermann 3 0 => 5 |
|||
ackermann 3 1 => 13 |
|||
ackermann 3 2 => 29 |
|||
ackermann 3 3 => 61 |
|||
ackermann 3 4 => 125</pre> |
|||
=={{header|ATS}}== |
=={{header|ATS}}== |
||
< |
<syntaxhighlight lang="ats">fun ackermann |
||
{m,n:nat} .<m,n>. |
{m,n:nat} .<m,n>. |
||
(m: int m, n: int n): Nat = |
(m: int m, n: int n): Nat = |
||
Line 551: | Line 1,312: | ||
| (_, 0) =>> ackermann (m-1, 1) |
| (_, 0) =>> ackermann (m-1, 1) |
||
| (_, _) =>> ackermann (m-1, ackermann (m, n-1)) |
| (_, _) =>> ackermann (m-1, ackermann (m, n-1)) |
||
// end of [ackermann]</ |
// end of [ackermann]</syntaxhighlight> |
||
=={{header|AutoHotkey}}== |
=={{header|AutoHotkey}}== |
||
< |
<syntaxhighlight lang="autohotkey">A(m, n) { |
||
If (m > 0) && (n = 0) |
If (m > 0) && (n = 0) |
||
Return A(m-1,1) |
Return A(m-1,1) |
||
Line 564: | Line 1,325: | ||
; Example: |
; Example: |
||
MsgBox, % "A(1,2) = " A(1,2)</ |
MsgBox, % "A(1,2) = " A(1,2)</syntaxhighlight> |
||
=={{header|AutoIt}}== |
=={{header|AutoIt}}== |
||
=== Classical version === |
=== Classical version === |
||
< |
<syntaxhighlight lang="autoit">Func Ackermann($m, $n) |
||
If ($m = 0) Then |
If ($m = 0) Then |
||
Return $n+1 |
Return $n+1 |
||
Line 578: | Line 1,339: | ||
EndIf |
EndIf |
||
EndIf |
EndIf |
||
EndFunc</ |
EndFunc</syntaxhighlight> |
||
=== Classical + cache implementation === |
=== Classical + cache implementation === |
||
Line 584: | Line 1,345: | ||
This version works way faster than the classical one: Ackermann(3, 5) runs in 12,7 ms, while the classical version takes 402,2 ms. |
This version works way faster than the classical one: Ackermann(3, 5) runs in 12,7 ms, while the classical version takes 402,2 ms. |
||
< |
<syntaxhighlight lang="autoit">Global $ackermann[2047][2047] ; Set the size to whatever you want |
||
Func Ackermann($m, $n) |
Func Ackermann($m, $n) |
||
If ($ackermann[$m][$n] <> 0) Then |
If ($ackermann[$m][$n] <> 0) Then |
||
Line 601: | Line 1,362: | ||
Return $return |
Return $return |
||
EndIf |
EndIf |
||
EndFunc ;==>Ackermann</ |
EndFunc ;==>Ackermann</syntaxhighlight> |
||
=={{header|AWK}}== |
=={{header|AWK}}== |
||
< |
<syntaxhighlight lang="awk">function ackermann(m, n) |
||
{ |
{ |
||
if ( m == 0 ) { |
if ( m == 0 ) { |
||
Line 621: | Line 1,382: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Babel}}== |
=={{header|Babel}}== |
||
< |
<syntaxhighlight lang="babel">main: |
||
{((0 0) (0 1) (0 2) |
{((0 0) (0 1) (0 2) |
||
(0 3) (0 4) (1 0) |
(0 3) (0 4) (1 0) |
||
Line 655: | Line 1,416: | ||
if } |
if } |
||
zero?!: { 0 = } |
zero?!: { 0 = }</syntaxhighlight> |
||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre>A(0 0 ) = 1 |
||
A(0 0 ) = 1 |
|||
A(0 1 ) = 2 |
A(0 1 ) = 2 |
||
A(0 2 ) = 3 |
A(0 2 ) = 3 |
||
Line 679: | Line 1,438: | ||
=={{header|BASIC}}== |
=={{header|BASIC}}== |
||
==={{header|Applesoft BASIC}}=== |
|||
{{works with|QuickBasic|4.5}} |
|||
{{works with|Chipmunk Basic}} |
|||
BASIC runs out of stack space very quickly. |
|||
<syntaxhighlight lang="basic">100 DIM R%(2900),M(2900),N(2900) |
|||
The call <tt>ack(3, 4)</tt> gives a stack error. |
|||
110 FOR M = 0 TO 3 |
|||
<lang qbasic>DECLARE FUNCTION ack! (m!, n!) |
|||
120 FOR N = 0 TO 4 |
|||
130 GOSUB 200"ACKERMANN |
|||
140 PRINT "ACK("M","N") = "ACK |
|||
150 NEXT N, M |
|||
160 END |
|||
200 M(SP) = M |
|||
FUNCTION ack (m!, n!) |
|||
210 N(SP) = N |
|||
IF m = 0 THEN ack = n + 1 |
|||
REM A(M - 1, A(M, N - 1)) |
|||
IF m > 0 AND n = 0 THEN |
|||
220 IF M > 0 AND N > 0 THEN N = N - 1 : R%(SP) = 0 : SP = SP + 1 : GOTO 200 |
|||
END IF |
|||
IF m > 0 AND n > 0 THEN |
|||
ack = ack(m - 1, ack(m, n - 1)) |
|||
END IF |
|||
END FUNCTION</lang> |
|||
REM A(M - 1, 1) |
|||
=={{header|BASIC256}}== |
|||
230 IF M > 0 THEN M = M - 1 : N = 1 : R%(SP) = 1 : SP = SP + 1 : GOTO 200 |
|||
<lang basic256>dim stack(5000, 3) # BASIC-256 lacks functions (as of ver. 0.9.6.66) |
|||
REM N + 1 |
|||
240 ACK = N + 1 |
|||
REM RETURN |
|||
250 M = M(SP) : N = N(SP) : IF SP = 0 THEN RETURN |
|||
260 FOR SP = SP - 1 TO 0 STEP -1 : IF R%(SP) THEN M = M(SP) : N = N(SP) : NEXT SP : SP = 0 : RETURN |
|||
270 M = M - 1 : N = ACK : R%(SP) = 1 : SP = SP + 1 : GOTO 200</syntaxhighlight> |
|||
==={{header|BASIC256}}=== |
|||
<syntaxhighlight lang="basic256">dim stack(5000, 3) # BASIC-256 lacks functions (as of ver. 0.9.6.66) |
|||
stack[0,0] = 3 # M |
stack[0,0] = 3 # M |
||
stack[0,1] = 7 # N |
stack[0,1] = 7 # N |
||
Line 728: | Line 1,498: | ||
stack[lev-1,2] = stack[lev,2] |
stack[lev-1,2] = stack[lev,2] |
||
lev = lev-1 |
lev = lev-1 |
||
return</ |
return</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> A(3,7) = 1021</pre> |
|||
<pre> |
|||
A(3,7) = 1021 |
|||
</pre> |
|||
< |
<syntaxhighlight lang="basic256"># BASIC256 since 0.9.9.1 supports functions |
||
for m = 0 to 3 |
for m = 0 to 3 |
||
for n = 0 to 4 |
for n = 0 to 4 |
||
Line 752: | Line 1,520: | ||
endif |
endif |
||
end if |
end if |
||
end function</ |
end function</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre>0 0 1 |
||
0 0 1 |
|||
0 1 2 |
0 1 2 |
||
0 2 3 |
0 2 3 |
||
Line 776: | Line 1,542: | ||
3 3 61 |
3 3 61 |
||
3 4 125</pre> |
3 4 125</pre> |
||
==={{header|BBC BASIC}}=== |
|||
<syntaxhighlight lang="bbcbasic"> PRINT FNackermann(3, 7) |
|||
END |
|||
DEF FNackermann(M%, N%) |
|||
IF M% = 0 THEN = N% + 1 |
|||
IF N% = 0 THEN = FNackermann(M% - 1, 1) |
|||
= FNackermann(M% - 1, FNackermann(M%, N%-1))</syntaxhighlight> |
|||
==={{header|Chipmunk Basic}}=== |
|||
{{works with|Chipmunk Basic|3.6.4}} |
|||
<syntaxhighlight lang="qbasic">100 for m = 0 to 4 |
|||
110 print using "###";m; |
|||
120 for n = 0 to 6 |
|||
130 if m = 4 and n = 1 then goto 160 |
|||
140 print using "######";ack(m,n); |
|||
150 next n |
|||
160 print |
|||
170 next m |
|||
180 end |
|||
190 sub ack(m,n) |
|||
200 if m = 0 then ack = n+1 |
|||
210 if m > 0 and n = 0 then ack = ack(m-1,1) |
|||
220 if m > 0 and n > 0 then ack = ack(m-1,ack(m,n-1)) |
|||
230 end sub</syntaxhighlight> |
|||
==={{header|True BASIC}}=== |
|||
<syntaxhighlight lang="qbasic">FUNCTION ack(m, n) |
|||
IF m = 0 THEN LET ack = n+1 |
|||
IF m > 0 AND n = 0 THEN LET ack = ack(m-1, 1) |
|||
IF m > 0 AND n > 0 THEN LET ack = ack(m-1, ack(m, n-1)) |
|||
END FUNCTION |
|||
FOR m = 0 TO 4 |
|||
PRINT USING "###": m; |
|||
FOR n = 0 TO 8 |
|||
! A(4, 1) OR higher will RUN OUT of stack memory (default 1M) |
|||
! change n = 1 TO n = 2 TO calculate A(4, 2), increase stack! |
|||
IF m = 4 AND n = 1 THEN EXIT FOR |
|||
PRINT USING "######": ack(m, n); |
|||
NEXT n |
|||
PRINT |
|||
NEXT m |
|||
END</syntaxhighlight> |
|||
==={{header|QuickBasic}}=== |
|||
{{works with|QuickBasic|4.5}} |
|||
BASIC runs out of stack space very quickly. |
|||
The call <tt>ack(3, 4)</tt> gives a stack error. |
|||
<syntaxhighlight lang="qbasic">DECLARE FUNCTION ack! (m!, n!) |
|||
FUNCTION ack (m!, n!) |
|||
IF m = 0 THEN ack = n + 1 |
|||
IF m > 0 AND n = 0 THEN |
|||
ack = ack(m - 1, 1) |
|||
END IF |
|||
IF m > 0 AND n > 0 THEN |
|||
ack = ack(m - 1, ack(m, n - 1)) |
|||
END IF |
|||
END FUNCTION</syntaxhighlight> |
|||
=={{header|Batch File}}== |
=={{header|Batch File}}== |
||
Had trouble with this, so called in the gurus at [http://stackoverflow.com/questions/2680668/what-is-wrong-with-this-recursive-windows-cmd-script-it-wont-do-ackermann-prope StackOverflow]. Thanks to Patrick Cuff for pointing out where I was going wrong. |
Had trouble with this, so called in the gurus at [http://stackoverflow.com/questions/2680668/what-is-wrong-with-this-recursive-windows-cmd-script-it-wont-do-ackermann-prope StackOverflow]. Thanks to Patrick Cuff for pointing out where I was going wrong. |
||
< |
<syntaxhighlight lang="dos">::Ackermann.cmd |
||
@echo off |
@echo off |
||
set depth=0 |
set depth=0 |
||
Line 809: | Line 1,638: | ||
set t=%errorlevel% |
set t=%errorlevel% |
||
set /a depth-=1 |
set /a depth-=1 |
||
if %depth%==0 ( exit %t% ) else ( exit /b %t% )</ |
if %depth%==0 ( exit %t% ) else ( exit /b %t% )</syntaxhighlight> |
||
Because of the <code>exit</code> statements, running this bare closes one's shell, so this test routine handles the calling of Ackermann.cmd |
Because of the <code>exit</code> statements, running this bare closes one's shell, so this test routine handles the calling of Ackermann.cmd |
||
< |
<syntaxhighlight lang="dos">::Ack.cmd |
||
@echo off |
@echo off |
||
cmd/c ackermann.cmd %1 %2 |
cmd/c ackermann.cmd %1 %2 |
||
echo Ackermann(%1, %2)=%errorlevel%</ |
echo Ackermann(%1, %2)=%errorlevel%</syntaxhighlight> |
||
A few test runs: |
A few test runs: |
||
<pre>D:\Documents and Settings\Bruce>ack 0 4 |
<pre>D:\Documents and Settings\Bruce>ack 0 4 |
||
Line 827: | Line 1,656: | ||
D:\Documents and Settings\Bruce>ack 3 4 |
D:\Documents and Settings\Bruce>ack 3 4 |
||
Ackermann(3, 4)=125</pre> |
Ackermann(3, 4)=125</pre> |
||
=={{header|BBC BASIC}}== |
|||
<lang bbcbasic> PRINT FNackermann(3, 7) |
|||
END |
|||
DEF FNackermann(M%, N%) |
|||
IF M% = 0 THEN = N% + 1 |
|||
IF N% = 0 THEN = FNackermann(M% - 1, 1) |
|||
= FNackermann(M% - 1, FNackermann(M%, N%-1))</lang> |
|||
=={{header|bc}}== |
=={{header|bc}}== |
||
Line 841: | Line 1,661: | ||
{{works with|OpenBSD bc}} |
{{works with|OpenBSD bc}} |
||
{{Works with|GNU bc}} |
{{Works with|GNU bc}} |
||
< |
<syntaxhighlight lang="bc">define ack(m, n) { |
||
if ( m == 0 ) return (n+1); |
if ( m == 0 ) return (n+1); |
||
if ( n == 0 ) return (ack(m-1, 1)); |
if ( n == 0 ) return (ack(m-1, 1)); |
||
Line 852: | Line 1,672: | ||
} |
} |
||
} |
} |
||
quit</ |
quit</syntaxhighlight> |
||
=={{header|BCPL}}== |
=={{header|BCPL}}== |
||
< |
<syntaxhighlight lang="bcpl">GET "libhdr" |
||
LET ack(m, n) = m=0 -> n+1, |
LET ack(m, n) = m=0 -> n+1, |
||
Line 865: | Line 1,685: | ||
writef("ack(%n, %n) = %n*n", m, n, ack(m,n)) |
writef("ack(%n, %n) = %n*n", m, n, ack(m,n)) |
||
RESULTIS 0 |
RESULTIS 0 |
||
}</ |
}</syntaxhighlight> |
||
=={{header|beeswax}}== |
=={{header|beeswax}}== |
||
Line 871: | Line 1,691: | ||
Iterative slow version: |
Iterative slow version: |
||
< |
<syntaxhighlight lang="beeswax"> |
||
>M?f@h@gMf@h3yzp if m>0 and n>0 => replace m,n with m-1,m,n-1 |
>M?f@h@gMf@h3yzp if m>0 and n>0 => replace m,n with m-1,m,n-1 |
||
>@h@g'b?1f@h@gM?f@hzp if m>0 and n=0 => replace m,n with m-1,1 |
>@h@g'b?1f@h@gM?f@hzp if m>0 and n=0 => replace m,n with m-1,1 |
||
Line 877: | Line 1,697: | ||
>I; |
>I; |
||
b < < |
b < < |
||
</syntaxhighlight> |
|||
</lang> |
|||
A functional and recursive realization of the version above. Functions are realized by direct calls of functions via jumps (instruction <code>J</code>) to the entry points of two distinct functions: |
A functional and recursive realization of the version above. Functions are realized by direct calls of functions via jumps (instruction <code>J</code>) to the entry points of two distinct functions: |
||
Line 887: | Line 1,707: | ||
Each block of <code>1FJ</code> or <code>1fFJ</code> in the code is a call of the Ackermann function itself. |
Each block of <code>1FJ</code> or <code>1fFJ</code> in the code is a call of the Ackermann function itself. |
||
< |
<syntaxhighlight lang="beeswax">Ag~1?Lp1~2@g'p?g?Pf1FJ Ackermann function. if m=0 => run Ackermann function (m, n+1) |
||
xI; x@g'p??@Mf1fFJ if m>0 and n=0 => run Ackermann (m-1,1) |
xI; x@g'p??@Mf1fFJ if m>0 and n=0 => run Ackermann (m-1,1) |
||
xM@~gM??f~f@f1FJ if m>0 and n>0 => run Ackermann(m,Ackermann(m-1,n-1)) |
xM@~gM??f~f@f1FJ if m>0 and n>0 => run Ackermann(m,Ackermann(m-1,n-1)) |
||
_ii1FJ input function. Input m,n, then execute Ackermann(m,n)</ |
_ii1FJ input function. Input m,n, then execute Ackermann(m,n)</syntaxhighlight> |
||
Highly optimized and fast version, returns A(4,1)/A(5,0) almost instantaneously: |
Highly optimized and fast version, returns A(4,1)/A(5,0) almost instantaneously: |
||
< |
<syntaxhighlight lang="beeswax"> |
||
>Mf@Ph?@g@2h@Mf@Php if m>4 and n>0 => replace m,n with m-1,m,n-1 |
>Mf@Ph?@g@2h@Mf@Php if m>4 and n>0 => replace m,n with m-1,m,n-1 |
||
>~4~L#1~2hg'd?1f@hgM?f2h p if m>4 and n=0 => replace m,n with m-1,1 |
>~4~L#1~2hg'd?1f@hgM?f2h p if m>4 and n=0 => replace m,n with m-1,1 |
||
Line 904: | Line 1,724: | ||
z b < < < |
z b < < < |
||
d < |
d < |
||
</syntaxhighlight> |
|||
</lang> |
|||
Higher values than A(4,1)/(5,0) lead to UInt64 wraparound, support for numbers bigger than 2^64-1 is not implemented in these solutions. |
Higher values than A(4,1)/(5,0) lead to UInt64 wraparound, support for numbers bigger than 2^64-1 is not implemented in these solutions. |
||
Line 913: | Line 1,733: | ||
{{trans|ERRE}} |
{{trans|ERRE}} |
||
Since Befunge-93 doesn't have recursive capabilities we need to use an iterative algorithm. |
Since Befunge-93 doesn't have recursive capabilities we need to use an iterative algorithm. |
||
< |
<syntaxhighlight lang="befunge">&>&>vvg0>#0\#-:#1_1v |
||
@v:\<vp0 0:-1<\+< |
@v:\<vp0 0:-1<\+< |
||
^>00p>:#^_$1+\:#^_$. |
^>00p>:#^_$1+\:#^_$. |
||
</syntaxhighlight> |
|||
</lang> |
|||
===Befunge-98=== |
===Befunge-98=== |
||
{{works with|CCBI|2.1}} |
{{works with|CCBI|2.1}} |
||
< |
<syntaxhighlight lang="befunge">r[1&&{0 |
||
>v |
>v |
||
j |
j |
||
Line 927: | Line 1,747: | ||
^ v:\_$1+ |
^ v:\_$1+ |
||
\^v_$1\1- |
\^v_$1\1- |
||
u^>1-0fp:1-\0fg101-</ |
u^>1-0fp:1-\0fg101-</syntaxhighlight> |
||
The program reads two integers (first m, then n) from command line, idles around funge space, then outputs the result of the Ackerman function. |
The program reads two integers (first m, then n) from command line, idles around funge space, then outputs the result of the Ackerman function. |
||
Since the latter is calculated truly recursively, the execution time becomes unwieldy for most m>3. |
Since the latter is calculated truly recursively, the execution time becomes unwieldy for most m>3. |
||
=={{header|Binary Lambda Calculus}}== |
|||
The Ackermann function on Church numerals (arbitrary precision), as shown in https://github.com/tromp/AIT/blob/master/fast_growing_and_conjectures/ackermann.lam is the 63 bit BLC |
|||
program |
|||
<pre>010000010110000001010111110101100010110000000011100101111011010</pre> |
|||
=={{header|BQN}}== |
|||
<syntaxhighlight lang="bqn">A ← { |
|||
A 0‿n: n+1; |
|||
A m‿0: A (m-1)‿1; |
|||
A m‿n: A (m-1)‿(A m‿(n-1)) |
|||
}</syntaxhighlight> |
|||
Example usage: |
|||
<syntaxhighlight lang="text"> A 0‿3 |
|||
4 |
|||
A 1‿4 |
|||
6 |
|||
A 2‿4 |
|||
11 |
|||
A 3‿4 |
|||
125</syntaxhighlight> |
|||
=={{header|Bracmat}}== |
=={{header|Bracmat}}== |
||
Line 936: | Line 1,779: | ||
The value of A(4,1) cannot be computed due to stack overflow. |
The value of A(4,1) cannot be computed due to stack overflow. |
||
It can compute A(3,9) (4093), but probably not A(3,10) |
It can compute A(3,9) (4093), but probably not A(3,10) |
||
< |
<syntaxhighlight lang="bracmat">( Ack |
||
= m n |
= m n |
||
. !arg:(?m,?n) |
. !arg:(?m,?n) |
||
Line 943: | Line 1,786: | ||
| Ack$(!m+-1,Ack$(!m,!n+-1)) |
| Ack$(!m+-1,Ack$(!m,!n+-1)) |
||
) |
) |
||
);</ |
);</syntaxhighlight> |
||
The second version is a purely non-recursive solution that easily can compute A(4,1). |
The second version is a purely non-recursive solution that easily can compute A(4,1). |
||
The program uses a stack for Ackermann function calls that are to be evaluated, but that cannot be computed given the currently known function values - the "known unknowns". |
The program uses a stack for Ackermann function calls that are to be evaluated, but that cannot be computed given the currently known function values - the "known unknowns". |
||
Line 951: | Line 1,794: | ||
Although all known values are stored in the hash table, the converse is not true: an element in the hash table is either a "known known" or an "unknown unknown" associated with an "known unknown". |
Although all known values are stored in the hash table, the converse is not true: an element in the hash table is either a "known known" or an "unknown unknown" associated with an "known unknown". |
||
< |
<syntaxhighlight lang="bracmat"> ( A |
||
= m n value key eq chain |
= m n value key eq chain |
||
, find insert future stack va val |
, find insert future stack va val |
||
Line 1,011: | Line 1,854: | ||
& !value |
& !value |
||
) |
) |
||
& new$hash:?cache</ |
& new$hash:?cache</syntaxhighlight> |
||
{{out|Some results}} |
{{out|Some results}} |
||
<pre> |
<pre> |
||
Line 1,020: | Line 1,863: | ||
</pre> |
</pre> |
||
The last solution is a recursive solution that employs some extra formulas, inspired by the Common Lisp solution further down. |
The last solution is a recursive solution that employs some extra formulas, inspired by the Common Lisp solution further down. |
||
< |
<syntaxhighlight lang="bracmat">( AckFormula |
||
= m n |
= m n |
||
. !arg:(?m,?n) |
. !arg:(?m,?n) |
||
Line 1,030: | Line 1,873: | ||
| AckFormula$(!m+-1,AckFormula$(!m,!n+-1)) |
| AckFormula$(!m+-1,AckFormula$(!m,!n+-1)) |
||
) |
) |
||
)</ |
)</syntaxhighlight> |
||
{{Out|Some results}} |
{{Out|Some results}} |
||
<pre>AckFormula$(4,1):65533 |
<pre>AckFormula$(4,1):65533 |
||
Line 1,038: | Line 1,881: | ||
=={{header|Brat}}== |
=={{header|Brat}}== |
||
< |
<syntaxhighlight lang="brat">ackermann = { m, n | |
||
when { m == 0 } { n + 1 } |
when { m == 0 } { n + 1 } |
||
{ m > 0 && n == 0 } { ackermann(m - 1, 1) } |
{ m > 0 && n == 0 } { ackermann(m - 1, 1) } |
||
Line 1,044: | Line 1,887: | ||
} |
} |
||
p ackermann 3, 4 #Prints 125</ |
p ackermann 3, 4 #Prints 125</syntaxhighlight> |
||
=={{header|Bruijn}}== |
|||
<syntaxhighlight lang="bruijn">:import std/Combinator . |
|||
:import std/Number/Unary U |
|||
:import std/Math . |
|||
# unary ackermann |
|||
ackermann-unary [0 [[U.inc 0 1 (+1u)]] U.inc] |
|||
:test (ackermann-unary (+0u) (+0u)) ((+1u)) |
|||
:test (ackermann-unary (+3u) (+4u)) ((+125u)) |
|||
# ternary ackermann (lower space complexity) |
|||
ackermann-ternary y [[[=?1 ++0 (=?0 (2 --1 (+1)) (2 --1 (2 1 --0)))]]] |
|||
:test ((ackermann-ternary (+0) (+0)) =? (+1)) ([[1]]) |
|||
:test ((ackermann-ternary (+3) (+4)) =? (+125)) ([[1]])</syntaxhighlight> |
|||
=={{header|C}}== |
=={{header|C}}== |
||
Straightforward implementation per Ackermann definition: |
Straightforward implementation per Ackermann definition: |
||
< |
<syntaxhighlight lang="c">#include <stdio.h> |
||
int ackermann(int m, int n) |
int ackermann(int m, int n) |
||
Line 1,065: | Line 1,925: | ||
return 0; |
return 0; |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>A(0, 0) = 1 |
<pre>A(0, 0) = 1 |
||
Line 1,088: | Line 1,948: | ||
A(4, 1) = 65533</pre> |
A(4, 1) = 65533</pre> |
||
Ackermann function makes <i>a lot</i> of recursive calls, so the above program is a bit naive. We need to be slightly less naive, by doing some simple caching: |
Ackermann function makes <i>a lot</i> of recursive calls, so the above program is a bit naive. We need to be slightly less naive, by doing some simple caching: |
||
< |
<syntaxhighlight lang="c">#include <stdio.h> |
||
#include <stdlib.h> |
#include <stdlib.h> |
||
#include <string.h> |
#include <string.h> |
||
Line 1,128: | Line 1,988: | ||
return 0; |
return 0; |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>A(0, 0) = 1 |
<pre>A(0, 0) = 1 |
||
Line 1,153: | Line 2,013: | ||
But see, <code>A(4, 2) = A(3, A(4, 1)) = A(3, 65533) = A(2, A(3, 65532)) = ...</code> you can see how fast it blows up. In fact, no amount of caching will help you calculate large m values; on the machine I use A(4, 2) segfaults because the recursions run out of stack space--not a whole lot I can do about it. At least it runs out of stack space <i>quickly</i>, unlike the first solution... |
But see, <code>A(4, 2) = A(3, A(4, 1)) = A(3, 65533) = A(2, A(3, 65532)) = ...</code> you can see how fast it blows up. In fact, no amount of caching will help you calculate large m values; on the machine I use A(4, 2) segfaults because the recursions run out of stack space--not a whole lot I can do about it. At least it runs out of stack space <i>quickly</i>, unlike the first solution... |
||
A couple of alternative approaches... |
|||
=={{header|C sharp}}== |
|||
<syntaxhighlight lang="c">/* Thejaka Maldeniya */ |
|||
#include <conio.h> |
|||
unsigned long long HR(unsigned int n, unsigned long long a, unsigned long long b) { |
|||
// (Internal) Recursive Hyperfunction: Perform a Hyperoperation... |
|||
unsigned long long r = 1; |
|||
while(b--) |
|||
r = n - 3 ? HR(n - 1, a, r) : /* Exponentiation */ r * a; |
|||
return r; |
|||
} |
|||
unsigned long long H(unsigned int n, unsigned long long a, unsigned long long b) { |
|||
// Hyperfunction (Recursive-Iterative-O(1) Hybrid): Perform a Hyperoperation... |
|||
switch(n) { |
|||
case 0: |
|||
// Increment |
|||
return ++b; |
|||
case 1: |
|||
// Addition |
|||
return a + b; |
|||
case 2: |
|||
// Multiplication |
|||
return a * b; |
|||
} |
|||
return HR(n, a, b); |
|||
} |
|||
unsigned long long APH(unsigned int m, unsigned int n) { |
|||
// Ackermann-Péter Function (Recursive-Iterative-O(1) Hybrid) |
|||
return H(m, 2, n + 3) - 3; |
|||
} |
|||
unsigned long long * p = 0; |
|||
unsigned long long APRR(unsigned int m, unsigned int n) { |
|||
if (!m) return ++n; |
|||
unsigned long long r = p ? p[m] : APRR(m - 1, 1); |
|||
--m; |
|||
while(n--) |
|||
r = APRR(m, r); |
|||
return r; |
|||
} |
|||
unsigned long long APRA(unsigned int m, unsigned int n) { |
|||
return |
|||
m ? |
|||
n ? |
|||
APRR(m, n) |
|||
: p ? p[m] : APRA(--m, 1) |
|||
: ++n |
|||
; |
|||
} |
|||
unsigned long long APR(unsigned int m, unsigned int n) { |
|||
unsigned long long r = 0; |
|||
// Allocate |
|||
p = (unsigned long long *) malloc(sizeof(unsigned long long) * (m + 1)); |
|||
// Initialize |
|||
for(; r <= m; ++r) |
|||
p[r] = r ? APRA(r - 1, 1) : APRA(r, 0); |
|||
// Calculate |
|||
r = APRA(m, n); |
|||
// Free |
|||
free(p); |
|||
return r; |
|||
} |
|||
unsigned long long AP(unsigned int m, unsigned int n) { |
|||
return APH(m, n); |
|||
return APR(m, n); |
|||
} |
|||
int main(int n, char ** a) { |
|||
unsigned int M, N; |
|||
if (n != 3) { |
|||
printf("Usage: %s <m> <n>\n", *a); |
|||
return 1; |
|||
} |
|||
printf("AckermannPeter(%u, %u) = %llu\n", M = atoi(a[1]), N = atoi(a[2]), AP(M, N)); |
|||
//printf("\nPress any key..."); |
|||
//getch(); |
|||
return 0; |
|||
}</syntaxhighlight> |
|||
A couple of more iterative techniques... |
|||
<syntaxhighlight lang="c">/* Thejaka Maldeniya */ |
|||
#include <conio.h> |
|||
unsigned long long HI(unsigned int n, unsigned long long a, unsigned long long b) { |
|||
// Hyperfunction (Iterative): Perform a Hyperoperation... |
|||
unsigned long long *I, r = 1; |
|||
unsigned int N = n - 3; |
|||
if (!N) |
|||
// Exponentiation |
|||
while(b--) |
|||
r *= a; |
|||
else if(b) { |
|||
n -= 2; |
|||
// Allocate |
|||
I = (unsigned long long *) malloc(sizeof(unsigned long long) * n--); |
|||
// Initialize |
|||
I[n] = b; |
|||
// Calculate |
|||
for(;;) { |
|||
if(I[n]) { |
|||
--I[n]; |
|||
if (n) |
|||
I[--n] = r, r = 1; |
|||
else |
|||
r *= a; |
|||
} else |
|||
for(;;) |
|||
if (n == N) |
|||
goto a; |
|||
else if(I[++n]) |
|||
break; |
|||
} |
|||
a: |
|||
// Free |
|||
free(I); |
|||
} |
|||
return r; |
|||
} |
|||
unsigned long long H(unsigned int n, unsigned long long a, unsigned long long b) { |
|||
// Hyperfunction (Iterative-O(1) Hybrid): Perform a Hyperoperation... |
|||
switch(n) { |
|||
case 0: |
|||
// Increment |
|||
return ++b; |
|||
case 1: |
|||
// Addition |
|||
return a + b; |
|||
case 2: |
|||
// Multiplication |
|||
return a * b; |
|||
} |
|||
return HI(n, a, b); |
|||
} |
|||
unsigned long long APH(unsigned int m, unsigned int n) { |
|||
// Ackermann-Péter Function (Recursive-Iterative-O(1) Hybrid) |
|||
return H(m, 2, n + 3) - 3; |
|||
} |
|||
unsigned long long * p = 0; |
|||
unsigned long long APIA(unsigned int m, unsigned int n) { |
|||
if (!m) return ++n; |
|||
// Initialize |
|||
unsigned long long *I, r = p ? p[m] : APIA(m - 1, 1); |
|||
unsigned int M = m; |
|||
if (n) { |
|||
// Allocate |
|||
I = (unsigned long long *) malloc(sizeof(unsigned long long) * (m + 1)); |
|||
// Initialize |
|||
I[m] = n; |
|||
// Calculate |
|||
for(;;) { |
|||
if(I[m]) { |
|||
if (m) |
|||
--I[m], I[--m] = r, r = p ? p[m] : APIA(m - 1, 1); |
|||
else |
|||
r += I[m], I[m] = 0; |
|||
} else |
|||
for(;;) |
|||
if (m == M) |
|||
goto a; |
|||
else if(I[++m]) |
|||
break; |
|||
} |
|||
a: |
|||
// Free |
|||
free(I); |
|||
} |
|||
return r; |
|||
} |
|||
unsigned long long API(unsigned int m, unsigned int n) { |
|||
unsigned long long r = 0; |
|||
// Allocate |
|||
p = (unsigned long long *) malloc(sizeof(unsigned long long) * (m + 1)); |
|||
// Initialize |
|||
for(; r <= m; ++r) |
|||
p[r] = r ? APIA(r - 1, 1) : APIA(r, 0); |
|||
// Calculate |
|||
r = APIA(m, n); |
|||
// Free |
|||
free(p); |
|||
return r; |
|||
} |
|||
unsigned long long AP(unsigned int m, unsigned int n) { |
|||
return APH(m, n); |
|||
return API(m, n); |
|||
} |
|||
int main(int n, char ** a) { |
|||
unsigned int M, N; |
|||
if (n != 3) { |
|||
printf("Usage: %s <m> <n>\n", *a); |
|||
return 1; |
|||
} |
|||
printf("AckermannPeter(%u, %u) = %llu\n", M = atoi(a[1]), N = atoi(a[2]), AP(M, N)); |
|||
//printf("\nPress any key..."); |
|||
//getch(); |
|||
return 0; |
|||
}</syntaxhighlight> |
|||
A few further tweaks/optimizations may be possible. |
|||
=={{header|C sharp|C#}}== |
|||
===Basic Version=== |
===Basic Version=== |
||
< |
<syntaxhighlight lang="csharp">using System; |
||
class Program |
class Program |
||
{ |
{ |
||
Line 1,187: | Line 2,300: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 1,213: | Line 2,326: | ||
===Efficient Version=== |
===Efficient Version=== |
||
< |
<syntaxhighlight lang="csharp"> |
||
using System; |
using System; |
||
using System.Numerics; |
using System.Numerics; |
||
Line 1,341: | Line 2,454: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
Possibly the most efficient implementation of Ackermann in C#. It successfully runs Ack(4,2) when executed in Visual Studio. Don't forget to add a reference to System.Numerics. |
Possibly the most efficient implementation of Ackermann in C#. It successfully runs Ack(4,2) when executed in Visual Studio. Don't forget to add a reference to System.Numerics. |
||
Line 1,347: | Line 2,460: | ||
===Basic version=== |
===Basic version=== |
||
< |
<syntaxhighlight lang="cpp">#include <iostream> |
||
unsigned int ackermann(unsigned int m, unsigned int n) { |
unsigned int ackermann(unsigned int m, unsigned int n) { |
||
Line 1,366: | Line 2,479: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
===Efficient version=== |
===Efficient version=== |
||
Line 1,372: | Line 2,485: | ||
C++11 with boost's big integer type. Compile with: |
C++11 with boost's big integer type. Compile with: |
||
g++ -std=c++11 -I /path/to/boost ackermann.cpp. |
g++ -std=c++11 -I /path/to/boost ackermann.cpp. |
||
< |
<syntaxhighlight lang="cpp">#include <iostream> |
||
#include <sstream> |
#include <sstream> |
||
#include <string> |
#include <string> |
||
Line 1,425: | Line 2,538: | ||
<< text.substr(0, 80) << "\n...\n" |
<< text.substr(0, 80) << "\n...\n" |
||
<< text.substr(text.length() - 80) << "\n"; |
<< text.substr(text.length() - 80) << "\n"; |
||
}</ |
}</syntaxhighlight> |
||
<pre> |
<pre> |
||
<pre> |
<pre> |
||
Line 1,476: | Line 2,589: | ||
=={{header|Chapel}}== |
=={{header|Chapel}}== |
||
< |
<syntaxhighlight lang="chapel">proc A(m:int, n:int):int { |
||
if m == 0 then |
if m == 0 then |
||
return n + 1; |
return n + 1; |
||
Line 1,483: | Line 2,596: | ||
else |
else |
||
return A(m - 1, A(m, n - 1)); |
return A(m - 1, A(m, n - 1)); |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Clay}}== |
=={{header|Clay}}== |
||
< |
<syntaxhighlight lang="clay">ackermann(m, n) { |
||
if(m == 0) |
if(m == 0) |
||
return n + 1; |
return n + 1; |
||
Line 1,493: | Line 2,606: | ||
return ackermann(m - 1, ackermann(m, n - 1)); |
return ackermann(m - 1, ackermann(m, n - 1)); |
||
}</ |
}</syntaxhighlight> |
||
=={{header|CLIPS}}== |
=={{header|CLIPS}}== |
||
'''Functional solution''' |
'''Functional solution''' |
||
< |
<syntaxhighlight lang="clips">(deffunction ackerman |
||
(?m ?n) |
(?m ?n) |
||
(if (= 0 ?m) |
(if (= 0 ?m) |
||
Line 1,506: | Line 2,619: | ||
) |
) |
||
) |
) |
||
)</ |
)</syntaxhighlight> |
||
{{out|Example usage}} |
{{out|Example usage}} |
||
<pre>CLIPS> (ackerman 0 4) |
<pre>CLIPS> (ackerman 0 4) |
||
Line 1,518: | Line 2,631: | ||
</pre> |
</pre> |
||
'''Fact-based solution''' |
'''Fact-based solution''' |
||
< |
<syntaxhighlight lang="clips">(deffacts solve-items |
||
(solve 0 4) |
(solve 0 4) |
||
(solve 1 4) |
(solve 1 4) |
||
Line 1,585: | Line 2,698: | ||
(retract ?solve) |
(retract ?solve) |
||
(printout t "A(" ?m "," ?n ") = " ?result crlf) |
(printout t "A(" ?m "," ?n ") = " ?result crlf) |
||
)</ |
)</syntaxhighlight> |
||
When invoked, each required A(m,n) needed to solve the requested (solve ?m ?n) facts gets generated as its own fact. Below shows the invocation of the above, as well as an excerpt of the final facts list. Regardless of how many input (solve ?m ?n) requests are made, each possible A(m,n) is only solved once. |
When invoked, each required A(m,n) needed to solve the requested (solve ?m ?n) facts gets generated as its own fact. Below shows the invocation of the above, as well as an excerpt of the final facts list. Regardless of how many input (solve ?m ?n) requests are made, each possible A(m,n) is only solved once. |
||
<pre>CLIPS> (reset) |
<pre>CLIPS> (reset) |
||
Line 1,613: | Line 2,726: | ||
=={{header|Clojure}}== |
=={{header|Clojure}}== |
||
< |
<syntaxhighlight lang="clojure">(defn ackermann [m n] |
||
(cond (zero? m) (inc n) |
(cond (zero? m) (inc n) |
||
(zero? n) (ackermann (dec m) 1) |
(zero? n) (ackermann (dec m) 1) |
||
:else (ackermann (dec m) (ackermann m (dec n)))))</ |
:else (ackermann (dec m) (ackermann m (dec n)))))</syntaxhighlight> |
||
=={{header|CLU}}== |
|||
<syntaxhighlight lang="clu">% Ackermann function |
|||
ack = proc (m, n: int) returns (int) |
|||
if m=0 then return(n+1) |
|||
elseif n=0 then return(ack(m-1, 1)) |
|||
else return(ack(m-1, ack(m, n-1))) |
|||
end |
|||
end ack |
|||
% Print a table of ack( 0..3, 0..8 ) |
|||
start_up = proc () |
|||
po: stream := stream$primary_output() |
|||
for m: int in int$from_to(0, 3) do |
|||
for n: int in int$from_to(0, 8) do |
|||
stream$putright(po, int$unparse(ack(m,n)), 8) |
|||
end |
|||
stream$putl(po, "") |
|||
end |
|||
end start_up </syntaxhighlight> |
|||
{{out}} |
|||
<pre> 1 2 3 4 5 6 7 8 9 |
|||
2 3 4 5 6 7 8 9 10 |
|||
3 5 7 9 11 13 15 17 19 |
|||
5 13 29 61 125 253 509 1021 2045</pre> |
|||
=={{header|COBOL}}== |
=={{header|COBOL}}== |
||
< |
<syntaxhighlight lang="cobol"> IDENTIFICATION DIVISION. |
||
PROGRAM-ID. Ackermann. |
PROGRAM-ID. Ackermann. |
||
Line 1,650: | Line 2,789: | ||
GOBACK |
GOBACK |
||
.</ |
.</syntaxhighlight> |
||
=={{header|CoffeeScript}}== |
=={{header|CoffeeScript}}== |
||
< |
<syntaxhighlight lang="coffeescript">ackermann = (m, n) -> |
||
if m is 0 then n + 1 |
if m is 0 then n + 1 |
||
else if m > 0 and n is 0 then ackermann m - 1, 1 |
else if m > 0 and n is 0 then ackermann m - 1, 1 |
||
else ackermann m - 1, ackermann m, n - 1</ |
else ackermann m - 1, ackermann m, n - 1</syntaxhighlight> |
||
=={{header|Comal}}== |
|||
<syntaxhighlight lang="comal">0010 // |
|||
0020 // Ackermann function |
|||
0030 // |
|||
0040 FUNC a#(m#,n#) |
|||
0050 IF m#=0 THEN RETURN n#+1 |
|||
0060 IF n#=0 THEN RETURN a#(m#-1,1) |
|||
0070 RETURN a#(m#-1,a#(m#,n#-1)) |
|||
0080 ENDFUNC a# |
|||
0090 // |
|||
0100 // Print table of Ackermann values |
|||
0110 // |
|||
0120 ZONE 5 |
|||
0130 FOR m#:=0 TO 3 DO |
|||
0140 FOR n#:=0 TO 4 DO PRINT a#(m#,n#), |
|||
0150 PRINT |
|||
0160 ENDFOR m# |
|||
0170 END</syntaxhighlight> |
|||
{{out}} |
|||
<pre>1 2 3 4 5 |
|||
2 3 4 5 6 |
|||
3 5 7 9 11 |
|||
5 13 29 61 125</pre> |
|||
=={{header|Common Lisp}}== |
=={{header|Common Lisp}}== |
||
< |
<syntaxhighlight lang="lisp">(defun ackermann (m n) |
||
(cond ((zerop m) (1+ n)) |
(cond ((zerop m) (1+ n)) |
||
((zerop n) (ackermann (1- m) 1)) |
((zerop n) (ackermann (1- m) 1)) |
||
(t (ackermann (1- m) (ackermann m (1- n))))))</ |
(t (ackermann (1- m) (ackermann m (1- n))))))</syntaxhighlight> |
||
More elaborately: |
More elaborately: |
||
< |
<syntaxhighlight lang="lisp">(defun ackermann (m n) |
||
(case m ((0) (1+ n)) |
(case m ((0) (1+ n)) |
||
((1) (+ 2 n)) |
((1) (+ 2 n)) |
||
Line 1,673: | Line 2,836: | ||
(loop for m from 0 to 4 do |
(loop for m from 0 to 4 do |
||
(loop for n from (- 5 m) to (- 6 m) do |
(loop for n from (- 5 m) to (- 6 m) do |
||
(format t "A(~d, ~d) = ~d~%" m n (ackermann m n))))</ |
(format t "A(~d, ~d) = ~d~%" m n (ackermann m n))))</syntaxhighlight> |
||
{{out}}<pre>A(0, 5) = 6 |
{{out}}<pre>A(0, 5) = 6 |
||
A(0, 6) = 7 |
A(0, 6) = 7 |
||
Line 1,684: | Line 2,847: | ||
A(4, 1) = 65533 |
A(4, 1) = 65533 |
||
A(4, 2) = 2003529930 <... skipping a few digits ...> 56733</pre> |
A(4, 2) = 2003529930 <... skipping a few digits ...> 56733</pre> |
||
=={{header|Coq}}== |
|||
<lang coq>Require Import Arith. |
|||
Fixpoint A m := fix A_m n := |
|||
match m with |
|||
| 0 => n + 1 |
|||
| S pm => |
|||
match n with |
|||
| 0 => A pm 1 |
|||
| S pn => A pm (A_m pn) |
|||
end |
|||
end.</lang> |
|||
<lang coq>Require Import Utf8. |
|||
Section FOLD. |
|||
Context {A: Type} (f: A → A) (a: A). |
|||
Fixpoint fold (n: nat) : A := |
|||
match n with |
|||
| O => a |
|||
| S n' => f (fold n') |
|||
end. |
|||
End FOLD. |
|||
Definition ackermann : nat → nat → nat := |
|||
fold (λ g, fold g (g (S O))) S. |
|||
</lang> |
|||
=={{header|Component Pascal}}== |
=={{header|Component Pascal}}== |
||
BlackBox Component Builder |
BlackBox Component Builder |
||
< |
<syntaxhighlight lang="oberon2"> |
||
MODULE NpctAckerman; |
MODULE NpctAckerman; |
||
Line 1,743: | Line 2,880: | ||
END NpctAckerman. |
END NpctAckerman. |
||
</syntaxhighlight> |
|||
</lang> |
|||
Execute: ^Q NpctAckerman.Do<br/> |
Execute: ^Q NpctAckerman.Do<br/> |
||
<pre> |
<pre> |
||
Line 1,751: | Line 2,888: | ||
3 5 7 9 11 13 15 |
3 5 7 9 11 13 15 |
||
5 13 29 61 125 253 509 |
5 13 29 61 125 253 509 |
||
</pre> |
|||
=={{header|Coq}}== |
|||
===Standard=== |
|||
<syntaxhighlight lang="coq"> |
|||
Fixpoint ack (m : nat) : nat -> nat := |
|||
fix ack_m (n : nat) : nat := |
|||
match m with |
|||
| 0 => S n |
|||
| S pm => |
|||
match n with |
|||
| 0 => ack pm 1 |
|||
| S pn => ack pm (ack_m pn) |
|||
end |
|||
end. |
|||
(* |
|||
Example: |
|||
A(3, 2) = 29 |
|||
*) |
|||
Eval compute in ack 3 2. |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
= 29 |
|||
: nat |
|||
</pre> |
|||
===Using fold=== |
|||
<syntaxhighlight lang="coq"> |
|||
Require Import Utf8. |
|||
Section FOLD. |
|||
Context {A : Type} (f : A → A) (a : A). |
|||
Fixpoint fold (n : nat) : A := |
|||
match n with |
|||
| O => a |
|||
| S k => f (fold k) |
|||
end. |
|||
End FOLD. |
|||
Definition ackermann : nat → nat → nat := |
|||
fold (λ g, fold g (g (S O))) S. |
|||
</syntaxhighlight> |
|||
=={{header|Crystal}}== |
|||
{{trans|Ruby}} |
|||
<syntaxhighlight lang="ruby">def ack(m, n) |
|||
if m == 0 |
|||
n + 1 |
|||
elsif n == 0 |
|||
ack(m-1, 1) |
|||
else |
|||
ack(m-1, ack(m, n-1)) |
|||
end |
|||
end |
|||
#Example: |
|||
(0..3).each do |m| |
|||
puts (0..6).map { |n| ack(m, n) }.join(' ') |
|||
end |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1 2 3 4 5 6 7 |
|||
2 3 4 5 6 7 8 |
|||
3 5 7 9 11 13 15 |
|||
5 13 29 61 125 253 509 |
|||
</pre> |
</pre> |
||
=={{header|D}}== |
=={{header|D}}== |
||
===Basic version=== |
===Basic version=== |
||
< |
<syntaxhighlight lang="d">ulong ackermann(in ulong m, in ulong n) pure nothrow @nogc { |
||
if (m == 0) |
if (m == 0) |
||
return n + 1; |
return n + 1; |
||
Line 1,765: | Line 2,974: | ||
void main() { |
void main() { |
||
assert(ackermann(2, 4) == 11); |
assert(ackermann(2, 4) == 11); |
||
}</ |
}</syntaxhighlight> |
||
===More Efficient Version=== |
===More Efficient Version=== |
||
{{trans|Mathematica}} |
{{trans|Mathematica}} |
||
< |
<syntaxhighlight lang="d">import std.stdio, std.bigint, std.conv; |
||
BigInt ipow(BigInt base, BigInt exp) pure nothrow { |
BigInt ipow(BigInt base, BigInt exp) pure nothrow { |
||
Line 1,812: | Line 3,021: | ||
writefln("ackermann(4, 2)) (%d digits):\n%s...\n%s", |
writefln("ackermann(4, 2)) (%d digits):\n%s...\n%s", |
||
a.length, a[0 .. 94], a[$ - 96 .. $]); |
a.length, a[0 .. 94], a[$ - 96 .. $]); |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,846: | Line 3,055: | ||
=={{header|Dart}}== |
=={{header|Dart}}== |
||
no caching, the implementation takes ages even for A(4,1) |
no caching, the implementation takes ages even for A(4,1) |
||
< |
<syntaxhighlight lang="dart">int A(int m, int n) => m==0 ? n+1 : n==0 ? A(m-1,1) : A(m-1,A(m,n-1)); |
||
main() { |
main() { |
||
Line 1,858: | Line 3,067: | ||
print(A(3,5)); |
print(A(3,5)); |
||
print(A(4,0)); |
print(A(4,0)); |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Dc}}== |
|||
This needs a modern Dc with <code>r</code> (swap) and <code>#</code> (comment). It easily can be adapted to an older Dc, but it will impact readability a lot. |
|||
<syntaxhighlight lang="dc">[ # todo: n 0 -- n+1 and break 2 levels |
|||
+ 1 + # n+1 |
|||
q |
|||
] s1 |
|||
[ # todo: m 0 -- A(m-1,1) and break 2 levels |
|||
+ 1 - # m-1 |
|||
1 # m-1 1 |
|||
lA x # A(m-1,1) |
|||
q |
|||
] s2 |
|||
[ # todo: m n -- A(m,n) |
|||
r d 0=1 # n m(!=0) |
|||
r d 0=2 # m(!=0) n(!=0) |
|||
Sn # m(!=0) |
|||
d 1 - r # m-1 m |
|||
Ln 1 - # m-1 m n-1 |
|||
lA x # m-1 A(m,n-1) |
|||
lA x # A(m-1,A(m,n-1)) |
|||
] sA |
|||
3 9 lA x f</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
4093 |
|||
</pre> |
|||
=={{header|Delphi}}== |
=={{header|Delphi}}== |
||
< |
<syntaxhighlight lang="delphi">function Ackermann(m,n:Int64):Int64; |
||
begin |
begin |
||
if m = 0 then |
if m = 0 then |
||
Line 1,869: | Line 3,108: | ||
else |
else |
||
Result := Ackermann(m-1, Ackermann(m, n - 1)); |
Result := Ackermann(m-1, Ackermann(m, n - 1)); |
||
end;</ |
end;</syntaxhighlight> |
||
=={{header|Draco}}== |
|||
<syntaxhighlight lang="draco">/* Ackermann function */ |
|||
proc ack(word m, n) word: |
|||
if m=0 then n+1 |
|||
elif n=0 then ack(m-1, 1) |
|||
else ack(m-1, ack(m, n-1)) |
|||
fi |
|||
corp; |
|||
/* Write a table of Ackermann values */ |
|||
proc nonrec main() void: |
|||
byte m, n; |
|||
for m from 0 upto 3 do |
|||
for n from 0 upto 8 do |
|||
write(ack(m,n) : 5) |
|||
od; |
|||
writeln() |
|||
od |
|||
corp</syntaxhighlight> |
|||
{{out}} |
|||
<pre> 1 2 3 4 5 6 7 8 9 |
|||
2 3 4 5 6 7 8 9 10 |
|||
3 5 7 9 11 13 15 17 19 |
|||
5 13 29 61 125 253 509 1021 2045</pre> |
|||
=={{header|DWScript}}== |
=={{header|DWScript}}== |
||
< |
<syntaxhighlight lang="delphi">function Ackermann(m, n : Integer) : Integer; |
||
begin |
begin |
||
if m = 0 then |
if m = 0 then |
||
Line 1,879: | Line 3,143: | ||
Result := Ackermann(m-1, 1) |
Result := Ackermann(m-1, 1) |
||
else Result := Ackermann(m-1, Ackermann(m, n-1)); |
else Result := Ackermann(m-1, Ackermann(m, n-1)); |
||
end;</ |
end;</syntaxhighlight> |
||
=={{header|Dylan}}== |
=={{header|Dylan}}== |
||
< |
<syntaxhighlight lang="dylan">define method ack(m == 0, n :: <integer>) |
||
n + 1 |
n + 1 |
||
end; |
end; |
||
define method ack(m :: <integer>, n :: <integer>) |
define method ack(m :: <integer>, n :: <integer>) |
||
ack(m - 1, if (n == 0) 1 else ack(m, n - 1) end) |
ack(m - 1, if (n == 0) 1 else ack(m, n - 1) end) |
||
end;</ |
end;</syntaxhighlight> |
||
=={{header|E}}== |
=={{header|E}}== |
||
< |
<syntaxhighlight lang="e">def A(m, n) { |
||
return if (m <=> 0) { n+1 } \ |
return if (m <=> 0) { n+1 } \ |
||
else if (m > 0 && n <=> 0) { A(m-1, 1) } \ |
else if (m > 0 && n <=> 0) { A(m-1, 1) } \ |
||
else { A(m-1, A(m,n-1)) } |
else { A(m-1, A(m,n-1)) } |
||
}</ |
}</syntaxhighlight> |
||
=={{header|EasyLang}}== |
|||
<syntaxhighlight lang="text"> |
|||
func ackerm m n . |
|||
if m = 0 |
|||
return n + 1 |
|||
elif n = 0 |
|||
return ackerm (m - 1) 1 |
|||
else |
|||
return ackerm (m - 1) ackerm m (n - 1) |
|||
. |
|||
. |
|||
print ackerm 3 6 |
|||
</syntaxhighlight> |
|||
=={{header|Egel}}== |
=={{header|Egel}}== |
||
<syntaxhighlight lang="egel"> |
|||
<lang Egel> |
|||
def ackermann = |
def ackermann = |
||
[ 0 N -> N + 1 |
[ 0 N -> N + 1 |
||
| M 0 -> ackermann (M - 1) 1 |
| M 0 -> ackermann (M - 1) 1 |
||
| M N -> ackermann (M - 1) (ackermann M (N - 1)) ] |
| M N -> ackermann (M - 1) (ackermann M (N - 1)) ] |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Eiffel}}== |
=={{header|Eiffel}}== |
||
[https://github.com/ljr1981/rosettacode_answers/blob/main/src/ackerman_example/ackerman_example.e Example code] |
|||
<lang Eiffel> |
|||
note |
|||
description: "Example of Ackerman function" |
|||
synopsis: "[ |
|||
The EIS link below (in Eiffel Studio) will launch in either an in-IDE browser or |
|||
and external browser (your choice). The protocol informs Eiffel Studio about what |
|||
program to use to open the `src' reference, which can be URI, PDF, or DOC. See |
|||
second EIS for more information. |
|||
]" |
|||
EIS: "name=Ackermann_function", "protocol=URI", "tag=rosetta_code", |
|||
"src=http://rosettacode.org/wiki/Ackermann_function" |
|||
EIS: "name=eis_protocols", "protocol=URI", "tag=eiffel_docs", |
|||
"src=https://docs.eiffel.com/book/eiffelstudio/protocols" |
|||
[https://github.com/ljr1981/rosettacode_answers/blob/main/testing/rc_ackerman/rc_ackerman_test_set.e Test of Example code] |
|||
<syntaxhighlight lang="eiffel"> |
|||
class |
class |
||
ACKERMAN_EXAMPLE |
|||
APPLICATION |
|||
feature -- Basic Operations |
|||
create |
|||
make |
|||
feature {NONE} -- Initialization |
|||
make |
|||
do |
|||
print ("%N A(0,0):" + ackerman (0, 0).out) |
|||
print ("%N A(1,0):" + ackerman (1, 0).out) |
|||
print ("%N A(0,1):" + ackerman (0, 1).out) |
|||
print ("%N A(1,1):" + ackerman (1, 1).out) |
|||
print ("%N A(2,0):" + ackerman (2, 0).out) |
|||
print ("%N A(2,1):" + ackerman (2, 1).out) |
|||
print ("%N A(2,2):" + ackerman (2, 2).out) |
|||
print ("%N A(0,2):" + ackerman (0, 2).out) |
|||
print ("%N A(1,2):" + ackerman (1, 2).out) |
|||
print ("%N A(3,3):" + ackerman (3, 3).out) |
|||
print ("%N A(3,4):" + ackerman (3, 4).out) |
|||
end |
|||
feature -- Access |
|||
ackerman (m, n: NATURAL): NATURAL |
ackerman (m, n: NATURAL): NATURAL |
||
-- Recursively compute the n-th term of a series. |
|||
require |
|||
non_negative_m: m >= 0 |
|||
non_negative_n: n >= 0 |
|||
do |
do |
||
if m = 0 then |
if m = 0 then |
||
Result := n + 1 |
Result := n + 1 |
||
elseif n = 0 then |
elseif m > 0 and n = 0 then |
||
Result := ackerman (m - 1, 1) |
Result := ackerman (m - 1, 1) |
||
elseif m > 0 and n > 0 then |
|||
else |
|||
Result := ackerman (m - 1, ackerman (m, n - 1)) |
Result := ackerman (m - 1, ackerman (m, n - 1)) |
||
else |
|||
check invalid_arg_state: False end |
|||
end |
end |
||
end |
end |
||
end |
end |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Ela}}== |
=={{header|Ela}}== |
||
< |
<syntaxhighlight lang="ela">ack 0 n = n+1 |
||
ack m 0 = ack (m - 1) 1 |
ack m 0 = ack (m - 1) 1 |
||
ack m n = ack (m - 1) <| ack m <| n - 1</ |
ack m n = ack (m - 1) <| ack m <| n - 1</syntaxhighlight> |
||
=={{header|Elena}}== |
=={{header|Elena}}== |
||
ELENA |
ELENA 6.x : |
||
< |
<syntaxhighlight lang="elena">import extensions; |
||
ackermann |
ackermann(m,n) |
||
{ |
|||
[ |
|||
if(n < 0 || m < 0) |
|||
{ |
|||
InvalidArgumentException.raise() |
|||
}; |
|||
m => |
|||
0 { ^n + 1 } |
|||
! { |
|||
n => |
|||
0 { ^ackermann(m - 1,1) } |
|||
! { ^ackermann(m - 1,ackermann(m,n-1)) } |
|||
} |
|||
} |
|||
]. |
|||
public program |
public program() |
||
{ |
|||
[ |
|||
0 |
for(int i:=0; i <= 3; i += 1) |
||
{ |
|||
0 |
for(int j := 0; j <= 5; j += 1) |
||
{ |
|||
console.printLine("A(",i,",",j,")=",ackermann(i,j)) |
|||
} |
|||
}; |
|||
console.readChar() |
|||
}</syntaxhighlight> |
|||
].</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 2,023: | Line 3,279: | ||
=={{header|Elixir}}== |
=={{header|Elixir}}== |
||
< |
<syntaxhighlight lang="elixir">defmodule Ackermann do |
||
def ack(0, n), do: n + 1 |
def ack(0, n), do: n + 1 |
||
def ack(m, 0), do: ack(m - 1, 1) |
def ack(m, 0), do: ack(m - 1, 1) |
||
Line 2,031: | Line 3,287: | ||
Enum.each(0..3, fn m -> |
Enum.each(0..3, fn m -> |
||
IO.puts Enum.map_join(0..6, " ", fn n -> Ackermann.ack(m, n) end) |
IO.puts Enum.map_join(0..6, " ", fn n -> Ackermann.ack(m, n) end) |
||
end)</ |
end)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 2,039: | Line 3,295: | ||
3 5 7 9 11 13 15 |
3 5 7 9 11 13 15 |
||
5 13 29 61 125 253 509 |
5 13 29 61 125 253 509 |
||
</pre> |
|||
=={{header|Emacs Lisp}}== |
|||
<syntaxhighlight lang="lisp">(defun ackermann (m n) |
|||
(cond ((zerop m) (1+ n)) |
|||
((zerop n) (ackermann (1- m) 1)) |
|||
(t (ackermann (1- m) |
|||
(ackermann m (1- n))))))</syntaxhighlight> |
|||
=={{header|EMal}}== |
|||
<syntaxhighlight lang="emal"> |
|||
fun ackermann = int by int m, int n |
|||
return when(m == 0, |
|||
n + 1, |
|||
when(n == 0, |
|||
ackermann(m - 1, 1), |
|||
ackermann(m - 1, ackermann(m, n - 1)))) |
|||
end |
|||
for int m = 0; m <= 3; ++m |
|||
for int n = 0; n <= 6; ++n |
|||
writeLine("Ackermann(" + m + ", " + n + ") = " + ackermann(m, n)) |
|||
end |
|||
end |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Ackermann(0, 0) = 1 |
|||
Ackermann(0, 1) = 2 |
|||
Ackermann(0, 2) = 3 |
|||
Ackermann(0, 3) = 4 |
|||
Ackermann(0, 4) = 5 |
|||
Ackermann(0, 5) = 6 |
|||
Ackermann(0, 6) = 7 |
|||
Ackermann(1, 0) = 2 |
|||
Ackermann(1, 1) = 3 |
|||
Ackermann(1, 2) = 4 |
|||
Ackermann(1, 3) = 5 |
|||
Ackermann(1, 4) = 6 |
|||
Ackermann(1, 5) = 7 |
|||
Ackermann(1, 6) = 8 |
|||
Ackermann(2, 0) = 3 |
|||
Ackermann(2, 1) = 5 |
|||
Ackermann(2, 2) = 7 |
|||
Ackermann(2, 3) = 9 |
|||
Ackermann(2, 4) = 11 |
|||
Ackermann(2, 5) = 13 |
|||
Ackermann(2, 6) = 15 |
|||
Ackermann(3, 0) = 5 |
|||
Ackermann(3, 1) = 13 |
|||
Ackermann(3, 2) = 29 |
|||
Ackermann(3, 3) = 61 |
|||
Ackermann(3, 4) = 125 |
|||
Ackermann(3, 5) = 253 |
|||
Ackermann(3, 6) = 509 |
|||
</pre> |
</pre> |
||
=={{header|Erlang}}== |
=={{header|Erlang}}== |
||
< |
<syntaxhighlight lang="erlang"> |
||
-module(ackermann). |
-module(ackermann). |
||
-export([ackermann/2]). |
-export([ackermann/2]). |
||
Line 2,053: | Line 3,363: | ||
ackermann(M, N) when M > 0 andalso N > 0 -> |
ackermann(M, N) when M > 0 andalso N > 0 -> |
||
ackermann(M-1, ackermann(M, N-1)). |
ackermann(M-1, ackermann(M, N-1)). |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|ERRE}}== |
=={{header|ERRE}}== |
||
Line 2,059: | Line 3,369: | ||
substituted with the new ERRE control statements. |
substituted with the new ERRE control statements. |
||
< |
<syntaxhighlight lang="erre"> |
||
PROGRAM ACKERMAN |
PROGRAM ACKERMAN |
||
Line 2,114: | Line 3,424: | ||
END FOR |
END FOR |
||
END PROGRAM |
END PROGRAM |
||
</syntaxhighlight> |
|||
</lang> |
|||
Prints a list of Ackermann function values: from A(0,0) to A(3,9). Uses a stack to avoid |
Prints a list of Ackermann function values: from A(0,0) to A(3,9). Uses a stack to avoid |
||
Line 2,129: | Line 3,439: | ||
Stack Level: 1 |
Stack Level: 1 |
||
</pre> |
</pre> |
||
=={{header|Euphoria}}== |
|||
This is based on the [[VBScript]] example. |
|||
<lang Euphoria>function ack(atom m, atom n) |
|||
if m = 0 then |
|||
return n + 1 |
|||
elsif m > 0 and n = 0 then |
|||
return ack(m - 1, 1) |
|||
else |
|||
return ack(m - 1, ack(m, n - 1)) |
|||
end if |
|||
end function |
|||
for i = 0 to 3 do |
|||
for j = 0 to 6 do |
|||
printf( 1, "%5d", ack( i, j ) ) |
|||
end for |
|||
puts( 1, "\n" ) |
|||
end for</lang> |
|||
=={{header|Euler Math Toolbox}}== |
=={{header|Euler Math Toolbox}}== |
||
<syntaxhighlight lang="euler math toolbox"> |
|||
<lang Euler Math Toolbox> |
|||
>M=zeros(1000,1000); |
>M=zeros(1000,1000); |
||
>function map A(m,n) ... |
>function map A(m,n) ... |
||
Line 2,168: | Line 3,459: | ||
3 5 7 9 11 13 |
3 5 7 9 11 13 |
||
5 13 29 61 125 253 |
5 13 29 61 125 253 |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Euphoria}}== |
|||
This is based on the [[VBScript]] example. |
|||
<syntaxhighlight lang="euphoria">function ack(atom m, atom n) |
|||
if m = 0 then |
|||
return n + 1 |
|||
elsif m > 0 and n = 0 then |
|||
return ack(m - 1, 1) |
|||
else |
|||
return ack(m - 1, ack(m, n - 1)) |
|||
end if |
|||
end function |
|||
for i = 0 to 3 do |
|||
for j = 0 to 6 do |
|||
printf( 1, "%5d", ack( i, j ) ) |
|||
end for |
|||
puts( 1, "\n" ) |
|||
end for</syntaxhighlight> |
|||
=={{header|Ezhil}}== |
=={{header|Ezhil}}== |
||
<syntaxhighlight lang="ezhil"> |
|||
<lang Ezhil> |
|||
நிரல்பாகம் அகெர்மன்(முதலெண், இரண்டாமெண்) |
நிரல்பாகம் அகெர்மன்(முதலெண், இரண்டாமெண்) |
||
Line 2,210: | Line 3,520: | ||
முடி |
முடி |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|F_Sharp|F#}}== |
=={{header|F_Sharp|F#}}== |
||
The following program implements the Ackermann function in F# but is not tail-recursive and so runs out of stack space quite fast. |
The following program implements the Ackermann function in F# but is not tail-recursive and so runs out of stack space quite fast. |
||
< |
<syntaxhighlight lang="fsharp">let rec ackermann m n = |
||
match m, n with |
match m, n with |
||
| 0, n -> n + 1 |
| 0, n -> n + 1 |
||
Line 2,221: | Line 3,531: | ||
do |
do |
||
printfn "%A" (ackermann (int fsi.CommandLineArgs.[1]) (int fsi.CommandLineArgs.[2]))</ |
printfn "%A" (ackermann (int fsi.CommandLineArgs.[1]) (int fsi.CommandLineArgs.[2]))</syntaxhighlight> |
||
Transforming this into continuation passing style avoids limited stack space by permitting tail-recursion. |
Transforming this into continuation passing style avoids limited stack space by permitting tail-recursion. |
||
< |
<syntaxhighlight lang="fsharp">let ackermann M N = |
||
let rec acker (m, n, k) = |
let rec acker (m, n, k) = |
||
match m,n with |
match m,n with |
||
Line 2,229: | Line 3,539: | ||
| m, 0 -> acker ((m - 1), 1, k) |
| m, 0 -> acker ((m - 1), 1, k) |
||
| m, n -> acker (m, (n - 1), (fun x -> acker ((m - 1), x, k))) |
| m, n -> acker (m, (n - 1), (fun x -> acker ((m - 1), x, k))) |
||
acker (M, N, (fun x -> x))</ |
acker (M, N, (fun x -> x))</syntaxhighlight> |
||
=={{header|Factor}}== |
=={{header|Factor}}== |
||
< |
<syntaxhighlight lang="factor">USING: kernel math locals combinators ; |
||
IN: ackermann |
IN: ackermann |
||
Line 2,240: | Line 3,550: | ||
{ [ n 0 = ] [ m 1 - 1 ackermann ] } |
{ [ n 0 = ] [ m 1 - 1 ackermann ] } |
||
[ m 1 - m n 1 - ackermann ackermann ] |
[ m 1 - m n 1 - ackermann ackermann ] |
||
} cond ;</ |
} cond ;</syntaxhighlight> |
||
=={{header|Falcon}}== |
=={{header|Falcon}}== |
||
< |
<syntaxhighlight lang="falcon">function ackermann( m, n ) |
||
if m == 0: return( n + 1 ) |
if m == 0: return( n + 1 ) |
||
if n == 0: return( ackermann( m - 1, 1 ) ) |
if n == 0: return( ackermann( m - 1, 1 ) ) |
||
Line 2,254: | Line 3,564: | ||
end |
end |
||
> |
> |
||
end</ |
end</syntaxhighlight> |
||
The above will output the below. |
The above will output the below. |
||
Formating options to make this pretty are available, |
Formating options to make this pretty are available, |
||
Line 2,266: | Line 3,576: | ||
=={{header|FALSE}}== |
=={{header|FALSE}}== |
||
< |
<syntaxhighlight lang="false">[$$[% |
||
\$$[% |
\$$[% |
||
1-\$@@a;! { i j -> A(i-1, A(i, j-1)) } |
1-\$@@a;! { i j -> A(i-1, A(i, j-1)) } |
||
Line 2,277: | Line 3,587: | ||
]?]a: { j i } |
]?]a: { j i } |
||
3 3 a;! . { 61 }</ |
3 3 a;! . { 61 }</syntaxhighlight> |
||
=={{header|Fantom}}== |
=={{header|Fantom}}== |
||
< |
<syntaxhighlight lang="fantom">class Main |
||
{ |
{ |
||
// assuming m,n are positive |
// assuming m,n are positive |
||
Line 2,303: | Line 3,613: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 2,335: | Line 3,645: | ||
Ackerman(3, 6) = 509 |
Ackerman(3, 6) = 509 |
||
</pre> |
</pre> |
||
=={{header|FBSL}}== |
=={{header|FBSL}}== |
||
Mixed-language solution using pure FBSL, Dynamic Assembler, and Dynamic C layers of FBSL v3.5 concurrently. '''The following is a single script'''; the breaks are caused by switching between RC's different syntax highlighting schemes: |
Mixed-language solution using pure FBSL, Dynamic Assembler, and Dynamic C layers of FBSL v3.5 concurrently. '''The following is a single script'''; the breaks are caused by switching between RC's different syntax highlighting schemes: |
||
< |
<syntaxhighlight lang="qbasic">#APPTYPE CONSOLE |
||
TestAckermann() |
TestAckermann() |
||
Line 2,358: | Line 3,669: | ||
END FUNCTION |
END FUNCTION |
||
DYNC AckermannC(m AS INTEGER, n AS INTEGER) AS INTEGER</ |
DYNC AckermannC(m AS INTEGER, n AS INTEGER) AS INTEGER</syntaxhighlight><syntaxhighlight lang="c"> |
||
int Ackermann(int m, int n) |
int Ackermann(int m, int n) |
||
{ |
{ |
||
Line 2,369: | Line 3,680: | ||
{ |
{ |
||
return Ackermann(m, n); |
return Ackermann(m, n); |
||
}</ |
}</syntaxhighlight><syntaxhighlight lang="qbasic"> |
||
END DYNC |
END DYNC |
||
DYNASM AckermannA(m AS INTEGER, n AS INTEGER) AS INTEGER</ |
DYNASM AckermannA(m AS INTEGER, n AS INTEGER) AS INTEGER</syntaxhighlight><syntaxhighlight lang="asm"> |
||
ENTER 0, 0 |
ENTER 0, 0 |
||
INVOKE Ackermann, m, n |
INVOKE Ackermann, m, n |
||
Line 2,408: | Line 3,719: | ||
LEAVE |
LEAVE |
||
RET 8 |
RET 8 |
||
</ |
</syntaxhighlight><syntaxhighlight lang="qbasic">END DYNASM</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 2,418: | Line 3,729: | ||
Press any key to continue... |
Press any key to continue... |
||
</pre> |
|||
=={{header|Fermat}}== |
|||
<syntaxhighlight lang="fermat">Func A(m,n) = if m = 0 then n+1 else if n = 0 then A(m-1,1) else A(m-1,A(m,n-1)) fi fi.; |
|||
A(3,8)</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
2045 |
|||
</pre> |
</pre> |
||
=={{header|Forth}}== |
=={{header|Forth}}== |
||
< |
<syntaxhighlight lang="forth">: acker ( m n -- u ) |
||
over 0= IF nip 1+ EXIT THEN |
over 0= IF nip 1+ EXIT THEN |
||
swap 1- swap ( m-1 n -- ) |
swap 1- swap ( m-1 n -- ) |
||
dup 0= IF 1+ recurse EXIT THEN |
dup 0= IF 1+ recurse EXIT THEN |
||
1- over 1+ swap recurse recurse ;</ |
1- over 1+ swap recurse recurse ;</syntaxhighlight> |
||
{{out|Example of use}} |
{{out|Example of use}} |
||
<pre>FORTH> 0 0 acker . 1 ok |
<pre>FORTH> 0 0 acker . 1 ok |
||
FORTH> 3 4 acker . 125 ok</pre> |
FORTH> 3 4 acker . 125 ok</pre> |
||
An optimized version: |
An optimized version: |
||
< |
<syntaxhighlight lang="forth">: ackermann ( m n -- u ) |
||
over ( case statement) |
over ( case statement) |
||
0 over = if drop nip 1+ else |
0 over = if drop nip 1+ else |
||
Line 2,443: | Line 3,762: | ||
then |
then |
||
then then then then |
then then then then |
||
;</ |
;</syntaxhighlight> |
||
=={{header|Fortran}}== |
=={{header|Fortran}}== |
||
{{works with|Fortran|90 and later}} |
{{works with|Fortran|90 and later}} |
||
< |
<syntaxhighlight lang="fortran">PROGRAM EXAMPLE |
||
IMPLICIT NONE |
IMPLICIT NONE |
||
Line 2,473: | Line 3,792: | ||
END FUNCTION Ackermann |
END FUNCTION Ackermann |
||
END PROGRAM EXAMPLE</ |
END PROGRAM EXAMPLE</syntaxhighlight> |
||
=={{header|Free Pascal}}== |
=={{header|Free Pascal}}== |
||
See [[#Delphi]] or [[#Pascal]]. |
See [[#Delphi]] or [[#Pascal]]. |
||
=={{header|FreeBASIC}}== |
=={{header|FreeBASIC}}== |
||
< |
<syntaxhighlight lang="freebasic">' version 28-10-2016 |
||
' compile with: fbc -s console |
' compile with: fbc -s console |
||
' to do A(4, 2) the stack size needs to be increased |
' to do A(4, 2) the stack size needs to be increased |
||
Line 2,518: | Line 3,838: | ||
Print : Print "hit any key to end program" |
Print : Print "hit any key to end program" |
||
Sleep |
Sleep |
||
End</ |
End</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> 0 1 2 3 4 5 6 7 8 9 10 11 |
<pre> 0 1 2 3 4 5 6 7 8 9 10 11 |
||
Line 2,527: | Line 3,847: | ||
=={{header|FunL}}== |
=={{header|FunL}}== |
||
< |
<syntaxhighlight lang="funl">def |
||
ackermann( 0, n ) = n + 1 |
ackermann( 0, n ) = n + 1 |
||
ackermann( m, 0 ) = ackermann( m - 1, 1 ) |
ackermann( m, 0 ) = ackermann( m - 1, 1 ) |
||
Line 2,533: | Line 3,853: | ||
for m <- 0..3, n <- 0..4 |
for m <- 0..3, n <- 0..4 |
||
printf( 'Ackermann( %d, %d ) = %d\n', m, n, ackermann(m, n) )</ |
printf( 'Ackermann( %d, %d ) = %d\n', m, n, ackermann(m, n) )</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 2,562: | Line 3,882: | ||
=={{header|Futhark}}== |
=={{header|Futhark}}== |
||
<syntaxhighlight lang="futhark"> |
|||
<lang Futhark> |
|||
fun ackermann(m: int, n: int): int = |
fun ackermann(m: int, n: int): int = |
||
if m == 0 then n + 1 |
if m == 0 then n + 1 |
||
else if n == 0 then ackermann(m-1, 1) |
else if n == 0 then ackermann(m-1, 1) |
||
else ackermann(m - 1, ackermann(m, n-1)) |
else ackermann(m - 1, ackermann(m, n-1)) |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|FutureBasic}}== |
=={{header|FutureBasic}}== |
||
< |
<syntaxhighlight lang="futurebasic"> |
||
include " |
include "NSLog.incl" |
||
local fn Ackerman( m as NSInteger, n as NSInteger ) as NSInteger |
|||
def tab 1 |
|||
NSInteger result |
|||
select |
|||
case m == 0 : result = ( n + 1 ) |
|||
case n == 0 : result = fn Ackerman( ( m - 1 ), 1 ) |
|||
case else : result = fn Ackerman( ( m - 1 ), fn Ackerman( m, ( n - 1 ) ) ) |
|||
end select |
|||
end fn = result |
|||
NSInteger m, n |
|||
begin globals |
|||
CFMutableStringRef mutStr |
|||
dim as container gC |
|||
end globals |
|||
mutStr = fn StringWithCapacity( 0 ) |
|||
def fn Ackerman( m as long, n as long ) as long |
|||
local fn Ackerman( m as long, n as long ) as long |
|||
dim as long result |
|||
if m == 0 then result = n + 1 : exit fn |
|||
if ( n == 0 ) |
|||
result = fn Ackerman( m - 1, 1 ) |
|||
exit fn |
|||
end if |
|||
result = fn Ackerman( m - 1, fn Ackerman(m, n - 1) ) |
|||
end fn = result |
|||
dim as long n, m |
|||
/* |
|||
Cache response in global string container to speed |
|||
processing rather printing each iteration. |
|||
*/ |
|||
for m = 0 to 3 |
for m = 0 to 3 |
||
for n = 0 to 9 |
|||
StringAppendString( mutStr, fn StringWithFormat( @"fn Ackerman( %ld, %ld ) = %ld\n", m, n, fn Ackerman( m, n ) ) ) |
|||
next |
|||
next |
next |
||
NSLog( @"%@", mutStr ) |
|||
print gC |
|||
</lang> |
|||
HandleEvents |
|||
</syntaxhighlight> |
|||
Output: |
Output: |
||
<pre> |
<pre> |
||
fn |
fn Ackerman( 0, 0 ) = 1 |
||
fn |
fn Ackerman( 0, 1 ) = 2 |
||
fn |
fn Ackerman( 0, 2 ) = 3 |
||
fn |
fn Ackerman( 0, 3 ) = 4 |
||
fn |
fn Ackerman( 0, 4 ) = 5 |
||
fn |
fn Ackerman( 0, 5 ) = 6 |
||
fn |
fn Ackerman( 0, 6 ) = 7 |
||
fn |
fn Ackerman( 0, 7 ) = 8 |
||
fn |
fn Ackerman( 0, 8 ) = 9 |
||
fn |
fn Ackerman( 0, 9 ) = 10 |
||
fn |
fn Ackerman( 1, 0 ) = 2 |
||
fn |
fn Ackerman( 1, 1 ) = 3 |
||
fn |
fn Ackerman( 1, 2 ) = 4 |
||
fn |
fn Ackerman( 1, 3 ) = 5 |
||
fn |
fn Ackerman( 1, 4 ) = 6 |
||
fn |
fn Ackerman( 1, 5 ) = 7 |
||
fn |
fn Ackerman( 1, 6 ) = 8 |
||
fn |
fn Ackerman( 1, 7 ) = 9 |
||
fn |
fn Ackerman( 1, 8 ) = 10 |
||
fn |
fn Ackerman( 1, 9 ) = 11 |
||
fn |
fn Ackerman( 2, 0 ) = 3 |
||
fn |
fn Ackerman( 2, 1 ) = 5 |
||
fn |
fn Ackerman( 2, 2 ) = 7 |
||
fn |
fn Ackerman( 2, 3 ) = 9 |
||
fn |
fn Ackerman( 2, 4 ) = 11 |
||
fn |
fn Ackerman( 2, 5 ) = 13 |
||
fn |
fn Ackerman( 2, 6 ) = 15 |
||
fn |
fn Ackerman( 2, 7 ) = 17 |
||
fn |
fn Ackerman( 2, 8 ) = 19 |
||
fn |
fn Ackerman( 2, 9 ) = 21 |
||
fn |
fn Ackerman( 3, 0 ) = 5 |
||
fn |
fn Ackerman( 3, 1 ) = 13 |
||
fn |
fn Ackerman( 3, 2 ) = 29 |
||
fn |
fn Ackerman( 3, 3 ) = 61 |
||
fn |
fn Ackerman( 3, 4 ) = 125 |
||
fn |
fn Ackerman( 3, 5 ) = 253 |
||
fn |
fn Ackerman( 3, 6 ) = 509 |
||
fn |
fn Ackerman( 3, 7 ) = 1021 |
||
fn |
fn Ackerman( 3, 8 ) = 2045 |
||
fn |
fn Ackerman( 3, 9 ) = 4093 |
||
fn ackerman( 3, 7 ) = 1021 |
|||
fn ackerman( 3, 8 ) = 2045 |
|||
fn ackerman( 3, 9 ) = 4093 |
|||
fn ackerman( 3, 10 ) = 8189 |
|||
</pre> |
</pre> |
||
=={{header| |
=={{header|Fōrmulæ}}== |
||
<lang gambas> |
|||
Public Function ackermann (m as Float, n as Float) as Float |
|||
If m = 0 then |
|||
return n + 1 |
|||
end If |
|||
If n = 0 then |
|||
return ackermann(m - 1, 1) |
|||
end If |
|||
return ackermann(m - 1, ackermann(m, n - 1)) |
|||
{{FormulaeEntry|page=https://formulae.org/?script=examples/Ackermann_function}} |
|||
End |
|||
'''Solution''' |
|||
[[File:Fōrmulæ - Ackermann function 01.png]] |
|||
Public Sub Main() |
|||
Dim m, n as Float |
|||
'''Test case''' |
|||
For m = 0 to 3 |
|||
For n = 0 to 4 |
|||
[[File:Fōrmulæ - Ackermann function 02.png]] |
|||
print "Ackerman(";m;",";n;")=";ackermann(m, n) |
|||
Next |
|||
Next |
|||
[[File:Fōrmulæ - Ackermann function 03.png]] |
|||
=={{header|Gambas}}== |
|||
<syntaxhighlight lang="gambas">Public Function Ackermann(m As Float, n As Float) As Float |
|||
If m = 0 Then |
|||
Return n + 1 |
|||
End If |
|||
If n = 0 Then |
|||
Return Ackermann(m - 1, 1) |
|||
End If |
|||
Return Ackermann(m - 1, Ackermann(m, n - 1)) |
|||
End |
End |
||
</lang> |
|||
Public Sub Main() |
|||
Dim m, n As Float |
|||
For m = 0 To 3 |
|||
For n = 0 To 4 |
|||
Print "Ackermann("; m; ", "; n; ") = "; Ackermann(m, n) |
|||
Next |
|||
Next |
|||
End</syntaxhighlight> |
|||
=={{header|GAP}}== |
=={{header|GAP}}== |
||
< |
<syntaxhighlight lang="gap">ack := function(m, n) |
||
if m = 0 then |
if m = 0 then |
||
return n + 1; |
return n + 1; |
||
Line 2,693: | Line 4,008: | ||
return fail; |
return fail; |
||
fi; |
fi; |
||
end;</ |
end;</syntaxhighlight> |
||
=={{header|Genyris}}== |
=={{header|Genyris}}== |
||
< |
<syntaxhighlight lang="genyris">def A (m n) |
||
cond |
cond |
||
(equal? m 0) |
(equal? m 0) |
||
Line 2,704: | Line 4,019: | ||
else |
else |
||
A (- m 1) |
A (- m 1) |
||
A m (- n 1)</ |
A m (- n 1)</syntaxhighlight> |
||
=={{header|GML}}== |
=={{header|GML}}== |
||
Define a script resource named ackermann and paste this code inside: |
Define a script resource named ackermann and paste this code inside: |
||
< |
<syntaxhighlight lang="gml">///ackermann(m,n) |
||
var m, n; |
var m, n; |
||
m = argument0; |
m = argument0; |
||
Line 2,723: | Line 4,038: | ||
{ |
{ |
||
return (ackermann(m-1,ackermann(m,n-1,2),1)) |
return (ackermann(m-1,ackermann(m,n-1,2),1)) |
||
}</ |
}</syntaxhighlight> |
||
=={{header|gnuplot}}== |
=={{header|gnuplot}}== |
||
< |
<syntaxhighlight lang="gnuplot">A (m, n) = m == 0 ? n + 1 : n == 0 ? A (m - 1, 1) : A (m - 1, A (m, n - 1)) |
||
print A (0, 4) |
print A (0, 4) |
||
print A (1, 4) |
print A (1, 4) |
||
print A (2, 4) |
print A (2, 4) |
||
print A (3, 4)</ |
print A (3, 4)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
5 |
5 |
||
Line 2,739: | Line 4,054: | ||
=={{header|Go}}== |
=={{header|Go}}== |
||
===Classic version=== |
===Classic version=== |
||
< |
<syntaxhighlight lang="go">func Ackermann(m, n uint) uint { |
||
switch 0 { |
switch 0 { |
||
case m: |
case m: |
||
Line 2,747: | Line 4,062: | ||
} |
} |
||
return Ackermann(m - 1, Ackermann(m, n - 1)) |
return Ackermann(m - 1, Ackermann(m, n - 1)) |
||
}</ |
}</syntaxhighlight> |
||
===Expanded version=== |
===Expanded version=== |
||
< |
<syntaxhighlight lang="go">func Ackermann2(m, n uint) uint { |
||
switch { |
switch { |
||
case m == 0: |
case m == 0: |
||
Line 2,763: | Line 4,078: | ||
} |
} |
||
return Ackermann2(m - 1, Ackermann2(m, n - 1)) |
return Ackermann2(m - 1, Ackermann2(m, n - 1)) |
||
}</ |
}</syntaxhighlight> |
||
===Expanded version with arbitrary precision=== |
===Expanded version with arbitrary precision=== |
||
< |
<syntaxhighlight lang="go">package main |
||
import ( |
import ( |
||
Line 2,854: | Line 4,169: | ||
) |
) |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 2,868: | Line 4,183: | ||
=={{header|Golfscript}}== |
=={{header|Golfscript}}== |
||
< |
<syntaxhighlight lang="golfscript">{ |
||
:_n; :_m; |
:_n; :_m; |
||
_m 0= {_n 1+} |
_m 0= {_n 1+} |
||
Line 2,875: | Line 4,190: | ||
if} |
if} |
||
if |
if |
||
}:ack;</ |
}:ack;</syntaxhighlight> |
||
=={{header|Groovy}}== |
=={{header|Groovy}}== |
||
< |
<syntaxhighlight lang="groovy">def ack ( m, n ) { |
||
assert m >= 0 && n >= 0 : 'both arguments must be non-negative' |
assert m >= 0 && n >= 0 : 'both arguments must be non-negative' |
||
m == 0 ? n + 1 : n == 0 ? ack(m-1, 1) : ack(m-1, ack(m, n-1)) |
m == 0 ? n + 1 : n == 0 ? ack(m-1, 1) : ack(m-1, ack(m, n-1)) |
||
}</ |
}</syntaxhighlight> |
||
Test program: |
Test program: |
||
< |
<syntaxhighlight lang="groovy">def ackMatrix = (0..3).collect { m -> (0..8).collect { n -> ack(m, n) } } |
||
ackMatrix.each { it.each { elt -> printf "%7d", elt }; println() }</ |
ackMatrix.each { it.each { elt -> printf "%7d", elt }; println() }</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> 1 2 3 4 5 6 7 8 9 |
<pre> 1 2 3 4 5 6 7 8 9 |
||
Line 2,891: | Line 4,206: | ||
5 13 29 61 125 253 509 1021 2045</pre> |
5 13 29 61 125 253 509 1021 2045</pre> |
||
Note: In the default groovyConsole configuration for WinXP, "ack(4,1)" caused a stack overflow error! |
Note: In the default groovyConsole configuration for WinXP, "ack(4,1)" caused a stack overflow error! |
||
=={{header|Hare}}== |
|||
<syntaxhighlight lang="hare">use fmt; |
|||
fn ackermann(m: u64, n: u64) u64 = { |
|||
if (m == 0) { |
|||
return n + 1; |
|||
}; |
|||
if (n == 0) { |
|||
return ackermann(m - 1, 1); |
|||
}; |
|||
return ackermann(m - 1, ackermann(m, n - 1)); |
|||
}; |
|||
export fn main() void = { |
|||
for (let m = 0u64; m < 4; m += 1) { |
|||
for (let n = 0u64; n < 10; n += 1) { |
|||
fmt::printfln("A({}, {}) = {}", m, n, ackermann(m, n))!; |
|||
}; |
|||
fmt::println()!; |
|||
}; |
|||
};</syntaxhighlight> |
|||
=={{header|Haskell}}== |
=={{header|Haskell}}== |
||
< |
<syntaxhighlight lang="haskell">ack :: Int -> Int -> Int |
||
ack 0 n = succ n |
ack 0 n = succ n |
||
ack m 0 = ack (pred m) 1 |
ack m 0 = ack (pred m) 1 |
||
Line 2,899: | Line 4,236: | ||
main :: IO () |
main :: IO () |
||
main = mapM_ print $ uncurry ack <$> [(0, 0), (3, 4)]</ |
main = mapM_ print $ uncurry ack <$> [(0, 0), (3, 4)]</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>1 |
<pre>1 |
||
Line 2,905: | Line 4,242: | ||
Generating a list instead: |
Generating a list instead: |
||
< |
<syntaxhighlight lang="haskell">import Data.List (mapAccumL) |
||
-- everything here are [Int] or [[Int]], which would overflow |
-- everything here are [Int] or [[Int]], which would overflow |
||
Line 2,914: | Line 4,251: | ||
f a b = (aa, head aa) where aa = drop b a |
f a b = (aa, head aa) where aa = drop b a |
||
main = mapM_ print $ map (\n -> take (6 - n) $ ackermann !! n) [0..5]</ |
main = mapM_ print $ map (\n -> take (6 - n) $ ackermann !! n) [0..5]</syntaxhighlight> |
||
=={{header|Haxe}}== |
=={{header|Haxe}}== |
||
< |
<syntaxhighlight lang="haxe">class RosettaDemo |
||
{ |
{ |
||
static public function main() |
static public function main() |
||
Line 2,936: | Line 4,273: | ||
return ackermann(m-1, ackermann(m, n-1)); |
return ackermann(m-1, ackermann(m, n-1)); |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Hoon}}== |
|||
<syntaxhighlight lang="hoon"> |
|||
|= [m=@ud n=@ud] |
|||
?: =(m 0) |
|||
+(n) |
|||
?: =(n 0) |
|||
$(n 1, m (dec m)) |
|||
$(m (dec m), n $(n (dec n))) |
|||
</syntaxhighlight> |
|||
=={{header|Icon}} and {{header|Unicon}}== |
=={{header|Icon}} and {{header|Unicon}}== |
||
Line 2,942: | Line 4,289: | ||
Taken from the public domain Icon Programming Library's [http://www.cs.arizona.edu/icon/library/procs/memrfncs.htm acker in memrfncs], |
Taken from the public domain Icon Programming Library's [http://www.cs.arizona.edu/icon/library/procs/memrfncs.htm acker in memrfncs], |
||
written by Ralph E. Griswold. |
written by Ralph E. Griswold. |
||
< |
<syntaxhighlight lang="icon">procedure acker(i, j) |
||
static memory |
static memory |
||
Line 2,966: | Line 4,313: | ||
write() |
write() |
||
} |
} |
||
end</ |
end</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 2,975: | Line 4,322: | ||
=={{header|Idris}}== |
=={{header|Idris}}== |
||
< |
<syntaxhighlight lang="idris">A : Nat -> Nat -> Nat |
||
A Z n = S n |
A Z n = S n |
||
A (S m) Z = A m (S Z) |
A (S m) Z = A m (S Z) |
||
A (S m) (S n) = A m (A (S m) n)</ |
A (S m) (S n) = A m (A (S m) n)</syntaxhighlight> |
||
=={{header|Ioke}}== |
=={{header|Ioke}}== |
||
{{trans|Clojure}} |
{{trans|Clojure}} |
||
< |
<syntaxhighlight lang="ioke">ackermann = method(m,n, |
||
cond( |
cond( |
||
m zero?, n succ, |
m zero?, n succ, |
||
n zero?, ackermann(m pred, 1), |
n zero?, ackermann(m pred, 1), |
||
ackermann(m pred, ackermann(m, n pred))) |
ackermann(m pred, ackermann(m, n pred))) |
||
)</ |
)</syntaxhighlight> |
||
=={{header|J}}== |
=={{header|J}}== |
||
As posted at the [[j:Essays/Ackermann%27s%20Function|J wiki]] |
As posted at the [[j:Essays/Ackermann%27s%20Function|J wiki]] |
||
< |
<syntaxhighlight lang="j">ack=: c1`c1`c2`c3 @. (#.@,&*) M. |
||
c1=: >:@] NB. if 0=x, 1+y |
c1=: >:@] NB. if 0=x, 1+y |
||
c2=: <:@[ ack 1: NB. if 0=y, (x-1) ack 1 |
c2=: <:@[ ack 1: NB. if 0=y, (x-1) ack 1 |
||
c3=: <:@[ ack [ ack <:@] NB. else, (x-1) ack x ack y-1</ |
c3=: <:@[ ack [ ack <:@] NB. else, (x-1) ack x ack y-1</syntaxhighlight> |
||
{{out|Example use}} |
{{out|Example use}} |
||
< |
<syntaxhighlight lang="j"> 0 ack 3 |
||
4 |
4 |
||
1 ack 3 |
1 ack 3 |
||
Line 3,003: | Line 4,350: | ||
9 |
9 |
||
3 ack 3 |
3 ack 3 |
||
61</ |
61</syntaxhighlight> |
||
J's stack was too small for me to compute <tt>4 ack 1</tt>. |
J's stack was too small for me to compute <tt>4 ack 1</tt>. |
||
===Alternative Primitive Recursive Version=== |
===Alternative Primitive Recursive Version=== |
||
Line 3,009: | Line 4,356: | ||
The Ackermann function derived in this fashion is primitive recursive. This is possible because in J (as in some other languages) functions, or representations of them, are first-class values. |
The Ackermann function derived in this fashion is primitive recursive. This is possible because in J (as in some other languages) functions, or representations of them, are first-class values. |
||
< |
<syntaxhighlight lang="j"> Ack=. 3 -~ [ ({&(2 4$'>: 2x&+') ::(,&'&1'&'2x&*'@:(-&2))"0@:[ 128!:2 ]) 3 + ]</syntaxhighlight> |
||
{{out|Example use}} |
{{out|Example use}} |
||
< |
<syntaxhighlight lang="j"> 0 1 2 3 Ack 0 1 2 3 4 5 6 7 |
||
1 2 3 4 5 6 7 8 |
1 2 3 4 5 6 7 8 |
||
2 3 4 5 6 7 8 9 |
2 3 4 5 6 7 8 9 |
||
Line 3,026: | Line 4,373: | ||
5 Ack 0 |
5 Ack 0 |
||
65533 |
65533 |
||
</syntaxhighlight> |
|||
</lang> |
|||
A structured derivation of Ack follows: |
A structured derivation of Ack follows: |
||
< |
<syntaxhighlight lang="j"> o=. @: NB. Composition of verbs (functions) |
||
x=. o[ NB. Composing the left noun (argument) |
x=. o[ NB. Composing the left noun (argument) |
||
Line 3,056: | Line 4,403: | ||
(Ack=. (3 -~ [ Buck 3 + ])f.) NB. Ackermann function-level code |
(Ack=. (3 -~ [ Buck 3 + ])f.) NB. Ackermann function-level code |
||
3 -~ [ ({&(2 4$'>: 2x&+') ::(,&'&1'&'2x&*'@:(-&2))"0@:[ 128!:2 ]) 3 + ]</ |
3 -~ [ ({&(2 4$'>: 2x&+') ::(,&'&1'&'2x&*'@:(-&2))"0@:[ 128!:2 ]) 3 + ]</syntaxhighlight> |
||
=={{header|Java}}== |
=={{header|Java}}== |
||
[[Category:Arbitrary precision]] |
[[Category:Arbitrary precision]] |
||
< |
<syntaxhighlight lang="java">import java.math.BigInteger; |
||
public static BigInteger ack(BigInteger m, BigInteger n) { |
public static BigInteger ack(BigInteger m, BigInteger n) { |
||
Line 3,067: | Line 4,414: | ||
: ack(m.subtract(BigInteger.ONE), |
: ack(m.subtract(BigInteger.ONE), |
||
n.equals(BigInteger.ZERO) ? BigInteger.ONE : ack(m, n.subtract(BigInteger.ONE))); |
n.equals(BigInteger.ZERO) ? BigInteger.ONE : ack(m, n.subtract(BigInteger.ONE))); |
||
}</ |
}</syntaxhighlight> |
||
{{works with|Java|8+}} |
{{works with|Java|8+}} |
||
< |
<syntaxhighlight lang="java5">@FunctionalInterface |
||
public interface FunctionalField<FIELD extends Enum<?>> { |
public interface FunctionalField<FIELD extends Enum<?>> { |
||
public Object untypedField(FIELD field); |
public Object untypedField(FIELD field); |
||
Line 3,078: | Line 4,425: | ||
return (VALUE) untypedField(field); |
return (VALUE) untypedField(field); |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
< |
<syntaxhighlight lang="java5">import java.util.function.BiFunction; |
||
import java.util.function.Function; |
import java.util.function.Function; |
||
import java.util.function.Predicate; |
import java.util.function.Predicate; |
||
Line 3,124: | Line 4,471: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
< |
<syntaxhighlight lang="java5">import java.math.BigInteger; |
||
import java.util.Stack; |
import java.util.Stack; |
||
import java.util.function.BinaryOperator; |
import java.util.function.BinaryOperator; |
||
Line 3,269: | Line 4,616: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{Iterative version}} |
|||
<syntaxhighlight lang="java5">/* |
|||
* Source https://stackoverflow.com/a/51092690/5520417 |
|||
*/ |
|||
package matematicas; |
|||
import java.math.BigInteger; |
|||
import java.util.HashMap; |
|||
import java.util.Stack; |
|||
/** |
|||
* @author rodri |
|||
* |
|||
*/ |
|||
public class IterativeAckermannMemoryOptimization extends Thread { |
|||
/** |
|||
* Max percentage of free memory that the program will use. Default is 10% since |
|||
* the majority of the used devices are mobile and therefore it is more likely |
|||
* that the user will have more opened applications at the same time than in a |
|||
* desktop device |
|||
*/ |
|||
private static Double SYSTEM_MEMORY_LIMIT_PERCENTAGE = 0.1; |
|||
/** |
|||
* Attribute of the type IterativeAckermann |
|||
*/ |
|||
private IterativeAckermann iterativeAckermann; |
|||
/** |
|||
* @param iterativeAckermann |
|||
*/ |
|||
public IterativeAckermannMemoryOptimization(IterativeAckermann iterativeAckermann) { |
|||
super(); |
|||
this.iterativeAckermann = iterativeAckermann; |
|||
} |
|||
/** |
|||
* @return |
|||
*/ |
|||
public IterativeAckermann getIterativeAckermann() { |
|||
return iterativeAckermann; |
|||
} |
|||
/** |
|||
* @param iterativeAckermann |
|||
*/ |
|||
public void setIterativeAckermann(IterativeAckermann iterativeAckermann) { |
|||
this.iterativeAckermann = iterativeAckermann; |
|||
} |
|||
public static Double getSystemMemoryLimitPercentage() { |
|||
return SYSTEM_MEMORY_LIMIT_PERCENTAGE; |
|||
} |
|||
/** |
|||
* Principal method of the thread. Checks that the memory used doesn't exceed or |
|||
* equal the limit, and informs the user when that happens. |
|||
*/ |
|||
@Override |
|||
public void run() { |
|||
String operating_system = System.getProperty("os.name").toLowerCase(); |
|||
if ( operating_system.equals("windows") || operating_system.equals("linux") || operating_system.equals("macintosh") ) { |
|||
SYSTEM_MEMORY_LIMIT_PERCENTAGE = 0.25; |
|||
} |
|||
while ( iterativeAckermann.getConsumed_heap() >= SYSTEM_MEMORY_LIMIT_PERCENTAGE * Runtime.getRuntime().freeMemory() ) { |
|||
try { |
|||
wait(); |
|||
} |
|||
catch ( InterruptedException e ) { |
|||
// TODO Auto-generated catch block |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
if ( ! iterativeAckermann.isAlive() ) |
|||
iterativeAckermann.start(); |
|||
else |
|||
notifyAll(); |
|||
} |
|||
} |
|||
public class IterativeAckermann extends Thread { |
|||
/* |
|||
* Adjust parameters conveniently |
|||
*/ |
|||
/** |
|||
* |
|||
*/ |
|||
private static final int HASH_SIZE_LIMIT = 636; |
|||
/** |
|||
* |
|||
*/ |
|||
private BigInteger m; |
|||
/** |
|||
* |
|||
*/ |
|||
private BigInteger n; |
|||
/** |
|||
* |
|||
*/ |
|||
private Integer hash_size; |
|||
/** |
|||
* |
|||
*/ |
|||
private Long consumed_heap; |
|||
/** |
|||
* @param m |
|||
* @param n |
|||
* @param invalid |
|||
* @param invalid2 |
|||
*/ |
|||
public IterativeAckermann(BigInteger m, BigInteger n, Integer invalid, Long invalid2) { |
|||
super(); |
|||
this.m = m; |
|||
this.n = n; |
|||
this.hash_size = invalid; |
|||
this.consumed_heap = invalid2; |
|||
} |
|||
/** |
|||
* |
|||
*/ |
|||
public IterativeAckermann() { |
|||
// TODO Auto-generated constructor stub |
|||
super(); |
|||
m = null; |
|||
n = null; |
|||
hash_size = 0; |
|||
consumed_heap = 0l; |
|||
} |
|||
/** |
|||
* @return |
|||
*/ |
|||
public static BigInteger getLimit() { |
|||
return LIMIT; |
|||
} |
|||
/** |
|||
* @author rodri |
|||
* |
|||
* @param <T1> |
|||
* @param <T2> |
|||
*/ |
|||
/** |
|||
* @author rodri |
|||
* |
|||
* @param <T1> |
|||
* @param <T2> |
|||
*/ |
|||
static class Pair<T1, T2> { |
|||
/** |
|||
* |
|||
*/ |
|||
/** |
|||
* |
|||
*/ |
|||
T1 x; |
|||
/** |
|||
* |
|||
*/ |
|||
/** |
|||
* |
|||
*/ |
|||
T2 y; |
|||
/** |
|||
* @param x_ |
|||
* @param y_ |
|||
*/ |
|||
/** |
|||
* @param x_ |
|||
* @param y_ |
|||
*/ |
|||
Pair(T1 x_, T2 y_) { |
|||
x = x_; |
|||
y = y_; |
|||
} |
|||
/** |
|||
* |
|||
*/ |
|||
/** |
|||
* |
|||
*/ |
|||
@Override |
|||
public int hashCode() { |
|||
return x.hashCode() ^ y.hashCode(); |
|||
} |
|||
/** |
|||
* |
|||
*/ |
|||
/** |
|||
* |
|||
*/ |
|||
@Override |
|||
public boolean equals(Object o_) { |
|||
if ( o_ == null ) { |
|||
return false; |
|||
} |
|||
if ( o_.getClass() != this.getClass() ) { |
|||
return false; |
|||
} |
|||
Pair<?, ?> o = (Pair<?, ?>) o_; |
|||
return x.equals(o.x) && y.equals(o.y); |
|||
} |
|||
} |
|||
/** |
|||
* |
|||
*/ |
|||
private static final BigInteger LIMIT = new BigInteger("6"); |
|||
/** |
|||
* @param m |
|||
* @param n |
|||
* @return |
|||
*/ |
|||
/** |
|||
* |
|||
*/ |
|||
@Override |
|||
public void run() { |
|||
while ( hash_size >= HASH_SIZE_LIMIT ) { |
|||
try { |
|||
this.wait(); |
|||
} |
|||
catch ( InterruptedException e ) { |
|||
// TODO Auto-generated catch block |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
for ( BigInteger i = BigInteger.ZERO; i.compareTo(LIMIT) == - 1; i = i.add(BigInteger.ONE) ) { |
|||
for ( BigInteger j = BigInteger.ZERO; j.compareTo(LIMIT) == - 1; j = j.add(BigInteger.ONE) ) { |
|||
IterativeAckermann iterativeAckermann = new IterativeAckermann(i, j, null, null); |
|||
System.out.printf("Ackmermann(%d, %d) = %d\n", i, j, iterativeAckermann.iterative_ackermann(i, j)); |
|||
} |
|||
} |
|||
} |
|||
/** |
|||
* @return |
|||
*/ |
|||
public BigInteger getM() { |
|||
return m; |
|||
} |
|||
/** |
|||
* @param m |
|||
*/ |
|||
public void setM(BigInteger m) { |
|||
this.m = m; |
|||
} |
|||
/** |
|||
* @return |
|||
*/ |
|||
public BigInteger getN() { |
|||
return n; |
|||
} |
|||
/** |
|||
* @param n |
|||
*/ |
|||
public void setN(BigInteger n) { |
|||
this.n = n; |
|||
} |
|||
/** |
|||
* @return |
|||
*/ |
|||
public Integer getHash_size() { |
|||
return hash_size; |
|||
} |
|||
/** |
|||
* @param hash_size |
|||
*/ |
|||
public void setHash_size(Integer hash_size) { |
|||
this.hash_size = hash_size; |
|||
} |
|||
/** |
|||
* @return |
|||
*/ |
|||
public Long getConsumed_heap() { |
|||
return consumed_heap; |
|||
} |
|||
/** |
|||
* @param consumed_heap |
|||
*/ |
|||
public void setConsumed_heap(Long consumed_heap) { |
|||
this.consumed_heap = consumed_heap; |
|||
} |
|||
/** |
|||
* @param m |
|||
* @param n |
|||
* @return |
|||
*/ |
|||
public BigInteger iterative_ackermann(BigInteger m, BigInteger n) { |
|||
if ( m.compareTo(BigInteger.ZERO) != - 1 && m.compareTo(BigInteger.ZERO) != - 1 ) |
|||
try { |
|||
HashMap<Pair<BigInteger, BigInteger>, BigInteger> solved_set = new HashMap<Pair<BigInteger, BigInteger>, BigInteger>(900000); |
|||
Stack<Pair<BigInteger, BigInteger>> to_solve = new Stack<Pair<BigInteger, BigInteger>>(); |
|||
to_solve.push(new Pair<BigInteger, BigInteger>(m, n)); |
|||
while ( ! to_solve.isEmpty() ) { |
|||
Pair<BigInteger, BigInteger> head = to_solve.peek(); |
|||
if ( head.x.equals(BigInteger.ZERO) ) { |
|||
solved_set.put(head, head.y.add(BigInteger.ONE)); |
|||
to_solve.pop(); |
|||
} |
|||
else if ( head.y.equals(BigInteger.ZERO) ) { |
|||
Pair<BigInteger, BigInteger> next = new Pair<BigInteger, BigInteger>(head.x.subtract(BigInteger.ONE), BigInteger.ONE); |
|||
BigInteger result = solved_set.get(next); |
|||
if ( result == null ) { |
|||
to_solve.push(next); |
|||
} |
|||
else { |
|||
solved_set.put(head, result); |
|||
to_solve.pop(); |
|||
} |
|||
} |
|||
else { |
|||
Pair<BigInteger, BigInteger> next0 = new Pair<BigInteger, BigInteger>(head.x, head.y.subtract(BigInteger.ONE)); |
|||
BigInteger result0 = solved_set.get(next0); |
|||
if ( result0 == null ) { |
|||
to_solve.push(next0); |
|||
} |
|||
else { |
|||
Pair<BigInteger, BigInteger> next = new Pair<BigInteger, BigInteger>(head.x.subtract(BigInteger.ONE), result0); |
|||
BigInteger result = solved_set.get(next); |
|||
if ( result == null ) { |
|||
to_solve.push(next); |
|||
} |
|||
else { |
|||
solved_set.put(head, result); |
|||
to_solve.pop(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
this.hash_size = solved_set.size(); |
|||
System.out.println("Hash Size: " + hash_size); |
|||
consumed_heap = (Runtime.getRuntime().totalMemory() / (1024 * 1024)); |
|||
System.out.println("Consumed Heap: " + consumed_heap + "m"); |
|||
setHash_size(hash_size); |
|||
setConsumed_heap(consumed_heap); |
|||
return solved_set.get(new Pair<BigInteger, BigInteger>(m, n)); |
|||
} |
|||
catch ( OutOfMemoryError e ) { |
|||
// TODO: handle exception |
|||
e.printStackTrace(); |
|||
} |
|||
throw new IllegalArgumentException("The arguments must be non-negative integers."); |
|||
} |
|||
/** |
|||
* @param args |
|||
*/ |
|||
/** |
|||
* @param args |
|||
*/ |
|||
public static void main(String[] args) { |
|||
IterativeAckermannMemoryOptimization iterative_ackermann_memory_optimization = new IterativeAckermannMemoryOptimization( |
|||
new IterativeAckermann()); |
|||
iterative_ackermann_memory_optimization.start(); |
|||
} |
|||
} |
|||
</syntaxhighlight> |
|||
=={{header|JavaScript}}== |
=={{header|JavaScript}}== |
||
===ES5=== |
|||
<lang javascript>function ack(m, n) { |
|||
<syntaxhighlight lang="javascript">function ack(m, n) { |
|||
return m === 0 ? n + 1 : ack(m - 1, n === 0 ? 1 : ack(m, n - 1)); |
return m === 0 ? n + 1 : ack(m - 1, n === 0 ? 1 : ack(m, n - 1)); |
||
}</ |
}</syntaxhighlight> |
||
===Eliminating Tail Calls=== |
|||
<syntaxhighlight lang="javascript">function ack(M,N) { |
|||
for (; M > 0; M--) { |
|||
N = N === 0 ? 1 : ack(M,N-1); |
|||
} |
|||
return N+1; |
|||
}</syntaxhighlight> |
|||
===Iterative, With Explicit Stack=== |
|||
<syntaxhighlight lang="javascript">function stackermann(M, N) { |
|||
const stack = []; |
|||
for (;;) { |
|||
if (M === 0) { |
|||
N++; |
|||
if (stack.length === 0) return N; |
|||
const r = stack[stack.length-1]; |
|||
if (r[1] === 1) stack.length--; |
|||
else r[1]--; |
|||
M = r[0]; |
|||
} else if (N === 0) { |
|||
M--; |
|||
N = 1; |
|||
} else { |
|||
M-- |
|||
stack.push([M, N]); |
|||
N = 1; |
|||
} |
|||
} |
|||
}</syntaxhighlight> |
|||
===Stackless Iterative=== |
|||
<syntaxhighlight lang="javascript">#!/usr/bin/env nodejs |
|||
function ack(M, N){ |
|||
const next = new Float64Array(M + 1); |
|||
const goal = new Float64Array(M + 1).fill(1, 0, M); |
|||
const n = N + 1; |
|||
// This serves as a sentinel value; |
|||
// next[M] never equals goal[M] == -1, |
|||
// so we don't need an extra check for |
|||
// loop termination below. |
|||
goal[M] = -1; |
|||
let v; |
|||
do { |
|||
v = next[0] + 1; |
|||
let m = 0; |
|||
while (next[m] === goal[m]) { |
|||
goal[m] = v; |
|||
next[m++]++; |
|||
} |
|||
next[m]++; |
|||
} while (next[M] !== n); |
|||
return v; |
|||
} |
|||
var args = process.argv; |
|||
console.log(ack(parseInt(args[2]), parseInt(args[3])));</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
> time ./ack.js 4 1 |
|||
65533 |
|||
./ack.js 4 1 0,48s user 0,03s system 100% cpu 0,505 total ; AMD FX-8350 @ 4 GHz |
|||
</pre> |
|||
===ES6=== |
|||
<syntaxhighlight lang="javascript">(() => { |
|||
'use strict'; |
|||
// ackermann :: Int -> Int -> Int |
|||
const ackermann = m => n => { |
|||
const go = (m, n) => |
|||
0 === m ? ( |
|||
succ(n) |
|||
) : go(pred(m), 0 === n ? ( |
|||
1 |
|||
) : go(m, pred(n))); |
|||
return go(m, n); |
|||
}; |
|||
// TEST ----------------------------------------------- |
|||
const main = () => console.log(JSON.stringify( |
|||
[0, 1, 2, 3].map( |
|||
flip(ackermann)(3) |
|||
) |
|||
)); |
|||
// GENERAL FUNCTIONS ---------------------------------- |
|||
// flip :: (a -> b -> c) -> b -> a -> c |
|||
const flip = f => |
|||
x => y => f(y)(x); |
|||
// pred :: Enum a => a -> a |
|||
const pred = x => x - 1; |
|||
// succ :: Enum a => a -> a |
|||
const succ = x => 1 + x; |
|||
// MAIN --- |
|||
return main(); |
|||
})();</syntaxhighlight> |
|||
{{Out}} |
|||
<pre>[4,5,9,61]</pre> |
|||
=={{header|Joy}}== |
=={{header|Joy}}== |
||
<syntaxhighlight lang="joy">DEFINE ack == [[[pop null] popd succ] |
|||
From [http://www.latrobe.edu.au/phimvt/joy/jp-nestrec.html here] |
|||
[[null] pop pred 1 ack] |
|||
[[dup pred swap] dip pred ack ack]] |
|||
cond.</syntaxhighlight> |
|||
[ [dup pred swap] dip pred ack ack ] ] |
|||
another using a combinator: |
|||
cond.</lang> |
|||
<syntaxhighlight lang="joy">DEFINE ack == [[[pop null] [popd succ]] |
|||
another using a combinator |
|||
[[null] [pop pred 1] []] |
|||
[[[dup pred swap] dip pred] [] []]] |
|||
condnestrec.</syntaxhighlight> |
|||
[ [[dup pred swap] dip pred] [] [] ] ] |
|||
condnestrec.</lang> |
|||
Whenever there are two definitions with the same name, the last one is the one that is used, when invoked. |
|||
=={{header|jq}}== |
=={{header|jq}}== |
||
{{ works with|jq|1.4}} |
{{ works with|jq|1.4}} |
||
'''Also works with gojq, the Go implementation of jq.''' |
|||
Except for a minor tweak to the line using string interpolation, the following have also been tested using jaq, the Rust implementation of jq, as of April 13, 2023. |
|||
For infinite-precision integer arithmetic, use gojq or fq. |
|||
===Without Memoization=== |
===Without Memoization=== |
||
< |
<syntaxhighlight lang="jq"># input: [m,n] |
||
def ack: |
def ack: |
||
.[0] as $m | .[1] as $n |
.[0] as $m | .[1] as $n |
||
Line 3,298: | Line 5,145: | ||
elif $n == 0 then [$m-1, 1] | ack |
elif $n == 0 then [$m-1, 1] | ack |
||
else [$m-1, ([$m, $n-1 ] | ack)] | ack |
else [$m-1, ([$m, $n-1 ] | ack)] | ack |
||
end ;</ |
end ;</syntaxhighlight> |
||
'''Example:''' |
'''Example:''' |
||
< |
<syntaxhighlight lang="jq">range(0;5) as $i |
||
| range(0; if $i > 3 then 1 else 6 end) as $j |
| range(0; if $i > 3 then 1 else 6 end) as $j |
||
| "A(\($i),\($j)) = \( [$i,$j] | ack )"</ |
| "A(\($i),\($j)) = \( [$i,$j] | ack )"</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
< |
<syntaxhighlight lang="sh"># jq -n -r -f ackermann.jq |
||
A(0,0) = 1 |
A(0,0) = 1 |
||
A(0,1) = 2 |
A(0,1) = 2 |
||
Line 3,329: | Line 5,176: | ||
A(3,4) = 125 |
A(3,4) = 125 |
||
A(3,5) = 253 |
A(3,5) = 253 |
||
A(4,0) = 13</ |
A(4,0) = 13</syntaxhighlight> |
||
===With Memoization and Optimization=== |
===With Memoization and Optimization=== |
||
< |
<syntaxhighlight lang="jq"># input: [m,n, cache] |
||
# output [value, updatedCache] |
# output [value, updatedCache] |
||
def ack: |
def ack: |
||
Line 3,360: | Line 5,207: | ||
def A(m;n): [m,n,{}] | ack | .[0]; |
def A(m;n): [m,n,{}] | ack | .[0]; |
||
</syntaxhighlight> |
|||
</lang> |
|||
'''Examples:''' |
|||
'''Example:'''<lang jq>A(4,1)</lang> |
|||
<syntaxhighlight lang="jq">A(4;1)</syntaxhighlight> |
|||
{{out}} |
|||
<syntaxhighlight lang="sh">65533</syntaxhighlight> |
|||
Using gojq: |
|||
<syntaxhighlight lang="jq">A(4;2), A(3;1000000) | tostring | length</syntaxhighlight> |
|||
{{out}} |
|||
<syntaxhighlight lang="sh"> |
|||
19729 |
|||
301031 |
|||
</syntaxhighlight> |
|||
=={{header|Jsish}}== |
|||
From javascript entry. |
|||
<syntaxhighlight lang="javascript">/* Ackermann function, in Jsish */ |
|||
function ack(m, n) { |
|||
return m === 0 ? n + 1 : ack(m - 1, n === 0 ? 1 : ack(m, n - 1)); |
|||
} |
|||
if (Interp.conf('unitTest')) { |
|||
Interp.conf({maxDepth:4096}); |
|||
; ack(1,3); |
|||
; ack(2,3); |
|||
; ack(3,3); |
|||
; ack(1,5); |
|||
; ack(2,5); |
|||
; ack(3,5); |
|||
} |
|||
/* |
|||
=!EXPECTSTART!= |
|||
ack(1,3) ==> 5 |
|||
ack(2,3) ==> 9 |
|||
ack(3,3) ==> 61 |
|||
ack(1,5) ==> 7 |
|||
ack(2,5) ==> 13 |
|||
ack(3,5) ==> 253 |
|||
=!EXPECTEND!= |
|||
*/</syntaxhighlight> |
|||
{{out}} |
{{out}} |
||
<pre>prompt$ jsish --U Ackermann.jsi |
|||
<lang sh>65533</lang> |
|||
ack(1,3) ==> 5 |
|||
ack(2,3) ==> 9 |
|||
ack(3,3) ==> 61 |
|||
ack(1,5) ==> 7 |
|||
ack(2,5) ==> 13 |
|||
ack(3,5) ==> 253</pre> |
|||
=={{header|Julia}}== |
=={{header|Julia}}== |
||
< |
<syntaxhighlight lang="julia">function ack(m,n) |
||
if m == 0 |
if m == 0 |
||
return n + 1 |
return n + 1 |
||
Line 3,374: | Line 5,268: | ||
return ack(m-1,ack(m,n-1)) |
return ack(m-1,ack(m,n-1)) |
||
end |
end |
||
end</ |
end</syntaxhighlight> |
||
'''One-liner:''' |
'''One-liner:''' |
||
< |
<syntaxhighlight lang="julia">ack2(m::Integer, n::Integer) = m == 0 ? n + 1 : n == 0 ? ack2(m - 1, 1) : ack2(m - 1, ack2(m, n - 1))</syntaxhighlight> |
||
'''Using memoization''', [https://github.com/simonster/Memoize.jl source]: |
'''Using memoization''', [https://github.com/simonster/Memoize.jl source]: |
||
< |
<syntaxhighlight lang="julia">using Memoize |
||
@memoize ack3(m::Integer, n::Integer) = m == 0 ? n + 1 : n == 0 ? ack3(m - 1, 1) : ack3(m - 1, ack3(m, n - 1))</ |
@memoize ack3(m::Integer, n::Integer) = m == 0 ? n + 1 : n == 0 ? ack3(m - 1, 1) : ack3(m - 1, ack3(m, n - 1))</syntaxhighlight> |
||
'''Benchmarking''': |
'''Benchmarking''': |
||
Line 3,393: | Line 5,287: | ||
=={{header|K}}== |
=={{header|K}}== |
||
{{works with|Kona}} |
|||
See [https://github.com/kevinlawler/kona/wiki the K wiki] |
|||
< |
<syntaxhighlight lang="k"> ack:{:[0=x;y+1;0=y;_f[x-1;1];_f[x-1;_f[x;y-1]]]} |
||
ack[2;2] |
ack[2;2] |
||
7 |
|||
ack[2;7] |
|||
17</syntaxhighlight> |
|||
=={{header|Kdf9 Usercode}}== |
=={{header|Kdf9 Usercode}}== |
||
< |
<syntaxhighlight lang="kdf9 usercode">V6; W0; |
||
YS26000; |
YS26000; |
||
RESTART; J999; J999; |
RESTART; J999; J999; |
||
Line 3,447: | Line 5,344: | ||
J99; (tail recursion for A[m-1, A[m, n-1]]); |
J99; (tail recursion for A[m-1, A[m, n-1]]); |
||
FINISH;</ |
FINISH;</syntaxhighlight> |
||
=={{header|Klingphix}}== |
|||
<syntaxhighlight lang="text">:ack |
|||
%n !n %m !m |
|||
$m 0 == |
|||
( [$n 1 +] |
|||
[$n 0 == |
|||
( [$m 1 - 1 ack] |
|||
[$m 1 - $m $n 1 - ack ack] |
|||
) if |
|||
] |
|||
) if |
|||
; |
|||
3 6 ack print nl |
|||
msec print |
|||
" " input</syntaxhighlight> |
|||
=={{header|Klong}}== |
=={{header|Klong}}== |
||
<syntaxhighlight lang="k"> |
|||
<lang k> |
|||
ack::{:[0=x;y+1:|0=y;.f(x-1;1);.f(x-1;.f(x;y-1))]} |
ack::{:[0=x;y+1:|0=y;.f(x-1;1);.f(x-1;.f(x;y-1))]} |
||
ack(2;2)</ |
ack(2;2)</syntaxhighlight> |
||
=={{header|Kotlin}}== |
=={{header|Kotlin}}== |
||
<syntaxhighlight lang="scala"> |
|||
<lang scala>fun A(m: Long, n: Long): Long = when { |
|||
tailrec fun A(m: Long, n: Long): Long { |
|||
m > 0L |
require(m >= 0L) { "m must not be negative" } |
||
n |
require(n >= 0L) { "n must not be negative" } |
||
if (m == 0L) { |
|||
return n + 1L |
|||
else -> throw IllegalArgumentException("illegal n") |
|||
} |
} |
||
if (n == 0L) { |
|||
else -> throw IllegalArgumentException("illegal m") |
|||
return A(m - 1L, 1L) |
|||
} |
|||
return A(m - 1L, A(m, n - 1L)) |
|||
} |
} |
||
inline fun<T> tryOrNull(block: () -> T): T? = try { block() } catch (e: Throwable) { null } |
|||
fun main(args: Array<String>) { |
|||
val M: Long = 4 |
|||
const val N = 10L |
|||
const val M = 4L |
|||
for (m in 0..M) { |
|||
fun main() { |
|||
print("\nA($m, $r) =") |
|||
(0..M) |
|||
var able = true |
|||
.map { it to 0..N } |
|||
.map { (m, Ns) -> (m to Ns) to Ns.map { n -> tryOrNull { A(m, n) } } } |
|||
try { |
|||
.map { (input, output) -> "A(${input.first}, ${input.second})" to output.map { it?.toString() ?: "?" } } |
|||
if (able) { |
|||
.map { (input, output) -> "$input = $output" } |
|||
.forEach(::println) |
|||
} |
|||
} else |
|||
</syntaxhighlight> |
|||
print(" ?") |
|||
} catch(e: Throwable) { |
|||
print(" ?") |
|||
able = false |
|||
} |
|||
} |
|||
} |
|||
}</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
A(0, 0.. |
A(0, 0..10) = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] |
||
A(1, 0.. |
A(1, 0..10) = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] |
||
A(2, 0.. |
A(2, 0..10) = [3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23] |
||
A(3, 0.. |
A(3, 0..10) = [5, 13, 29, 61, 125, 253, 509, 1021, 2045, 4093, 8189] |
||
A(4, 0.. |
A(4, 0..10) = [13, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?] |
||
</pre> |
|||
=={{header|Lambdatalk}}== |
|||
<syntaxhighlight lang="scheme"> |
|||
{def ack |
|||
{lambda {:m :n} |
|||
{if {= :m 0} |
|||
then {+ :n 1} |
|||
else {if {= :n 0} |
|||
then {ack {- :m 1} 1} |
|||
else {ack {- :m 1} {ack :m {- :n 1}}}}}}} |
|||
-> ack |
|||
{S.map {ack 0} {S.serie 0 300000}} // 2090ms |
|||
{S.map {ack 1} {S.serie 0 500}} // 2038ms |
|||
{S.map {ack 2} {S.serie 0 70}} // 2100ms |
|||
{S.map {ack 3} {S.serie 0 6}} // 1800ms |
|||
{ack 2 700} // 8900ms |
|||
-> 1403 |
|||
{ack 3 7} // 6000ms |
|||
-> 1021 |
|||
{ack 4 1} // too much |
|||
-> ??? |
|||
</syntaxhighlight> |
|||
=={{header|Lasso}}== |
=={{header|Lasso}}== |
||
< |
<syntaxhighlight lang="lasso">#!/usr/bin/lasso9 |
||
define ackermann(m::integer, n::integer) => { |
define ackermann(m::integer, n::integer) => { |
||
Line 3,510: | Line 5,449: | ||
y in generateSeries(0,8,2) |
y in generateSeries(0,8,2) |
||
do stdoutnl(#x+', '#y+': ' + ackermann(#x, #y)) |
do stdoutnl(#x+', '#y+': ' + ackermann(#x, #y)) |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre>1, 0: 2 |
<pre>1, 0: 2 |
||
Line 3,529: | Line 5,468: | ||
=={{header|LFE}}== |
=={{header|LFE}}== |
||
< |
<syntaxhighlight lang="lisp">(defun ackermann |
||
((0 n) (+ n 1)) |
((0 n) (+ n 1)) |
||
((m 0) (ackermann (- m 1) 1)) |
((m 0) (ackermann (- m 1) 1)) |
||
((m n) (ackermann (- m 1) (ackermann m (- n 1)))))</ |
((m n) (ackermann (- m 1) (ackermann m (- n 1)))))</syntaxhighlight> |
||
=={{header|Liberty BASIC}}== |
=={{header|Liberty BASIC}}== |
||
< |
<syntaxhighlight lang="lb">Print Ackermann(1, 2) |
||
Function Ackermann(m, n) |
Function Ackermann(m, n) |
||
Line 3,548: | Line 5,487: | ||
Ackermann = Ackermann((m - 1), Ackermann(m, (n - 1))) |
Ackermann = Ackermann((m - 1), Ackermann(m, (n - 1))) |
||
End Select |
End Select |
||
End Function</ |
End Function</syntaxhighlight> |
||
=={{header|LiveCode}}== |
=={{header|LiveCode}}== |
||
< |
<syntaxhighlight lang="livecode">function ackermann m,n |
||
switch |
switch |
||
Case m = 0 |
Case m = 0 |
||
Line 3,560: | Line 5,499: | ||
return ackermann((m - 1), ackermann(m, (n - 1))) |
return ackermann((m - 1), ackermann(m, (n - 1))) |
||
end switch |
end switch |
||
end ackermann</ |
end ackermann</syntaxhighlight> |
||
=={{header|Logo}}== |
=={{header|Logo}}== |
||
< |
<syntaxhighlight lang="logo">to ack :i :j |
||
if :i = 0 [output :j+1] |
if :i = 0 [output :j+1] |
||
if :j = 0 [output ack :i-1 1] |
if :j = 0 [output ack :i-1 1] |
||
output ack :i-1 ack :i :j-1 |
output ack :i-1 ack :i :j-1 |
||
end</ |
end</syntaxhighlight> |
||
=={{header|Logtalk}}== |
=={{header|Logtalk}}== |
||
< |
<syntaxhighlight lang="logtalk">ack(0, N, V) :- |
||
!, |
!, |
||
V is N + 1. |
V is N + 1. |
||
Line 3,582: | Line 5,520: | ||
N2 is N - 1, |
N2 is N - 1, |
||
ack(M, N2, V2), |
ack(M, N2, V2), |
||
ack(M2, V2, V).</ |
ack(M2, V2, V).</syntaxhighlight> |
||
=={{header|LOLCODE}}== |
=={{header|LOLCODE}}== |
||
{{trans|C}} |
{{trans|C}} |
||
< |
<syntaxhighlight lang="lolcode">HAI 1.3 |
||
HOW IZ I ackermann YR m AN YR n |
HOW IZ I ackermann YR m AN YR n |
||
Line 3,607: | Line 5,545: | ||
IM OUTTA YR outer |
IM OUTTA YR outer |
||
KTHXBYE</ |
KTHXBYE</syntaxhighlight> |
||
=={{header|Lua}}== |
=={{header|Lua}}== |
||
< |
<syntaxhighlight lang="lua">function ack(M,N) |
||
if M == 0 then return N + 1 end |
if M == 0 then return N + 1 end |
||
if N == 0 then return ack(M-1,1) end |
if N == 0 then return ack(M-1,1) end |
||
return ack(M-1,ack(M, N-1)) |
return ack(M-1,ack(M, N-1)) |
||
end</ |
end</syntaxhighlight> |
||
=== Stackless iterative solution with multiple precision, fast === |
|||
<syntaxhighlight lang="lua"> |
|||
#!/usr/bin/env luajit |
|||
local gmp = require 'gmp' ('libgmp') |
|||
local mpz, z_mul, z_add, z_add_ui, z_set_d = |
|||
gmp.types.z, gmp.z_mul, gmp.z_add, gmp.z_add_ui, gmp.z_set_d |
|||
local z_cmp, z_cmp_ui, z_init_d, z_set= |
|||
gmp.z_cmp, gmp.z_cmp_ui, gmp.z_init_set_d, gmp.z_set |
|||
local printf = gmp.printf |
|||
local function ack(i,n) |
|||
local nxt=setmetatable({}, {__index=function(t,k) local z=mpz() z_init_d(z, 0) t[k]=z return z end}) |
|||
local goal=setmetatable({}, {__index=function(t,k) local o=mpz() z_init_d(o, 1) t[k]=o return o end}) |
|||
goal[i]=mpz() z_init_d(goal[i], -1) |
|||
local v=mpz() z_init_d(v, 0) |
|||
local ic |
|||
local END=n+1 |
|||
local ntmp,gtmp |
|||
repeat |
|||
ic=0 |
|||
ntmp,gtmp=nxt[ic], goal[ic] |
|||
z_add_ui(v, ntmp, 1) |
|||
while z_cmp(ntmp, gtmp) == 0 do |
|||
z_set(gtmp,v) |
|||
z_add_ui(ntmp, ntmp, 1) |
|||
nxt[ic], goal[ic]=ntmp, gtmp |
|||
ic=ic+1 |
|||
ntmp,gtmp=nxt[ic], goal[ic] |
|||
end |
|||
z_add_ui(ntmp, ntmp, 1) |
|||
nxt[ic]=ntmp |
|||
until z_cmp_ui(nxt[i], END) == 0 |
|||
return v |
|||
end |
|||
if #arg<1 then |
|||
print("Ackermann: "..arg[0].." <num1> [num2]") |
|||
else |
|||
printf("%Zd\n", ack(tonumber(arg[1]), arg[2] and tonumber(arg[2]) or 0)) |
|||
end |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
> time ./ackermann_iter.lua 4 1 |
|||
65533 |
|||
./ackermann_iter.lua 4 1 0,01s user 0,01s system 95% cpu 0,015 total // AMD FX-8350@4 GHz |
|||
> time ./ackermann.lua 3 10 ⏎ |
|||
8189 |
|||
./ackermann.lua 3 10 0,22s user 0,00s system 98% cpu 0,222 total // recursive solution |
|||
> time ./ackermann_iter.lua 3 10 |
|||
8189 |
|||
./ackermann_iter.lua 3 10 0,00s user 0,00s system 92% cpu 0,009 total |
|||
</pre> |
|||
=={{header|Lucid}}== |
=={{header|Lucid}}== |
||
< |
<syntaxhighlight lang="lucid">ack(m,n) |
||
where |
where |
||
ack(m,n) = if m eq 0 then n+1 |
ack(m,n) = if m eq 0 then n+1 |
||
Line 3,623: | Line 5,616: | ||
else ack(m-1, ack(m, n-1)) fi |
else ack(m-1, ack(m, n-1)) fi |
||
fi; |
fi; |
||
end</ |
end</syntaxhighlight> |
||
=={{header|Luck}}== |
=={{header|Luck}}== |
||
< |
<syntaxhighlight lang="luck">function ackermann(m: int, n: int): int = ( |
||
if m==0 then n+1 |
if m==0 then n+1 |
||
else if n==0 then ackermann(m-1,1) |
else if n==0 then ackermann(m-1,1) |
||
else ackermann(m-1,ackermann(m,n-1)) |
else ackermann(m-1,ackermann(m,n-1)) |
||
)</ |
)</syntaxhighlight> |
||
=={{header|M2000 Interpreter}}== |
=={{header|M2000 Interpreter}}== |
||
<syntaxhighlight lang="m2000 interpreter"> |
|||
<lang M2000 Interpreter> |
|||
Module Checkit { |
Module Checkit { |
||
Def ackermann(m,n) =If(m=0-> n+1, If(n=0-> ackermann(m-1,1), ackermann(m-1,ackermann(m,n-1)))) |
Def ackermann(m,n) =If(m=0-> n+1, If(n=0-> ackermann(m-1,1), ackermann(m-1,ackermann(m,n-1)))) |
||
Line 3,649: | Line 5,641: | ||
} |
} |
||
Checkit |
Checkit |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|M4}}== |
=={{header|M4}}== |
||
< |
<syntaxhighlight lang="m4">define(`ack',`ifelse($1,0,`incr($2)',`ifelse($2,0,`ack(decr($1),1)',`ack(decr($1),ack($1,decr($2)))')')')dnl |
||
ack(3,3)</ |
ack(3,3)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>61 </pre> |
<pre>61 </pre> |
||
=={{header|MACRO-11}}== |
|||
<syntaxhighlight lang="macro11"> .TITLE ACKRMN |
|||
.MCALL .TTYOUT,.EXIT |
|||
ACKRMN::JMP MKTBL |
|||
; R0 = ACK(R0,R1) |
|||
ACK: MOV SP,R2 ; KEEP OLD STACK PTR |
|||
MOV #ASTK,SP ; USE PRIVATE STACK |
|||
JSR PC,1$ |
|||
MOV R2,SP ; RESTORE STACK PTR |
|||
RTS PC |
|||
1$: TST R0 |
|||
BNE 2$ |
|||
INC R1 |
|||
MOV R1,R0 |
|||
RTS PC |
|||
2$: TST R1 |
|||
BNE 3$ |
|||
DEC R0 |
|||
INC R1 |
|||
BR 1$ |
|||
3$: MOV R0,-(SP) |
|||
DEC R1 |
|||
JSR PC,1$ |
|||
MOV R0,R1 |
|||
MOV (SP)+,R0 |
|||
DEC R0 |
|||
BR 1$ |
|||
.BLKB 4000 ; BIG STACK |
|||
ASTK = . |
|||
; PRINT TABLE |
|||
MMAX = 4 |
|||
NMAX = 7 |
|||
MKTBL: CLR R3 |
|||
1$: CLR R4 |
|||
2$: MOV R3,R0 |
|||
MOV R4,R1 |
|||
JSR PC,ACK |
|||
JSR PC,PR0 |
|||
INC R4 |
|||
CMP R4,#NMAX |
|||
BLT 2$ |
|||
MOV #15,R0 |
|||
.TTYOUT |
|||
MOV #12,R0 |
|||
.TTYOUT |
|||
INC R3 |
|||
CMP R3,#MMAX |
|||
BLT 1$ |
|||
.EXIT |
|||
; PRINT NUMBER IN R0 AS DECIMAL |
|||
PR0: MOV #4$,R1 |
|||
1$: MOV #-1,R2 |
|||
2$: INC R2 |
|||
SUB #12,R0 |
|||
BCC 2$ |
|||
ADD #72,R0 |
|||
MOVB R0,-(R1) |
|||
MOV R2,R0 |
|||
BNE 1$ |
|||
3$: MOVB (R1)+,R0 |
|||
.TTYOUT |
|||
BNE 3$ |
|||
RTS PC |
|||
.ASCII /...../ |
|||
4$: .BYTE 11,0 |
|||
.END ACKRMN</syntaxhighlight> |
|||
{{out}} |
|||
<pre>1 2 3 4 5 6 7 |
|||
2 3 4 5 6 7 8 |
|||
3 5 7 9 11 13 15 |
|||
5 13 29 61 125 253 509</pre> |
|||
=={{header|MAD}}== |
|||
While MAD supports function calls, it does not handle recursion automatically. |
|||
There is support for a stack, but the programmer has to set it up himself (by defining an array to reserve memory, |
|||
then making it the stack using the <code>SET LIST</code>) command. |
|||
Values have to be pushed and popped from it by hand (using <code>SAVE</code> and <code>RESTORE</code>), and for |
|||
a function to be reentrant, even the return address has to be kept. |
|||
On top of this, all variables are global throughout the program (there is no scope), and argument passing is |
|||
done by reference, meaning that even once the stack is set up, arguments cannot be passed in the normal way. |
|||
To define a function that takes arguments, one would have to declare a helper function that then passes |
|||
the arguments to the recursive function via the stack or the global variables. The following program demonstrates this. |
|||
<syntaxhighlight lang="mad"> NORMAL MODE IS INTEGER |
|||
DIMENSION LIST(3000) |
|||
SET LIST TO LIST |
|||
INTERNAL FUNCTION(DUMMY) |
|||
ENTRY TO ACKH. |
|||
LOOP WHENEVER M.E.0 |
|||
FUNCTION RETURN N+1 |
|||
OR WHENEVER N.E.0 |
|||
M=M-1 |
|||
N=1 |
|||
TRANSFER TO LOOP |
|||
OTHERWISE |
|||
SAVE RETURN |
|||
SAVE DATA M |
|||
N=N-1 |
|||
N=ACKH.(0) |
|||
RESTORE DATA M |
|||
RESTORE RETURN |
|||
M=M-1 |
|||
TRANSFER TO LOOP |
|||
END OF CONDITIONAL |
|||
ERROR RETURN |
|||
END OF FUNCTION |
|||
INTERNAL FUNCTION(MM,NN) |
|||
ENTRY TO ACK. |
|||
M=MM |
|||
N=NN |
|||
FUNCTION RETURN ACKH.(0) |
|||
END OF FUNCTION |
|||
THROUGH SHOW, FOR I=0, 1, I.G.3 |
|||
THROUGH SHOW, FOR J=0, 1, J.G.8 |
|||
SHOW PRINT FORMAT ACKF,I,J,ACK.(I,J) |
|||
VECTOR VALUES ACKF = $4HACK(,I1,1H,,I1,4H) = ,I4*$ |
|||
END OF PROGRAM |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre style='height: 50ex;'>ACK(0,0) = 1 |
|||
ACK(0,1) = 2 |
|||
ACK(0,2) = 3 |
|||
ACK(0,3) = 4 |
|||
ACK(0,4) = 5 |
|||
ACK(0,5) = 6 |
|||
ACK(0,6) = 7 |
|||
ACK(0,7) = 8 |
|||
ACK(0,8) = 9 |
|||
ACK(1,0) = 2 |
|||
ACK(1,1) = 3 |
|||
ACK(1,2) = 4 |
|||
ACK(1,3) = 5 |
|||
ACK(1,4) = 6 |
|||
ACK(1,5) = 7 |
|||
ACK(1,6) = 8 |
|||
ACK(1,7) = 9 |
|||
ACK(1,8) = 10 |
|||
ACK(2,0) = 3 |
|||
ACK(2,1) = 5 |
|||
ACK(2,2) = 7 |
|||
ACK(2,3) = 9 |
|||
ACK(2,4) = 11 |
|||
ACK(2,5) = 13 |
|||
ACK(2,6) = 15 |
|||
ACK(2,7) = 17 |
|||
ACK(2,8) = 19 |
|||
ACK(3,0) = 5 |
|||
ACK(3,1) = 13 |
|||
ACK(3,2) = 29 |
|||
ACK(3,3) = 61 |
|||
ACK(3,4) = 125 |
|||
ACK(3,5) = 253 |
|||
ACK(3,6) = 509 |
|||
ACK(3,7) = 1021 |
|||
ACK(3,8) = 2045</pre> |
|||
=={{header|Maple}}== |
=={{header|Maple}}== |
||
Strictly by the definition given above, we can code this as follows. |
Strictly by the definition given above, we can code this as follows. |
||
<syntaxhighlight lang="maple"> |
|||
<lang Maple> |
|||
Ackermann := proc( m :: nonnegint, n :: nonnegint ) |
Ackermann := proc( m :: nonnegint, n :: nonnegint ) |
||
option remember; # optional automatic memoization |
option remember; # optional automatic memoization |
||
Line 3,670: | Line 5,829: | ||
end if |
end if |
||
end proc: |
end proc: |
||
</syntaxhighlight> |
|||
</lang> |
|||
In Maple, the keyword <lang |
In Maple, the keyword <syntaxhighlight lang="maple">thisproc</syntaxhighlight> refers to the currently executing procedure (closure) and is used when writing recursive procedures. (You could also use the name of the procedure, Ackermann in this case, but then a concurrently executing task or thread could re-assign that name while the recursive procedure is executing, resulting in an incorrect result.) |
||
To make this faster, you can use known expansions for small values of <math>m</math>. (See [[wp:Ackermann_function|Wikipedia:Ackermann function]]) |
To make this faster, you can use known expansions for small values of <math>m</math>. (See [[wp:Ackermann_function|Wikipedia:Ackermann function]]) |
||
<syntaxhighlight lang="maple"> |
|||
<lang Maple> |
|||
Ackermann := proc( m :: nonnegint, n :: nonnegint ) |
Ackermann := proc( m :: nonnegint, n :: nonnegint ) |
||
option remember; # optional automatic memoization |
option remember; # optional automatic memoization |
||
Line 3,691: | Line 5,850: | ||
end if |
end if |
||
end proc: |
end proc: |
||
</syntaxhighlight> |
|||
</lang> |
|||
This makes it possible to compute <code>Ackermann( 4, 1 )</code> and <code>Ackermann( 4, 2 )</code> essentially instantly, though <code>Ackermann( 4, 3 )</code> is still out of reach. |
This makes it possible to compute <code>Ackermann( 4, 1 )</code> and <code>Ackermann( 4, 2 )</code> essentially instantly, though <code>Ackermann( 4, 3 )</code> is still out of reach. |
||
To compute Ackermann( 1, i ) for i from 1 to 10 use |
To compute Ackermann( 1, i ) for i from 1 to 10 use |
||
<syntaxhighlight lang="maple"> |
|||
<lang Maple> |
|||
> map2( Ackermann, 1, [seq]( 1 .. 10 ) ); |
> map2( Ackermann, 1, [seq]( 1 .. 10 ) ); |
||
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12] |
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12] |
||
</syntaxhighlight> |
|||
</lang> |
|||
To get the first 10 values for m = 2 use |
To get the first 10 values for m = 2 use |
||
<syntaxhighlight lang="maple"> |
|||
<lang Maple> |
|||
> map2( Ackermann, 2, [seq]( 1 .. 10 ) ); |
> map2( Ackermann, 2, [seq]( 1 .. 10 ) ); |
||
[5, 7, 9, 11, 13, 15, 17, 19, 21, 23] |
[5, 7, 9, 11, 13, 15, 17, 19, 21, 23] |
||
</syntaxhighlight> |
|||
</lang> |
|||
For Ackermann( 4, 2 ) we get a very long number with |
For Ackermann( 4, 2 ) we get a very long number with |
||
<syntaxhighlight lang="maple"> |
|||
<lang Maple> |
|||
> length( Ackermann( 4, 2 ) ); |
> length( Ackermann( 4, 2 ) ); |
||
19729 |
19729 |
||
</syntaxhighlight> |
|||
</lang> |
|||
digits. |
digits. |
||
=={{header|Mathcad}}== |
|||
Mathcad is a non-text-based programming environment. The equation below is an approximation of the way that it is entered (and) displayed on a Mathcad worksheet. The worksheet is available at https://community.ptc.com/t5/PTC-Mathcad/Rosetta-Code-Ackermann-Function/m-p/750117#M197410 |
|||
This particular version of Ackermann's function was created in Mathcad Prime Express 7.0, a free version of Mathcad Prime 7.0 with restrictions (such as no programming or symbolics). All Prime Express numbers are complex. There is a recursion depth limit of about 4,500. |
|||
<syntaxhighlight lang="mathcad">A(m,n):=if(m=0,n+1,if(n=0,A(m-1,1),A(m-1,A(m,n-1))))</syntaxhighlight> |
|||
The worksheet also contains an explictly-calculated version of Ackermann's function that calls the tetration function n<sub>a</sub>. |
|||
n<sub>a</sub>(a,n):=if(n=0,1,a<sup>n<sub>a</sub>(a,n-1))</sup> |
|||
a<sub>error</sub>(m,n):=error(format("cannot compute a({0},{1})",m,n)) |
|||
a(m,n):=if(m=0,n+1,if(m=1,n+2,if(m=2,2n+3,if(m=3,2^(n+3)-3,a<sub>error</sub>(m,n))))) |
|||
a(m,n):=if(m=4,n<sub>a</sub>(2,n+3)-3,a(m,n) |
|||
=={{header|Mathematica}} / {{header|Wolfram Language}}== |
=={{header|Mathematica}} / {{header|Wolfram Language}}== |
||
Two possible implementations would be: |
Two possible implementations would be: |
||
< |
<syntaxhighlight lang="mathematica">$RecursionLimit=Infinity |
||
Ackermann1[m_,n_]:= |
Ackermann1[m_,n_]:= |
||
If[m==0,n+1, |
If[m==0,n+1, |
||
Line 3,723: | Line 5,900: | ||
Ackermann2[0,n_]:=n+1; |
Ackermann2[0,n_]:=n+1; |
||
Ackermann2[m_,0]:=Ackermann1[m-1,1]; |
Ackermann2[m_,0]:=Ackermann1[m-1,1]; |
||
Ackermann2[m_,n_]:=Ackermann1[m-1,Ackermann1[m,n-1]]</ |
Ackermann2[m_,n_]:=Ackermann1[m-1,Ackermann1[m,n-1]]</syntaxhighlight> |
||
Note that the second implementation is quite a bit faster, as doing 'if' comparisons is slower than the built-in pattern matching algorithms. |
Note that the second implementation is quite a bit faster, as doing 'if' comparisons is slower than the built-in pattern matching algorithms. |
||
Examples: |
Examples: |
||
< |
<syntaxhighlight lang="mathematica">Flatten[#,1]&@Table[{"Ackermann2["<>ToString[i]<>","<>ToString[j]<>"] =",Ackermann2[i,j]},{i,3},{j,8}]//Grid</syntaxhighlight> |
||
gives back: |
gives back: |
||
< |
<syntaxhighlight lang="mathematica">Ackermann2[1,1] = 3 |
||
Ackermann2[1,2] = 4 |
Ackermann2[1,2] = 4 |
||
Ackermann2[1,3] = 5 |
Ackermann2[1,3] = 5 |
||
Line 3,751: | Line 5,928: | ||
Ackermann2[3,6] = 509 |
Ackermann2[3,6] = 509 |
||
Ackermann2[3,7] = 1021 |
Ackermann2[3,7] = 1021 |
||
Ackermann2[3,8] = 2045</ |
Ackermann2[3,8] = 2045</syntaxhighlight> |
||
If we would like to calculate Ackermann[4,1] or Ackermann[4,2] we have to optimize a little bit: |
If we would like to calculate Ackermann[4,1] or Ackermann[4,2] we have to optimize a little bit: |
||
< |
<syntaxhighlight lang="mathematica">Clear[Ackermann3] |
||
$RecursionLimit=Infinity; |
$RecursionLimit=Infinity; |
||
Ackermann3[0,n_]:=n+1; |
Ackermann3[0,n_]:=n+1; |
||
Line 3,760: | Line 5,937: | ||
Ackermann3[3,n_]:=5+8 (2^n-1); |
Ackermann3[3,n_]:=5+8 (2^n-1); |
||
Ackermann3[m_,0]:=Ackermann3[m-1,1]; |
Ackermann3[m_,0]:=Ackermann3[m-1,1]; |
||
Ackermann3[m_,n_]:=Ackermann3[m-1,Ackermann3[m,n-1]]</ |
Ackermann3[m_,n_]:=Ackermann3[m-1,Ackermann3[m,n-1]]</syntaxhighlight> |
||
Now computing Ackermann[4,1] and Ackermann[4,2] can be done quickly (<0.01 sec): |
Now computing Ackermann[4,1] and Ackermann[4,2] can be done quickly (<0.01 sec): |
||
Examples 2: |
Examples 2: |
||
< |
<syntaxhighlight lang="mathematica">Ackermann3[4, 1] |
||
Ackermann3[4, 2]</ |
Ackermann3[4, 2]</syntaxhighlight> |
||
gives back: |
gives back: |
||
<div style="width:full;overflow:scroll">< |
<div style="width:full;overflow:scroll"><syntaxhighlight lang="mathematica">65533 |
||
2003529930406846464979072351560255750447825475569751419265016973710894059556311453089506130880........699146577530041384717124577965048175856395072895337539755822087777506072339445587895905719156733</ |
2003529930406846464979072351560255750447825475569751419265016973710894059556311453089506130880........699146577530041384717124577965048175856395072895337539755822087777506072339445587895905719156733</syntaxhighlight></div> |
||
Ackermann[4,2] has 19729 digits, several thousands of digits omitted in the result above for obvious reasons. Ackermann[5,0] can be computed also quite fast, and is equal to 65533. |
Ackermann[4,2] has 19729 digits, several thousands of digits omitted in the result above for obvious reasons. Ackermann[5,0] can be computed also quite fast, and is equal to 65533. |
||
Summarizing Ackermann[0,n_], Ackermann[1,n_], Ackermann[2,n_], and Ackermann[3,n_] can all be calculated for n>>1000. Ackermann[4,0], Ackermann[4,1], Ackermann[4,2] and Ackermann[5,0] are only possible now. Maybe in the future we can calculate higher Ackermann numbers efficiently and fast. Although showing the results will always be a problem. |
Summarizing Ackermann[0,n_], Ackermann[1,n_], Ackermann[2,n_], and Ackermann[3,n_] can all be calculated for n>>1000. Ackermann[4,0], Ackermann[4,1], Ackermann[4,2] and Ackermann[5,0] are only possible now. Maybe in the future we can calculate higher Ackermann numbers efficiently and fast. Although showing the results will always be a problem. |
||
=={{header|MATLAB}}== |
=={{header|MATLAB}}== |
||
< |
<syntaxhighlight lang="matlab">function A = ackermannFunction(m,n) |
||
if m == 0 |
if m == 0 |
||
A = n+1; |
A = n+1; |
||
Line 3,780: | Line 5,957: | ||
A = ackermannFunction( m-1,ackermannFunction(m,n-1) ); |
A = ackermannFunction( m-1,ackermannFunction(m,n-1) ); |
||
end |
end |
||
end</ |
end</syntaxhighlight> |
||
=={{header|Maxima}}== |
=={{header|Maxima}}== |
||
< |
<syntaxhighlight lang="maxima">ackermann(m, n) := if integerp(m) and integerp(n) then ackermann[m, n] else 'ackermann(m, n)$ |
||
ackermann[m, n] := if m = 0 then n + 1 |
ackermann[m, n] := if m = 0 then n + 1 |
||
Line 3,797: | Line 5,974: | ||
ackermann(4, n) - (tetration(2, n + 3) - 3); |
ackermann(4, n) - (tetration(2, n + 3) - 3); |
||
subst(n = 2, %); |
subst(n = 2, %); |
||
ev(%, nouns);</ |
ev(%, nouns);</syntaxhighlight> |
||
=={{header|MAXScript}}== |
=={{header|MAXScript}}== |
||
Use with caution. Will cause a stack overflow for m > 3. |
Use with caution. Will cause a stack overflow for m > 3. |
||
< |
<syntaxhighlight lang="maxscript">fn ackermann m n = |
||
( |
( |
||
if m == 0 then |
if m == 0 then |
||
Line 3,815: | Line 5,992: | ||
ackermann (m-1) (ackermann m (n-1)) |
ackermann (m-1) (ackermann m (n-1)) |
||
) |
) |
||
)</ |
)</syntaxhighlight> |
||
=={{header| |
=={{header|Mercury}}== |
||
This is the Ackermann function with some (obvious) elements elided. The <code>ack/3</code> predicate is implemented in terms of the <code>ack/2</code> function. The <code>ack/2</code> function is implemented in terms of the <code>ack/3</code> predicate. This makes the code both more concise and easier to follow than would otherwise be the case. The <code>integer</code> type is used instead of <code>int</code> because the problem statement stipulates the use of bignum integers if possible. |
|||
<lang>П1 <-> П0 ПП 06 С/П ИП0 x=0 13 ИП1 |
|||
<syntaxhighlight lang="mercury">:- func ack(integer, integer) = integer. |
|||
1 + В/О ИП1 x=0 24 ИП0 1 П1 - |
|||
ack(M, N) = R :- ack(M, N, R). |
|||
П0 ПП 06 В/О ИП0 П2 ИП1 1 - П1 |
|||
ПП 06 П1 ИП2 1 - П0 ПП 06 В/О</lang> |
|||
:- pred ack(integer::in, integer::in, integer::out) is det. |
|||
=={{header|mLite}}== |
|||
ack(M, N, R) :- |
|||
<lang haskell>fun ackermann( 0, n ) = n + 1 |
|||
( ( M < integer(0) |
|||
| ( m, 0 ) = ackermann( m - 1, 1 ) |
|||
; N < integer(0) ) -> throw(bounds_error) |
|||
| ( m, n ) = ackermann( m - 1, ackermann(m, n - 1) )</lang> |
|||
; M = integer(0) -> R = N + integer(1) |
|||
Test code providing tuples from (0,0) to (3,8) |
|||
; N = integer(0) -> ack(M - integer(1), integer(1), R) |
|||
<lang haskell>fun jota x = map (fn x = x-1) ` iota x |
|||
; ack(M - integer(1), ack(M, N - integer(1)), R) ).</syntaxhighlight> |
|||
=={{header|min}}== |
|||
fun test_tuples (x, y) = append_map (fn a = map (fn b = (b, a)) ` jota x) ` jota y |
|||
{{works with|min|0.19.3}} |
|||
<syntaxhighlight lang="min">( |
|||
:n :m |
|||
( |
|||
((m 0 ==) (n 1 +)) |
|||
((n 0 ==) (m 1 - 1 ackermann)) |
|||
((true) (m 1 - m n 1 - ackermann ackermann)) |
|||
) case |
|||
) :ackermann</syntaxhighlight> |
|||
=={{header|MiniScript}}== |
|||
map ackermann (test_tuples(4,9))</lang> |
|||
Result |
|||
<syntaxhighlight lang="miniscript">ackermann = function(m, n) |
|||
<pre>[1, 2, 3, 5, 2, 3, 5, 13, 3, 4, 7, 29, 4, 5, 9, 61, 5, 6, 11, 125, 6, 7, 13, 253, 7, 8, 15, 509, 8, 9, 17, 1021, 9, 10, 19, 2045]</pre> |
|||
if m == 0 then return n+1 |
|||
if n == 0 then return ackermann(m - 1, 1) |
|||
return ackermann(m - 1, ackermann(m, n - 1)) |
|||
end function |
|||
for m in range(0, 3) |
|||
for n in range(0, 4) |
|||
print "(" + m + ", " + n + "): " + ackermann(m, n) |
|||
end for |
|||
end for</syntaxhighlight> |
|||
=={{header|МК-61/52}}== |
|||
<syntaxhighlight lang="text">П1 <-> П0 ПП 06 С/П ИП0 x=0 13 ИП1 |
|||
1 + В/О ИП1 x=0 24 ИП0 1 П1 - |
|||
П0 ПП 06 В/О ИП0 П2 ИП1 1 - П1 |
|||
ПП 06 П1 ИП2 1 - П0 ПП 06 В/О</syntaxhighlight> |
|||
=={{header|ML/I}}== |
=={{header|ML/I}}== |
||
ML/I loves recursion, but runs out of its default amount of storage with larger numbers than those tested here! |
ML/I loves recursion, but runs out of its default amount of storage with larger numbers than those tested here! |
||
===Program=== |
===Program=== |
||
< |
<syntaxhighlight lang="ml/i">MCSKIP "WITH" NL |
||
"" Ackermann function |
"" Ackermann function |
||
"" Will overflow when it reaches implementation-defined signed integer limit |
"" Will overflow when it reaches implementation-defined signed integer limit |
||
Line 3,871: | Line 6,073: | ||
a(3,1) => ACK(3,1) |
a(3,1) => ACK(3,1) |
||
a(3,2) => ACK(3,2) |
a(3,2) => ACK(3,2) |
||
a(4,0) => ACK(4,0)</ |
a(4,0) => ACK(4,0)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
< |
<syntaxhighlight lang="ml/i">a(0,0) => 1 |
||
a(0,1) => 2 |
a(0,1) => 2 |
||
a(0,2) => 3 |
a(0,2) => 3 |
||
Line 3,891: | Line 6,093: | ||
a(3,1) => 13 |
a(3,1) => 13 |
||
a(3,2) => 29 |
a(3,2) => 29 |
||
a(4,0) => 13</ |
a(4,0) => 13</syntaxhighlight> |
||
=={{header| |
=={{header|mLite}}== |
||
<syntaxhighlight lang="haskell">fun ackermann( 0, n ) = n + 1 |
|||
This is the Ackermann function with some (obvious) elements elided. The <code>ack/3</code> predicate is implemented in terms of the <code>ack/2</code> function. The <code>ack/2</code> function is implemented in terms of the <code>ack/3</code> predicate. This makes the code both more concise and easier to follow than would otherwise be the case. The <code>integer</code> type is used instead of <code>int</code> because the problem statement stipulates the use of bignum integers if possible. |
|||
| ( m, 0 ) = ackermann( m - 1, 1 ) |
|||
<lang mercury>:- func ack(integer, integer) = integer. |
|||
| ( m, n ) = ackermann( m - 1, ackermann(m, n - 1) )</syntaxhighlight> |
|||
ack(M, N) = R :- ack(M, N, R). |
|||
Test code providing tuples from (0,0) to (3,8) |
|||
<syntaxhighlight lang="haskell">fun jota x = map (fn x = x-1) ` iota x |
|||
fun test_tuples (x, y) = append_map (fn a = map (fn b = (b, a)) ` jota x) ` jota y |
|||
:- pred ack(integer::in, integer::in, integer::out) is det. |
|||
ack(M, N, R) :- |
|||
map ackermann (test_tuples(4,9))</syntaxhighlight> |
|||
( ( M < integer(0) |
|||
Result |
|||
; N < integer(0) ) -> throw(bounds_error) |
|||
<pre>[1, 2, 3, 5, 2, 3, 5, 13, 3, 4, 7, 29, 4, 5, 9, 61, 5, 6, 11, 125, 6, 7, 13, 253, 7, 8, 15, 509, 8, 9, 17, 1021, 9, 10, 19, 2045]</pre> |
|||
; M = integer(0) -> R = N + integer(1) |
|||
; N = integer(0) -> ack(M - integer(1), integer(1), R) |
|||
; ack(M - integer(1), ack(M, N - integer(1)), R) ).</lang> |
|||
=={{header|Modula-2}}== |
=={{header|Modula-2}}== |
||
< |
<syntaxhighlight lang="modula2">MODULE ackerman; |
||
IMPORT ASCII, NumConv, InOut; |
IMPORT ASCII, NumConv, InOut; |
||
Line 3,939: | Line 6,141: | ||
END; |
END; |
||
InOut.WriteLn |
InOut.WriteLn |
||
END ackerman.</ |
END ackerman.</syntaxhighlight> |
||
{{out}}<pre>jan@Beryllium:~/modula/rosetta$ ackerman |
{{out}}<pre>jan@Beryllium:~/modula/rosetta$ ackerman |
||
1 2 3 4 5 6 7 |
1 2 3 4 5 6 7 |
||
Line 3,948: | Line 6,150: | ||
=={{header|Modula-3}}== |
=={{header|Modula-3}}== |
||
The type CARDINAL is defined in Modula-3 as [0..LAST(INTEGER)], in other words, it can hold all positive integers. |
The type CARDINAL is defined in Modula-3 as [0..LAST(INTEGER)], in other words, it can hold all positive integers. |
||
< |
<syntaxhighlight lang="modula3">MODULE Ack EXPORTS Main; |
||
FROM IO IMPORT Put; |
FROM IO IMPORT Put; |
||
Line 3,971: | Line 6,173: | ||
Put("\n"); |
Put("\n"); |
||
END; |
END; |
||
END Ack.</ |
END Ack.</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>1 2 3 4 5 6 7 |
<pre>1 2 3 4 5 6 7 |
||
Line 3,979: | Line 6,181: | ||
=={{header|MUMPS}}== |
=={{header|MUMPS}}== |
||
< |
<syntaxhighlight lang="mumps">Ackermann(m,n) ; |
||
If m=0 Quit n+1 |
If m=0 Quit n+1 |
||
If m>0,n=0 Quit $$Ackermann(m-1,1) |
If m>0,n=0 Quit $$Ackermann(m-1,1) |
||
Line 3,987: | Line 6,189: | ||
Write $$Ackermann(1,8) ; 10 |
Write $$Ackermann(1,8) ; 10 |
||
Write $$Ackermann(2,8) ; 19 |
Write $$Ackermann(2,8) ; 19 |
||
Write $$Ackermann(3,5) ; 253</ |
Write $$Ackermann(3,5) ; 253</syntaxhighlight> |
||
=={{header|Neko}}== |
|||
<syntaxhighlight lang="actionscript">/** |
|||
Ackermann recursion, in Neko |
|||
Tectonics: |
|||
nekoc ackermann.neko |
|||
neko ackermann 4 0 |
|||
*/ |
|||
ack = function(x,y) { |
|||
if (x == 0) return y+1; |
|||
if (y == 0) return ack(x-1,1); |
|||
return ack(x-1, ack(x,y-1)); |
|||
}; |
|||
var arg1 = $int($loader.args[0]); |
|||
var arg2 = $int($loader.args[1]); |
|||
/* If not given, or negative, default to Ackermann(3,4) */ |
|||
if (arg1 == null || arg1 < 0) arg1 = 3; |
|||
if (arg2 == null || arg2 < 0) arg2 = 4; |
|||
try |
|||
$print("Ackermann(", arg1, ",", arg2, "): ", ack(arg1,arg2), "\n") |
|||
catch problem |
|||
$print("Ackermann(", arg1, ",", arg2, "): ", problem, "\n")</syntaxhighlight> |
|||
{{out}} |
|||
<pre>prompt$ nekoc ackermann.neko |
|||
prompt$ neko ackermann.n 3 4 |
|||
Ackermann(3,4): 125 |
|||
prompt$ time neko ackermann.n 4 1 |
|||
Ackermann(4,1): Stack Overflow |
|||
real 0m31.475s |
|||
user 0m31.460s |
|||
sys 0m0.012s |
|||
prompt$ time neko ackermann 3 10 |
|||
Ackermann(3,10): 8189 |
|||
real 0m1.865s |
|||
user 0m1.862s |
|||
sys 0m0.004s</pre> |
|||
=={{header|Nemerle}}== |
=={{header|Nemerle}}== |
||
In Nemerle, we can state the Ackermann function as a lambda. By using pattern-matching, our definition strongly resembles the mathematical notation. |
In Nemerle, we can state the Ackermann function as a lambda. By using pattern-matching, our definition strongly resembles the mathematical notation. |
||
<syntaxhighlight lang="nemerle"> |
|||
<lang Nemerle> |
|||
using System; |
using System; |
||
using Nemerle.IO; |
using Nemerle.IO; |
||
Line 4,012: | Line 6,258: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
A terser version using implicit <code>match</code> (which doesn't use the alias <code>A</code> internally): |
A terser version using implicit <code>match</code> (which doesn't use the alias <code>A</code> internally): |
||
<syntaxhighlight lang="nemerle"> |
|||
<lang Nemerle> |
|||
def ackermann(m, n) { |
def ackermann(m, n) { |
||
| (0, n) => n + 1 |
| (0, n) => n + 1 |
||
Line 4,021: | Line 6,267: | ||
| _ => throw Exception("invalid inputs"); |
| _ => throw Exception("invalid inputs"); |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
Or, if we were set on using the <code>A</code> notation, we could do this: |
Or, if we were set on using the <code>A</code> notation, we could do this: |
||
<syntaxhighlight lang="nemerle"> |
|||
<lang Nemerle> |
|||
def ackermann = { |
def ackermann = { |
||
def A(m, n) { |
def A(m, n) { |
||
Line 4,033: | Line 6,279: | ||
A |
A |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|NetRexx}}== |
=={{header|NetRexx}}== |
||
< |
<syntaxhighlight lang="netrexx">/* NetRexx */ |
||
options replace format comments java crossref symbols binary |
options replace format comments java crossref symbols binary |
||
Line 4,060: | Line 6,306: | ||
end |
end |
||
return rval |
return rval |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|NewLISP}}== |
=={{header|NewLISP}}== |
||
< |
<syntaxhighlight lang="newlisp"> |
||
#! /usr/local/bin/newlisp |
#! /usr/local/bin/newlisp |
||
Line 4,070: | Line 6,316: | ||
((zero? n) (ackermann (dec m) 1)) |
((zero? n) (ackermann (dec m) 1)) |
||
(true (ackermann (- m 1) (ackermann m (dec n)))))) |
(true (ackermann (- m 1) (ackermann m (dec n)))))) |
||
</syntaxhighlight> |
|||
</lang> |
|||
<pre> |
<pre> |
||
Line 4,079: | Line 6,325: | ||
=={{header|Nim}}== |
=={{header|Nim}}== |
||
< |
<syntaxhighlight lang="nim">from strutils import parseInt |
||
proc ackermann(m, n: int64): int64 = |
proc ackermann(m, n: int64): int64 = |
||
Line 4,104: | Line 6,350: | ||
let second = getNumber() |
let second = getNumber() |
||
echo "Result: ", $ackermann(first, second) |
echo "Result: ", $ackermann(first, second) |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Nit}}== |
=={{header|Nit}}== |
||
Line 4,110: | Line 6,356: | ||
Source: [https://github.com/nitlang/nit/blob/master/examples/rosettacode/ackermann_function.nit the official Nit’s repository]. |
Source: [https://github.com/nitlang/nit/blob/master/examples/rosettacode/ackermann_function.nit the official Nit’s repository]. |
||
< |
<syntaxhighlight lang="nit"># Task: Ackermann function |
||
# |
# |
||
# A simple straightforward recursive implementation. |
# A simple straightforward recursive implementation. |
||
Line 4,127: | Line 6,373: | ||
end |
end |
||
print "" |
print "" |
||
end</ |
end</syntaxhighlight> |
||
Output: |
Output: |
||
Line 4,164: | Line 6,410: | ||
</pre> |
</pre> |
||
=={{header|Oberon-2}}== |
|||
<syntaxhighlight lang="oberon2">MODULE ackerman; |
|||
IMPORT Out; |
|||
VAR m, n : INTEGER; |
|||
PROCEDURE Ackerman (x, y : INTEGER) : INTEGER; |
|||
BEGIN |
|||
IF x = 0 THEN RETURN y + 1 |
|||
ELSIF y = 0 THEN RETURN Ackerman (x - 1 , 1) |
|||
ELSE |
|||
RETURN Ackerman (x - 1 , Ackerman (x , y - 1)) |
|||
END |
|||
END Ackerman; |
|||
BEGIN |
|||
FOR m := 0 TO 3 DO |
|||
FOR n := 0 TO 6 DO |
|||
Out.Int (Ackerman (m, n), 10); |
|||
Out.Char (9X) |
|||
END; |
|||
Out.Ln |
|||
END; |
|||
Out.Ln |
|||
END ackerman.</syntaxhighlight> |
|||
=={{header|Objeck}}== |
=={{header|Objeck}}== |
||
{{trans|C#|C sharp}} |
{{trans|C#|C sharp}} |
||
< |
<syntaxhighlight lang="objeck">class Ackermann { |
||
function : Main(args : String[]) ~ Nil { |
function : Main(args : String[]) ~ Nil { |
||
for(m := 0; m <= 3; ++m;) { |
for(m := 0; m <= 3; ++m;) { |
||
Line 4,196: | Line 6,470: | ||
return -1; |
return -1; |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
<pre> |
<pre> |
||
Ackermann(0, 0) = 1 |
Ackermann(0, 0) = 1 |
||
Line 4,221: | Line 6,495: | ||
=={{header|OCaml}}== |
=={{header|OCaml}}== |
||
< |
<syntaxhighlight lang="ocaml">let rec a m n = |
||
if m=0 then (n+1) else |
if m=0 then (n+1) else |
||
if n=0 then (a (m-1) 1) else |
if n=0 then (a (m-1) 1) else |
||
(a (m-1) (a m (n-1)))</ |
(a (m-1) (a m (n-1)))</syntaxhighlight> |
||
or: |
or: |
||
< |
<syntaxhighlight lang="ocaml">let rec a = function |
||
| 0, n -> (n+1) |
| 0, n -> (n+1) |
||
| m, 0 -> a(m-1, 1) |
| m, 0 -> a(m-1, 1) |
||
| m, n -> a(m-1, a(m, n-1))</ |
| m, n -> a(m-1, a(m, n-1))</syntaxhighlight> |
||
with memoization using an hash-table: |
with memoization using an hash-table: |
||
< |
<syntaxhighlight lang="ocaml">let h = Hashtbl.create 4001 |
||
let a m n = |
let a m n = |
||
Line 4,238: | Line 6,512: | ||
let res = a (m, n) in |
let res = a (m, n) in |
||
Hashtbl.add h (m, n) res; |
Hashtbl.add h (m, n) res; |
||
(res)</ |
(res)</syntaxhighlight> |
||
taking advantage of the memoization we start calling small values of '''m''' and '''n''' in order to reduce the recursion call stack: |
taking advantage of the memoization we start calling small values of '''m''' and '''n''' in order to reduce the recursion call stack: |
||
< |
<syntaxhighlight lang="ocaml">let a m n = |
||
for _m = 0 to m do |
for _m = 0 to m do |
||
for _n = 0 to n do |
for _n = 0 to n do |
||
Line 4,246: | Line 6,520: | ||
done; |
done; |
||
done; |
done; |
||
(a m n)</ |
(a m n)</syntaxhighlight> |
||
=== Arbitrary precision === |
=== Arbitrary precision === |
||
With arbitrary-precision integers ([http://caml.inria.fr/pub/docs/manual-ocaml/libref/Big_int.html Big_int module]): |
With arbitrary-precision integers ([http://caml.inria.fr/pub/docs/manual-ocaml/libref/Big_int.html Big_int module]): |
||
< |
<syntaxhighlight lang="ocaml">open Big_int |
||
let one = unit_big_int |
let one = unit_big_int |
||
let zero = zero_big_int |
let zero = zero_big_int |
||
Line 4,259: | Line 6,533: | ||
if eq m zero then (succ n) else |
if eq m zero then (succ n) else |
||
if eq n zero then (a (pred m) one) else |
if eq n zero then (a (pred m) one) else |
||
(a (pred m) (a m (pred n)))</ |
(a (pred m) (a m (pred n)))</syntaxhighlight> |
||
compile with: |
compile with: |
||
ocamlopt -o acker nums.cmxa acker.ml |
ocamlopt -o acker nums.cmxa acker.ml |
||
=== Tail-Recursive === |
=== Tail-Recursive === |
||
Here is a [[:Category:Recursion|tail-recursive]] version: |
Here is a [[:Category:Recursion|tail-recursive]] version: |
||
< |
<syntaxhighlight lang="ocaml">let rec find_option h v = |
||
try Some(Hashtbl.find h v) |
try Some(Hashtbl.find h v) |
||
with Not_found -> None |
with Not_found -> None |
||
Line 4,293: | Line 6,567: | ||
a bounds caller todo m (n-1) |
a bounds caller todo m (n-1) |
||
let a = a (Hashtbl.create 42 (* arbitrary *) ) [] [] ;;</ |
let a = a (Hashtbl.create 42 (* arbitrary *) ) [] [] ;;</syntaxhighlight> |
||
This one uses the arbitrary precision, the tail-recursion, and the optimisation explain on the Wikipedia page about <tt>(m,n) = (3,_)</tt>. |
This one uses the arbitrary precision, the tail-recursion, and the optimisation explain on the Wikipedia page about <tt>(m,n) = (3,_)</tt>. |
||
< |
<syntaxhighlight lang="ocaml">open Big_int |
||
let one = unit_big_int |
let one = unit_big_int |
||
let zero = zero_big_int |
let zero = zero_big_int |
||
Line 4,373: | Line 6,647: | ||
(string_of_big_int n) |
(string_of_big_int n) |
||
(string_of_big_int r); |
(string_of_big_int r); |
||
;;</ |
;;</syntaxhighlight> |
||
=={{header|Oberon-2}}== |
|||
<lang oberon2>MODULE ackerman; |
|||
IMPORT Out; |
|||
VAR m, n : INTEGER; |
|||
PROCEDURE Ackerman (x, y : INTEGER) : INTEGER; |
|||
BEGIN |
|||
IF x = 0 THEN RETURN y + 1 |
|||
ELSIF y = 0 THEN RETURN Ackerman (x - 1 , 1) |
|||
ELSE |
|||
RETURN Ackerman (x - 1 , Ackerman (x , y - 1)) |
|||
END |
|||
END Ackerman; |
|||
BEGIN |
|||
FOR m := 0 TO 3 DO |
|||
FOR n := 0 TO 6 DO |
|||
Out.Int (Ackerman (m, n), 10); |
|||
Out.Char (9X) |
|||
END; |
|||
Out.Ln |
|||
END; |
|||
Out.Ln |
|||
END ackerman.</lang> |
|||
=={{header|Octave}}== |
=={{header|Octave}}== |
||
< |
<syntaxhighlight lang="octave">function r = ackerman(m, n) |
||
if ( m == 0 ) |
if ( m == 0 ) |
||
r = n + 1; |
r = n + 1; |
||
Line 4,416: | Line 6,662: | ||
for i = 0:3 |
for i = 0:3 |
||
disp(ackerman(i, 4)); |
disp(ackerman(i, 4)); |
||
endfor</ |
endfor</syntaxhighlight> |
||
=={{header|Oforth}}== |
=={{header|Oforth}}== |
||
< |
<syntaxhighlight lang="oforth">: A( m n -- p ) |
||
m ifZero: [ n 1+ return ] |
m ifZero: [ n 1+ return ] |
||
m 1- n ifZero: [ 1 ] else: [ A( m, n 1- ) ] A |
m 1- n ifZero: [ 1 ] else: [ A( m, n 1- ) ] A |
||
;</ |
;</syntaxhighlight> |
||
=={{header|Ol}}== |
|||
<syntaxhighlight lang="scheme"> |
|||
; simple version |
|||
(define (A m n) |
|||
(cond |
|||
((= m 0) (+ n 1)) |
|||
((= n 0) (A (- m 1) 1)) |
|||
(else (A (- m 1) (A m (- n 1)))))) |
|||
(print "simple version (A 3 6): " (A 3 6)) |
|||
; smart (lazy) version |
|||
(define (ints-from n) |
|||
(cons* n (delay (ints-from (+ n 1))))) |
|||
(define (knuth-up-arrow a n b) |
|||
(let loop ((n n) (b b)) |
|||
(cond ((= b 0) 1) |
|||
((= n 1) (expt a b)) |
|||
(else (loop (- n 1) (loop n (- b 1))))))) |
|||
(define (A+ m n) |
|||
(define (A-stream) |
|||
(cons* |
|||
(ints-from 1) ;; m = 0 |
|||
(ints-from 2) ;; m = 1 |
|||
;; m = 2 |
|||
(lmap (lambda (n) |
|||
(+ (* 2 (+ n 1)) 1)) |
|||
(ints-from 0)) |
|||
;; m = 3 |
|||
(lmap (lambda (n) |
|||
(- (knuth-up-arrow 2 (- m 2) (+ n 3)) 3)) |
|||
(ints-from 0)) |
|||
;; m = 4... |
|||
(delay (ldrop (A-stream) 3)))) |
|||
(llref (llref (A-stream) m) n)) |
|||
(print "extended version (A 3 6): " (A+ 3 6)) |
|||
</syntaxhighlight> |
|||
{{Out}} |
|||
<pre> |
|||
simple version (A 3 6): 509 |
|||
extended version (A 3 6): 509 |
|||
</pre> |
|||
=={{header|OOC}}== |
=={{header|OOC}}== |
||
< |
<syntaxhighlight lang="ooc"> |
||
ack: func (m: Int, n: Int) -> Int { |
ack: func (m: Int, n: Int) -> Int { |
||
if (m == 0) { |
if (m == 0) { |
||
Line 4,443: | Line 6,735: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|ooRexx}}== |
=={{header|ooRexx}}== |
||
<syntaxhighlight lang="oorexx"> |
|||
<lang ooRexx> |
|||
loop m = 0 to 3 |
loop m = 0 to 3 |
||
loop n = 0 to 6 |
loop n = 0 to 6 |
||
Line 4,460: | Line 6,752: | ||
else if n = 0 then return ackermann(m - 1, 1) |
else if n = 0 then return ackermann(m - 1, 1) |
||
else return ackermann(m - 1, ackermann(m, n - 1)) |
else return ackermann(m - 1, ackermann(m, n - 1)) |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 4,494: | Line 6,786: | ||
=={{header|Order}}== |
=={{header|Order}}== |
||
< |
<syntaxhighlight lang="c">#include <order/interpreter.h> |
||
#define ORDER_PP_DEF_8ack ORDER_PP_FN( \ |
#define ORDER_PP_DEF_8ack ORDER_PP_FN( \ |
||
Line 4,502: | Line 6,794: | ||
(8else, 8ack(8dec(8X), 8ack(8X, 8dec(8Y))))))) |
(8else, 8ack(8dec(8X), 8ack(8X, 8dec(8Y))))))) |
||
ORDER_PP(8to_lit(8ack(3, 4))) // 125</ |
ORDER_PP(8to_lit(8ack(3, 4))) // 125</syntaxhighlight> |
||
=={{header|Oz}}== |
=={{header|Oz}}== |
||
Oz has arbitrary precision integers. |
Oz has arbitrary precision integers. |
||
< |
<syntaxhighlight lang="oz">declare |
||
fun {Ack M N} |
fun {Ack M N} |
||
Line 4,517: | Line 6,809: | ||
in |
in |
||
{Show {Ack 3 7}}</ |
{Show {Ack 3 7}}</syntaxhighlight> |
||
=={{header|PARI/GP}}== |
=={{header|PARI/GP}}== |
||
Naive implementation. |
Naive implementation. |
||
< |
<syntaxhighlight lang="parigp">A(m,n)={ |
||
if(m, |
if(m, |
||
if(n, |
if(n, |
||
Line 4,531: | Line 6,823: | ||
n+1 |
n+1 |
||
) |
) |
||
};</ |
};</syntaxhighlight> |
||
=={{header|Pascal}}== |
=={{header|Pascal}}== |
||
< |
<syntaxhighlight lang="pascal">Program Ackerman; |
||
function ackermann(m, n: Integer) : Integer; |
function ackermann(m, n: Integer) : Integer; |
||
Line 4,553: | Line 6,845: | ||
for m := 0 to 3 do |
for m := 0 to 3 do |
||
WriteLn('A(', m, ',', n, ') = ', ackermann(m,n)); |
WriteLn('A(', m, ',', n, ') = ', ackermann(m,n)); |
||
end.</ |
end.</syntaxhighlight> |
||
=={{header|Pascal}}== |
|||
<syntaxhighlight lang="pascal">Program Ackerman; |
|||
function ackermann(m, n: Integer) : Integer; |
|||
begin |
|||
if m = 0 then |
|||
ackermann := n+1 |
|||
else if n = 0 then |
|||
ackermann := ackermann(m-1, 1) |
|||
else |
|||
ackermann := ackermann(m-1, ackermann(m, n-1)); |
|||
end; |
|||
var |
|||
m, n : Integer; |
|||
begin |
|||
for n := 0 to 6 do |
|||
for m := 0 to 3 do |
|||
WriteLn('A(', m, ',', n, ') = ', ackermann(m,n)); |
|||
end.</syntaxhighlight> |
|||
=={{header|PascalABC.NET}}== |
|||
<syntaxhighlight lang="delphi"> |
|||
function Ackermann(m,n: integer): integer; |
|||
begin |
|||
if (m < 0) or (n < 0) then |
|||
raise new System.ArgumentOutOfRangeException(); |
|||
if m = 0 then |
|||
Result := n + 1 |
|||
else if n = 0 then |
|||
Result := Ackermann(m - 1, 1) |
|||
else Result := Ackermann(m - 1, Ackermann(m, n - 1)) |
|||
end; |
|||
begin |
|||
for var m := 0 to 3 do |
|||
for var n := 0 to 4 do |
|||
Println($'Ackermann({m}, {n}) = {Ackermann(m,n)}'); |
|||
end. |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
Ackermann(0, 0) = 1 |
|||
Ackermann(0, 1) = 2 |
|||
Ackermann(0, 2) = 3 |
|||
Ackermann(0, 3) = 4 |
|||
Ackermann(0, 4) = 5 |
|||
Ackermann(1, 0) = 2 |
|||
Ackermann(1, 1) = 3 |
|||
Ackermann(1, 2) = 4 |
|||
Ackermann(1, 3) = 5 |
|||
Ackermann(1, 4) = 6 |
|||
Ackermann(2, 0) = 3 |
|||
Ackermann(2, 1) = 5 |
|||
Ackermann(2, 2) = 7 |
|||
Ackermann(2, 3) = 9 |
|||
Ackermann(2, 4) = 11 |
|||
Ackermann(3, 0) = 5 |
|||
Ackermann(3, 1) = 13 |
|||
Ackermann(3, 2) = 29 |
|||
Ackermann(3, 3) = 61 |
|||
Ackermann(3, 4) = 125 |
|||
</pre> |
|||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
We memoize calls to ''A'' to make ''A''(2, ''n'') and ''A''(3, ''n'') feasible for larger values of ''n''. |
We memoize calls to ''A'' to make ''A''(2, ''n'') and ''A''(3, ''n'') feasible for larger values of ''n''. |
||
< |
<syntaxhighlight lang="perl">{ |
||
my @memo; |
my @memo; |
||
sub A { |
sub A { |
||
Line 4,569: | Line 6,928: | ||
); |
); |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
An implementation using the conditional statements 'if', 'elsif' and 'else': |
An implementation using the conditional statements 'if', 'elsif' and 'else': |
||
< |
<syntaxhighlight lang="perl">sub A { |
||
my ($m, $n) = @_; |
my ($m, $n) = @_; |
||
if ($m == 0) { $n + 1 } |
if ($m == 0) { $n + 1 } |
||
elsif ($n == 0) { A($m - 1, 1) } |
elsif ($n == 0) { A($m - 1, 1) } |
||
else { A($m - 1, A($m, $n - 1)) } |
else { A($m - 1, A($m, $n - 1)) } |
||
}</ |
}</syntaxhighlight> |
||
An implementation using ternary chaining: |
An implementation using ternary chaining: |
||
< |
<syntaxhighlight lang="perl">sub A { |
||
my ($m, $n) = @_; |
my ($m, $n) = @_; |
||
$m == 0 ? $n + 1 : |
$m == 0 ? $n + 1 : |
||
$n == 0 ? A($m - 1, 1) : |
$n == 0 ? A($m - 1, 1) : |
||
A($m - 1, A($m, $n - 1)) |
A($m - 1, A($m, $n - 1)) |
||
}</ |
}</syntaxhighlight> |
||
Adding memoization and extra terms: |
Adding memoization and extra terms: |
||
< |
<syntaxhighlight lang="perl">use Memoize; memoize('ack2'); |
||
use bigint try=>"GMP"; |
use bigint try=>"GMP"; |
||
Line 4,602: | Line 6,961: | ||
print "ack2(3,4) is ", ack2(3,4), "\n"; |
print "ack2(3,4) is ", ack2(3,4), "\n"; |
||
print "ack2(4,1) is ", ack2(4,1), "\n"; |
print "ack2(4,1) is ", ack2(4,1), "\n"; |
||
print "ack2(4,2) has ", length(ack2(4,2)), " digits\n";</ |
print "ack2(4,2) has ", length(ack2(4,2)), " digits\n";</syntaxhighlight> |
||
{{output}} |
{{output}} |
||
<pre>ack2(3,4) is 125 |
<pre>ack2(3,4) is 125 |
||
Line 4,610: | Line 6,969: | ||
An optimized version, which uses <code>@_</code> as a stack, |
An optimized version, which uses <code>@_</code> as a stack, |
||
instead of recursion. Very fast. |
instead of recursion. Very fast. |
||
< |
<syntaxhighlight lang="perl">use strict; |
||
use warnings; |
use warnings; |
||
use Math::BigInt; |
use Math::BigInt; |
||
Line 4,645: | Line 7,004: | ||
print "ack(4,2) has ", length(ack(4,2)), " digits\n"; |
print "ack(4,2) has ", length(ack(4,2)), " digits\n"; |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header| |
=={{header|Phix}}== |
||
=== native version === |
|||
{{works with|Rakudo|2018.03}} |
|||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">ack</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">)</span> |
|||
<lang perl6>sub A(Int $m, Int $n) { |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> |
|||
if $m == 0 { $n + 1 } |
|||
<span style="color: #008080;">return</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span> |
|||
elsif $n == 0 { A($m - 1, 1) } |
|||
<span style="color: #008080;">elsif</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> |
|||
else { A($m - 1, A($m, $n - 1)) } |
|||
<span style="color: #008080;">return</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">+</span><span style="color: #000000;">2</span> |
|||
}</lang> |
|||
<span style="color: #008080;">elsif</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">then</span> |
|||
An implementation using multiple dispatch: |
|||
<span style="color: #008080;">return</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">*</span><span style="color: #000000;">n</span><span style="color: #0000FF;">+</span><span style="color: #000000;">3</span> |
|||
<lang perl6>multi sub A(0, Int $n) { $n + 1 } |
|||
<span style="color: #008080;">elsif</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">=</span><span style="color: #000000;">3</span> <span style="color: #008080;">then</span> |
|||
multi sub A(Int $m, 0 ) { A($m - 1, 1) } |
|||
<span style="color: #008080;">return</span> <span style="color: #7060A8;">power</span><span style="color: #0000FF;">(</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n</span><span style="color: #0000FF;">+</span><span style="color: #000000;">3</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">3</span> |
|||
multi sub A(Int $m, Int $n) { A($m - 1, A($m, $n - 1)) }</lang> |
|||
<span style="color: #008080;">elsif</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">></span><span style="color: #000000;">0</span> <span style="color: #008080;">and</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> |
|||
Note that in either case, Int is defined to be arbitrary precision in Perl 6. |
|||
<span style="color: #008080;">return</span> <span style="color: #000000;">ack</span><span style="color: #0000FF;">(</span><span style="color: #000000;">m</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">else</span> |
|||
<span style="color: #008080;">return</span> <span style="color: #000000;">ack</span><span style="color: #0000FF;">(</span><span style="color: #000000;">m</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ack</span><span style="color: #0000FF;">(</span><span style="color: #000000;">m</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">))</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">limit</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">23</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #000000;">fmtlens</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8</span><span style="color: #0000FF;">}</span> |
|||
<span style="color: #004080;">atom</span> <span style="color: #000000;">t0</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">" 0"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">limit</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #004080;">string</span> <span style="color: #000000;">fmt</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">" %%%dd"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fmtlens</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fmt</span><span style="color: #0000FF;">,</span><span style="color: #000000;">j</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">to</span> <span style="color: #000000;">5</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%d:"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">i</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">to</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">4</span><span style="color: #0000FF;">?</span><span style="color: #000000;">5</span><span style="color: #0000FF;">-</span><span style="color: #000000;">i</span><span style="color: #0000FF;">:</span><span style="color: #000000;">limit</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #004080;">string</span> <span style="color: #000000;">fmt</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">" %%%dd"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fmtlens</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fmt</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">ack</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span><span style="color: #000000;">j</span><span style="color: #0000FF;">)})</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<!--</syntaxhighlight>--> |
|||
{{out}} |
|||
<pre> |
|||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|||
0: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|||
1: 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|||
2: 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 |
|||
3: 5 13 29 61 125 253 509 1021 2045 4093 8189 16381 32765 65533 131069 262141 524285 1048573 2097149 4194301 8388605 16777213 33554429 67108861 |
|||
4: 13 65533 |
|||
5: 65533 |
|||
</pre> |
|||
ack(4,2) and above fail with power function overflow. ack(3,100) will get you an answer, but only accurate to 16 or so digits. |
|||
=== gmp version === |
|||
Here's a caching version of that, written in the sigilless style, with liberal use of Unicode, and the extra optimizing terms to make A(4,2) possible: |
|||
{{trans|Go}} |
|||
<lang perl6>proto A(Int \𝑚, Int \𝑛) { (state @)[𝑚][𝑛] //= {*} } |
|||
{{libheader|Phix/mpfr}} |
|||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
<span style="color: #000080;font-style:italic;">-- demo\rosetta\Ackermann.exw</span> |
|||
<span style="color: #008080;">include</span> <span style="color: #7060A8;">mpfr</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span> |
|||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">ack</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">mpz</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #7060A8;">mpz_add_ui</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- return n+1</span> |
|||
<span style="color: #008080;">elsif</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #7060A8;">mpz_add_ui</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- return n+2</span> |
|||
<span style="color: #008080;">elsif</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #7060A8;">mpz_mul_si</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">mpz_add_ui</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- return 2*n+3</span> |
|||
<span style="color: #008080;">elsif</span> <span style="color: #000000;">m</span><span style="color: #0000FF;">=</span><span style="color: #000000;">3</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #008080;">not</span> <span style="color: #7060A8;">mpz_fits_integer</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #000080;font-style:italic;">-- As per Go: 2^MAXINT would most certainly run out of memory. |
|||
-- (think about it: a million digits is fine but pretty daft; |
|||
-- however a billion digits requires > addressable memory.)</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">bn</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mpz_sizeinbase</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">throw</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"A(m,n) had n of %d bits; too large"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">bn</span><span style="color: #0000FF;">))</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">ni</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mpz_get_integer</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">mpz_set_si</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">8</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">mpz_mul_2exp</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">ni</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- (n:=8*2^ni)</span> |
|||
<span style="color: #7060A8;">mpz_sub_ui</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- return power(2,n+3)-3</span> |
|||
<span style="color: #008080;">elsif</span> <span style="color: #7060A8;">mpz_cmp_si</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #7060A8;">mpz_set_si</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ack</span><span style="color: #0000FF;">(</span><span style="color: #000000;">m</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- return ack(m-1,1)</span> |
|||
<span style="color: #008080;">else</span> |
|||
<span style="color: #7060A8;">mpz_sub_ui</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ack</span><span style="color: #0000FF;">(</span><span style="color: #000000;">m</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ack</span><span style="color: #0000FF;">(</span><span style="color: #000000;">m</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- return ack(m-1,ack(m,n-1))</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span> |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">limit</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">23</span><span style="color: #0000FF;">,</span> |
|||
<span style="color: #000000;">fmtlens</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8</span><span style="color: #0000FF;">},</span> |
|||
<span style="color: #000000;">extras</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">100</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1e6</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">}}</span> |
|||
<span style="color: #008080;">procedure</span> <span style="color: #000000;">ackermann_tests</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #004080;">atom</span> <span style="color: #000000;">t0</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #004080;">atom</span> <span style="color: #000000;">n</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mpz_init</span><span style="color: #0000FF;">()</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">" 0"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">limit</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #004080;">string</span> <span style="color: #000000;">fmt</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">" %%%dd"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fmtlens</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fmt</span><span style="color: #0000FF;">,</span><span style="color: #000000;">j</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">to</span> <span style="color: #000000;">5</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%d:"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">i</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">to</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">4</span><span style="color: #0000FF;">?</span><span style="color: #000000;">5</span><span style="color: #0000FF;">-</span><span style="color: #000000;">i</span><span style="color: #0000FF;">:</span><span style="color: #000000;">limit</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #7060A8;">mpz_set_si</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">ack</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">string</span> <span style="color: #000000;">fmt</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">" %%%ds"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fmtlens</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">fmt</span><span style="color: #0000FF;">,{</span><span style="color: #7060A8;">mpz_get_str</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">)})</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">extras</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">em</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">en</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">extras</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> |
|||
<span style="color: #7060A8;">mpz_set_si</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">en</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">string</span> <span style="color: #000000;">res</span> |
|||
<span style="color: #008080;">try</span> |
|||
<span style="color: #000000;">ack</span><span style="color: #0000FF;">(</span><span style="color: #000000;">em</span><span style="color: #0000FF;">,</span><span style="color: #000000;">n</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mpz_get_str</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">lr</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">res</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">lr</span><span style="color: #0000FF;">></span><span style="color: #000000;">50</span> <span style="color: #008080;">then</span> |
|||
<span style="color: #000000;">res</span><span style="color: #0000FF;">[</span><span style="color: #000000;">21</span><span style="color: #0000FF;">..-</span><span style="color: #000000;">21</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"..."</span> |
|||
<span style="color: #000000;">res</span> <span style="color: #0000FF;">&=</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">" (%d digits)"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">lr</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
<span style="color: #008080;">catch</span> <span style="color: #000000;">e</span> |
|||
<span style="color: #000080;font-style:italic;">-- ack(4,3), ack(5,1) and ack(6,0) all fail, |
|||
-- just as they should do</span> |
|||
<span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"***ERROR***: "</span><span style="color: #0000FF;">&</span><span style="color: #000000;">e</span><span style="color: #0000FF;">[</span><span style="color: #000000;">E_USER</span><span style="color: #0000FF;">]</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">try</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"ack(%d,%d) %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">em</span><span style="color: #0000FF;">,</span><span style="color: #000000;">en</span><span style="color: #0000FF;">,</span><span style="color: #000000;">res</span><span style="color: #0000FF;">})</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
<span style="color: #000000;">n</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mpz_free</span><span style="color: #0000FF;">(</span><span style="color: #000000;">n</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"ackermann_tests completed (%s)\n\n"</span><span style="color: #0000FF;">,{</span><span style="color: #7060A8;">elapsed</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">time</span><span style="color: #0000FF;">()-</span><span style="color: #000000;">t0</span><span style="color: #0000FF;">)})</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span> |
|||
<span style="color: #000000;">ackermann_tests</span><span style="color: #0000FF;">()</span> |
|||
<!--</syntaxhighlight>--> |
|||
{{out}} |
|||
<pre> |
|||
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|||
0: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|||
1: 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|||
2: 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 |
|||
3: 5 13 29 61 125 253 509 1021 2045 4093 8189 16381 32765 65533 131069 262141 524285 1048573 2097149 4194301 8388605 16777213 33554429 67108861 |
|||
4: 13 65533 |
|||
5: 65533 |
|||
ack(3,100) 10141204801825835211973625643005 |
|||
multi A(0, Int \𝑛) { 𝑛 + 1 } |
|||
ack(3,1000000) 79205249834367186005...39107225301976875005 (301031 digits) |
|||
multi A(1, Int \𝑛) { 𝑛 + 2 } |
|||
ack(4,2) 20035299304068464649...45587895905719156733 (19729 digits) |
|||
multi A(2, Int \𝑛) { 3 + 2 * 𝑛 } |
|||
ack(4,3) ***ERROR***: A(m,n) had n of 65536 bits; too large |
|||
multi A(3, Int \𝑛) { 5 + 8 * (2 ** 𝑛 - 1) } |
|||
ackermann_tests completed (0.2s) |
|||
multi A(Int \𝑚, 0 ) { A(𝑚 - 1, 1) } |
|||
</pre> |
|||
multi A(Int \𝑚, Int \𝑛) { A(𝑚 - 1, A(𝑚, 𝑛 - 1)) } |
|||
=={{header|Phixmonti}}== |
|||
# Testing: |
|||
<syntaxhighlight lang="phixmonti">def ack |
|||
say A(4,1); |
|||
var n var m |
|||
say .chars, " digits starting with ", .substr(0,50), "..." given A(4,2);</lang> |
|||
{{out}} |
|||
m 0 == if |
|||
<pre>65533 |
|||
n 1 + |
|||
19729 digits starting with 20035299304068464649790723515602557504478254755697...</pre> |
|||
=={{header|Phix}}== |
|||
<lang Phix> |
|||
-- |
|||
-- Ackermann.exw |
|||
-- ============= |
|||
-- |
|||
-- optimised. still no bignum library, so ack(4,2), which is power(2,65536)-3, which is |
|||
-- apparently 19729 digits, and any above, are beyond (the CPU/FPU hardware) and this. |
|||
-- (replaced ack(atom,atom) with ack(int,int) since the former fares no better.) |
|||
function ack(integer m, integer n) |
|||
if m=0 then |
|||
return n+1 |
|||
elsif m=1 then |
|||
return n+2 |
|||
elsif m=2 then |
|||
return 2*n+3 |
|||
elsif m=3 then |
|||
return power(2,n+3)-3 |
|||
elsif m>0 and n=0 then |
|||
return ack(m-1,1) |
|||
else |
else |
||
n 0 == if |
|||
m 1 - 1 ack |
|||
end if |
|||
else |
|||
end function |
|||
m 1 - m n 1 - ack ack |
|||
endif |
|||
endif |
|||
enddef |
|||
3 6 ack print nl</syntaxhighlight> |
|||
procedure Ackermann() |
|||
for i=0 to 3 do |
|||
for j=0 to 10 do |
|||
printf(1,"%5d",ack(i,j)) |
|||
end for |
|||
puts(1,"\n") |
|||
end for |
|||
printf(1,"ack(4,1) %5d\n",ack(4,1)) |
|||
-- printf(1,"ack(4,2) %5d\n",ack(4,2)) -- power function overflow |
|||
if getc(0) then end if |
|||
end procedure |
|||
Ackermann() |
|||
</lang> |
|||
{{out}} |
|||
<pre> |
|||
1 2 3 4 5 6 7 8 9 10 11 |
|||
2 3 4 5 6 7 8 9 10 11 12 |
|||
3 5 7 9 11 13 15 17 19 21 23 |
|||
5 13 29 61 125 253 509 1021 2045 4093 8189 |
|||
ack(4,1) 65533 |
|||
</pre> |
|||
=={{header|PHP}}== |
=={{header|PHP}}== |
||
< |
<syntaxhighlight lang="php">function ackermann( $m , $n ) |
||
{ |
{ |
||
if ( $m==0 ) |
if ( $m==0 ) |
||
Line 4,745: | Line 7,193: | ||
echo ackermann( 3, 4 ); |
echo ackermann( 3, 4 ); |
||
// prints 125</ |
// prints 125</syntaxhighlight> |
||
=={{header|Picat}}== |
|||
<syntaxhighlight lang="picat">go => |
|||
foreach(M in 0..3) |
|||
println([m=M,[a(M,N) : N in 0..16]]) |
|||
end, |
|||
nl, |
|||
printf("a2(4,1): %d\n", a2(4,1)), |
|||
nl, |
|||
time(check_larger(3,10000)), |
|||
nl, |
|||
time(check_larger(4,2)), |
|||
nl. |
|||
% Using a2/2 and chop off large output |
|||
check_larger(M,N) => |
|||
printf("a2(%d,%d): ", M,N), |
|||
A = a2(M,N).to_string, |
|||
Len = A.len, |
|||
if Len < 50 then |
|||
println(A) |
|||
else |
|||
println(A[1..20] ++ ".." ++ A[Len-20..Len]) |
|||
end, |
|||
println(digits=Len). |
|||
% Plain tabled (memoized) version with guards |
|||
table |
|||
a(0, N) = N+1 => true. |
|||
a(M, 0) = a(M-1,1), M > 0 => true. |
|||
a(M, N) = a(M-1,a(M, N-1)), M > 0, N > 0 => true. |
|||
% Faster and pure function version (no guards). |
|||
% (Based on Python example.) |
|||
table |
|||
a2(0,N) = N + 1. |
|||
a2(1,N) = N + 2. |
|||
a2(2,N) = 2*N + 3. |
|||
a2(3,N) = 8*(2**N - 1) + 5. |
|||
a2(M,N) = cond(N == 0,a2(M-1, 1), a2(M-1, a2(M, N-1))). |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
[m = 0,[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]] |
|||
[m = 1,[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]] |
|||
[m = 2,[3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35]] |
|||
[m = 3,[5,13,29,61,125,253,509,1021,2045,4093,8189,16381,32765,65533,131069,262141,524285]] |
|||
a2(4,1): 65533 |
|||
a2(3,10000): 15960504935046067079..454194438340773675005 |
|||
digits = 3012 |
|||
CPU time 0.02 seconds. |
|||
a2(4,2): 20035299304068464649..445587895905719156733 |
|||
digits = 19729 |
|||
CPU time 0.822 seconds. |
|||
</pre> |
|||
=={{header|PicoLisp}}== |
=={{header|PicoLisp}}== |
||
< |
<syntaxhighlight lang="picolisp">(de ack (X Y) |
||
(cond |
(cond |
||
((=0 X) (inc Y)) |
((=0 X) (inc Y)) |
||
((=0 Y) (ack (dec X) 1)) |
((=0 Y) (ack (dec X) 1)) |
||
(T (ack (dec X) (ack X (dec Y)))) ) )</ |
(T (ack (dec X) (ack X (dec Y)))) ) )</syntaxhighlight> |
||
=={{header|Piet}}== |
=={{header|Piet}}== |
||
Line 5,121: | Line 7,628: | ||
=={{header|Pike}}== |
=={{header|Pike}}== |
||
< |
<syntaxhighlight lang="pike">int main(){ |
||
write(ackermann(3,4) + "\n"); |
write(ackermann(3,4) + "\n"); |
||
} |
} |
||
Line 5,133: | Line 7,640: | ||
return ackermann(m-1, ackermann(m, n-1)); |
return ackermann(m-1, ackermann(m, n-1)); |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
=={{header|PL/I}}== |
=={{header|PL/I}}== |
||
< |
<syntaxhighlight lang="pl/i">Ackerman: procedure (m, n) returns (fixed (30)) recursive; |
||
declare (m, n) fixed (30); |
declare (m, n) fixed (30); |
||
if m = 0 then return (n+1); |
if m = 0 then return (n+1); |
||
Line 5,142: | Line 7,649: | ||
else if m > 0 & n > 0 then return (Ackerman(m-1, Ackerman(m, n-1))); |
else if m > 0 & n > 0 then return (Ackerman(m-1, Ackerman(m, n-1))); |
||
return (0); |
return (0); |
||
end Ackerman;</ |
end Ackerman;</syntaxhighlight> |
||
=={{header|PL/SQL}}== |
=={{header|PL/SQL}}== |
||
< |
<syntaxhighlight lang="plsql">DECLARE |
||
FUNCTION ackermann(pi_m IN NUMBER, |
FUNCTION ackermann(pi_m IN NUMBER, |
||
Line 5,166: | Line 7,673: | ||
END LOOP; |
END LOOP; |
||
END; |
END; |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 5,200: | Line 7,707: | ||
=={{header|PostScript}}== |
=={{header|PostScript}}== |
||
< |
<syntaxhighlight lang="postscript">/ackermann{ |
||
/n exch def |
/n exch def |
||
/m exch def %PostScript takes arguments in the reverse order as specified in the function definition |
/m exch def %PostScript takes arguments in the reverse order as specified in the function definition |
||
Line 5,213: | Line 7,720: | ||
m 1 sub m n 1 sub ackermann ackermann |
m 1 sub m n 1 sub ackermann ackermann |
||
}if |
}if |
||
}def</ |
}def</syntaxhighlight> |
||
{{libheader|initlib}} |
{{libheader|initlib}} |
||
< |
<syntaxhighlight lang="postscript">/A { |
||
[/.m /.n] let |
[/.m /.n] let |
||
{ |
{ |
||
Line 5,222: | Line 7,729: | ||
{.m 0 gt .n 0 gt and} {.m pred .m .n pred A A} is? |
{.m 0 gt .n 0 gt and} {.m pred .m .n pred A A} is? |
||
} cond |
} cond |
||
end}.</ |
end}.</syntaxhighlight> |
||
=={{header|Potion}}== |
=={{header|Potion}}== |
||
< |
<syntaxhighlight lang="potion">ack = (m, n): |
||
if (m == 0): n + 1 |
if (m == 0): n + 1 |
||
. elsif (n == 0): ack(m - 1, 1) |
. elsif (n == 0): ack(m - 1, 1) |
||
Line 5,235: | Line 7,742: | ||
ack(m, n) print |
ack(m, n) print |
||
" " print. |
" " print. |
||
"\n" print.</ |
"\n" print.</syntaxhighlight> |
||
=={{header|PowerBASIC}}== |
=={{header|PowerBASIC}}== |
||
< |
<syntaxhighlight lang="powerbasic">FUNCTION PBMAIN () AS LONG |
||
DIM m AS QUAD, n AS QUAD |
DIM m AS QUAD, n AS QUAD |
||
Line 5,255: | Line 7,762: | ||
FUNCTION = Ackermann(m - 1, Ackermann(m, n - 1)) |
FUNCTION = Ackermann(m - 1, Ackermann(m, n - 1)) |
||
END IF |
END IF |
||
END FUNCTION</ |
END FUNCTION</syntaxhighlight> |
||
=={{header|PowerShell}}== |
=={{header|PowerShell}}== |
||
{{trans|PHP}} |
{{trans|PHP}} |
||
< |
<syntaxhighlight lang="powershell">function ackermann ([long] $m, [long] $n) { |
||
if ($m -eq 0) { |
if ($m -eq 0) { |
||
return $n + 1 |
return $n + 1 |
||
Line 5,270: | Line 7,776: | ||
return (ackermann ($m - 1) (ackermann $m ($n - 1))) |
return (ackermann ($m - 1) (ackermann $m ($n - 1))) |
||
}</ |
}</syntaxhighlight> |
||
Building an example table (takes a while to compute, though, especially for the last three numbers; also it fails with the last line in Powershell v1 since the maximum recursion depth is only 100 there): |
Building an example table (takes a while to compute, though, especially for the last three numbers; also it fails with the last line in Powershell v1 since the maximum recursion depth is only 100 there): |
||
< |
<syntaxhighlight lang="powershell">foreach ($m in 0..3) { |
||
foreach ($n in 0..6) { |
foreach ($n in 0..6) { |
||
Write-Host -NoNewline ("{0,5}" -f (ackermann $m $n)) |
Write-Host -NoNewline ("{0,5}" -f (ackermann $m $n)) |
||
} |
} |
||
Write-Host |
Write-Host |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> 1 2 3 4 5 6 7 |
<pre> 1 2 3 4 5 6 7 |
||
Line 5,285: | Line 7,791: | ||
===A More "PowerShelly" Way=== |
===A More "PowerShelly" Way=== |
||
<syntaxhighlight lang="powershell"> |
|||
<lang PowerShell> |
|||
function Get-Ackermann ([int64]$m, [int64]$n) |
function Get-Ackermann ([int64]$m, [int64]$n) |
||
{ |
{ |
||
Line 5,300: | Line 7,806: | ||
return (Get-Ackermann ($m - 1) (Get-Ackermann $m ($n - 1))) |
return (Get-Ackermann ($m - 1) (Get-Ackermann $m ($n - 1))) |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
Save the result to an array (for possible future use?), then display it using the <code>Format-Wide</code> cmdlet: |
Save the result to an array (for possible future use?), then display it using the <code>Format-Wide</code> cmdlet: |
||
<syntaxhighlight lang="powershell"> |
|||
<lang PowerShell> |
|||
$ackermann = 0..3 | ForEach-Object {$m = $_; 0..6 | ForEach-Object {Get-Ackermann $m $_}} |
$ackermann = 0..3 | ForEach-Object {$m = $_; 0..6 | ForEach-Object {Get-Ackermann $m $_}} |
||
$ackermann | Format-Wide {"{0,3}" -f $_} -Column 7 -Force |
$ackermann | Format-Wide {"{0,3}" -f $_} -Column 7 -Force |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{Out}} |
{{Out}} |
||
<pre> |
<pre> |
||
Line 5,316: | Line 7,822: | ||
=={{header|Processing}}== |
=={{header|Processing}}== |
||
< |
<syntaxhighlight lang="java">int ackermann(int m, int n) { |
||
if (m == 0) |
|||
{ |
|||
return n + 1; |
|||
else if (m > 0 && n == 0) |
|||
return ackermann(m - 1, 1); |
|||
else |
|||
return ackermann(m - 1, 1); |
|||
return ackermann( m - 1, ackermann(m, n - 1) ); |
|||
else |
|||
} |
|||
return ackermann( m - 1, ackermann(m, n - 1) ); |
|||
}</lang> |
|||
// Call function to produce output: |
|||
// the first 4x7 Ackermann numbers |
|||
void setup() { |
|||
for (int m=0; m<4; m++) { |
|||
for (int n=0; n<7; n++) { |
|||
print(ackermann(m, n), " "); |
|||
} |
|||
println(); |
|||
} |
|||
}</syntaxhighlight> |
|||
{{Out}} |
|||
<pre>1 2 3 4 5 6 7 |
|||
2 3 4 5 6 7 8 |
|||
3 5 7 9 11 13 15 |
|||
5 13 29 61 125 253 509</pre> |
|||
==={{header|Processing Python mode}}=== |
|||
Python is not very adequate for deep recursion, so |
|||
even setting sys.setrecursionlimit(1000000000) if |
|||
m = 5 it throws 'maximum recursion depth exceeded' |
|||
<syntaxhighlight lang="python">from __future__ import print_function |
|||
def setup(): |
|||
for m in range(4): |
|||
for n in range(7): |
|||
print("{} ".format(ackermann(m, n)), end = "") |
|||
print() |
|||
# print('finished') |
|||
def ackermann(m, n): |
|||
if m == 0: |
|||
return n + 1 |
|||
elif m > 0 and n == 0: |
|||
return ackermann(m - 1, 1) |
|||
else: |
|||
return ackermann(m - 1, ackermann(m, n - 1))</syntaxhighlight> |
|||
==={{header|Processing.R}}=== |
|||
Processing.R may exceed its stack depth at ~n==6 and returns null. |
|||
<syntaxhighlight lang="r">setup <- function() { |
|||
for (m in 0:3) { |
|||
for (n in 0:4) { |
|||
stdout$print(paste(ackermann(m, n), " ")) |
|||
} |
|||
stdout$println("") |
|||
} |
|||
} |
|||
ackermann <- function(m, n) { |
|||
if ( m == 0 ) { |
|||
return(n+1) |
|||
} else if ( n == 0 ) { |
|||
ackermann(m-1, 1) |
|||
} else { |
|||
ackermann(m-1, ackermann(m, n-1)) |
|||
} |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre>1 2 3 4 5 |
|||
2 3 4 5 6 |
|||
3 5 7 9 11 |
|||
5 13 29 61 125</pre> |
|||
=={{header|Prolog}}== |
=={{header|Prolog}}== |
||
{{works with|SWI Prolog}} |
{{works with|SWI Prolog}} |
||
<syntaxhighlight lang="prolog">:- table ack/3. % memoization reduces the execution time of ack(4,1,X) from several |
|||
<lang prolog>ack(0, N, Ans) :- Ans is N+1. |
|||
% minutes to about one second on a typical desktop computer. |
|||
ack(0, N, Ans) :- Ans is N+1. |
|||
ack(M, 0, Ans) :- M>0, X is M-1, ack(X, 1, Ans). |
ack(M, 0, Ans) :- M>0, X is M-1, ack(X, 1, Ans). |
||
ack(M, N, Ans) :- M>0, N>0, X is M-1, Y is N-1, ack(M, Y, Ans2), ack(X, Ans2, Ans).</ |
ack(M, N, Ans) :- M>0, N>0, X is M-1, Y is N-1, ack(M, Y, Ans2), ack(X, Ans2, Ans).</syntaxhighlight> |
||
"Pure" Prolog Version (Uses Peano arithmetic instead of is/2): |
|||
=={{header|Pure}}== |
|||
<syntaxhighlight lang="prolog">ack(0,N,s(N)). |
|||
<lang pure>A 0 n = n+1; |
|||
ack(s(M),0,P):- ack(M,s(0),P). |
|||
A m 0 = A (m-1) 1 if m > 0; |
|||
ack(s(M),s(N),P):- ack(s(M),N,S), ack(M,S,P). |
|||
A m n = A (m-1) (A m (n-1)) if m > 0 && n > 0;</lang> |
|||
% Peano's first axiom in Prolog is that s(0) AND s(s(N)):- s(N) |
|||
=={{header|PureBasic}}== |
|||
% Thanks to this we don't need explicit N > 0 checks. |
|||
<lang PureBasic>Procedure.q Ackermann(m, n) |
|||
% Nor explicit arithmetic operations like X is M-1. |
|||
If m = 0 |
|||
% Recursion and unification naturally decrement s(N) to N. |
|||
ProcedureReturn n + 1 |
|||
% But: Prolog clauses are relations and cannot be replaced by their result, like functions. |
|||
ElseIf n = 0 |
|||
% Because of this we do need an extra argument to hold the output of the function. |
|||
ProcedureReturn Ackermann(m - 1, 1) |
|||
% And we also need an additional call to the function in the last clause. |
|||
Else |
|||
ProcedureReturn Ackermann(m - 1, Ackermann(m, n - 1)) |
|||
EndIf |
|||
EndProcedure |
|||
% Example input/output: |
|||
Debug Ackermann(3,4)</lang> |
|||
% ?- ack(s(0),s(s(0)),P). |
|||
% P = s(s(s(s(0)))) ; |
|||
% false. |
|||
</syntaxhighlight> |
|||
=={{header|Pure}}== |
|||
<syntaxhighlight lang="pure">A 0 n = n+1; |
|||
A m 0 = A (m-1) 1 if m > 0; |
|||
A m n = A (m-1) (A m (n-1)) if m > 0 && n > 0;</syntaxhighlight> |
|||
=={{header|Pure Data}}== |
=={{header|Pure Data}}== |
||
<syntaxhighlight lang="pure data"> |
|||
<lang Pure Data> |
|||
#N canvas 741 265 450 436 10; |
#N canvas 741 265 450 436 10; |
||
#X obj 83 111 t b l; |
#X obj 83 111 t b l; |
||
Line 5,396: | Line 7,978: | ||
#X connect 15 0 10 0; |
#X connect 15 0 10 0; |
||
#X connect 16 0 10 0; |
#X connect 16 0 10 0; |
||
#X connect 17 0 0 0;</ |
#X connect 17 0 0 0;</syntaxhighlight> |
||
=={{header|PureBasic}}== |
|||
<syntaxhighlight lang="purebasic">Procedure.q Ackermann(m, n) |
|||
If m = 0 |
|||
ProcedureReturn n + 1 |
|||
ElseIf n = 0 |
|||
ProcedureReturn Ackermann(m - 1, 1) |
|||
Else |
|||
ProcedureReturn Ackermann(m - 1, Ackermann(m, n - 1)) |
|||
EndIf |
|||
EndProcedure |
|||
Debug Ackermann(3,4)</syntaxhighlight> |
|||
=={{header|Purity}}== |
=={{header|Purity}}== |
||
< |
<syntaxhighlight lang="purity">data Iter = f => FoldNat <const $f One, $f> |
||
data Ackermann = FoldNat <const Succ, Iter></ |
data Ackermann = FoldNat <const Succ, Iter></syntaxhighlight> |
||
=={{header|Python}}== |
=={{header|Python}}== |
||
===Python: Explicitly recursive=== |
|||
{{works with|Python|2.5}} |
{{works with|Python|2.5}} |
||
< |
<syntaxhighlight lang="python">def ack1(M, N): |
||
return (N + 1) if M == 0 else ( |
return (N + 1) if M == 0 else ( |
||
ack1(M-1, 1) if N == 0 else ack1(M-1, ack1(M, N-1)))</ |
ack1(M-1, 1) if N == 0 else ack1(M-1, ack1(M, N-1)))</syntaxhighlight> |
||
Another version: |
Another version: |
||
<syntaxhighlight lang="python">from functools import lru_cache |
|||
<lang python>def ack2(M, N): |
|||
@lru_cache(None) |
|||
def ack2(M, N): |
|||
if M == 0: |
if M == 0: |
||
return N + 1 |
return N + 1 |
||
Line 5,414: | Line 8,013: | ||
return ack2(M - 1, 1) |
return ack2(M - 1, 1) |
||
else: |
else: |
||
return ack2(M - 1, ack2(M, N - 1))</ |
return ack2(M - 1, ack2(M, N - 1))</syntaxhighlight> |
||
{{out|Example of use}} |
{{out|Example of use}} |
||
< |
<syntaxhighlight lang="python">>>> import sys |
||
>>> sys.setrecursionlimit(3000) |
>>> sys.setrecursionlimit(3000) |
||
>>> ack1(0,0) |
>>> ack1(0,0) |
||
Line 5,425: | Line 8,024: | ||
1 |
1 |
||
>>> ack2(3,4) |
>>> ack2(3,4) |
||
125</ |
125</syntaxhighlight> |
||
From the Mathematica ack3 example: |
From the Mathematica ack3 example: |
||
< |
<syntaxhighlight lang="python">def ack2(M, N): |
||
return (N + 1) if M == 0 else ( |
return (N + 1) if M == 0 else ( |
||
(N + 2) if M == 1 else ( |
(N + 2) if M == 1 else ( |
||
(2*N + 3) if M == 2 else ( |
(2*N + 3) if M == 2 else ( |
||
(8*(2**N - 1) + 5) if M == 3 else ( |
(8*(2**N - 1) + 5) if M == 3 else ( |
||
ack2(M-1, 1) if N == 0 else ack2(M-1, ack2(M, N-1))))))</ |
ack2(M-1, 1) if N == 0 else ack2(M-1, ack2(M, N-1))))))</syntaxhighlight> |
||
Results confirm those of Mathematica for ack(4,1) and ack(4,2) |
Results confirm those of Mathematica for ack(4,1) and ack(4,2) |
||
===Python: Without recursive function calls=== |
|||
The heading is more correct than saying the following is iterative as an explicit stack is used to replace explicit recursive function calls. I don't think this is what Comp. Sci. professors mean by iterative. |
|||
<syntaxhighlight lang="python">from collections import deque |
|||
def ack_ix(m, n): |
|||
"Paddy3118's iterative with optimisations on m" |
|||
stack = deque([]) |
|||
stack.extend([m, n]) |
|||
while len(stack) > 1: |
|||
n, m = stack.pop(), stack.pop() |
|||
if m == 0: |
|||
stack.append(n + 1) |
|||
elif m == 1: |
|||
stack.append(n + 2) |
|||
elif m == 2: |
|||
stack.append(2*n + 3) |
|||
elif m == 3: |
|||
stack.append(2**(n + 3) - 3) |
|||
elif n == 0: |
|||
stack.extend([m-1, 1]) |
|||
else: |
|||
stack.extend([m-1, m, n-1]) |
|||
return stack[0]</syntaxhighlight> |
|||
{{out}} |
|||
(From an ipython shell) |
|||
<pre>In [26]: %time a_4_2 = ack_ix(4, 2) |
|||
Wall time: 0 ns |
|||
In [27]: # How big is the answer? |
|||
In [28]: float(a_4_2) |
|||
Traceback (most recent call last): |
|||
File "<ipython-input-28-af4ad951eff8>", line 1, in <module> |
|||
float(a_4_2) |
|||
OverflowError: int too large to convert to float |
|||
In [29]: # How many decimal digits in the answer? |
|||
In [30]: len(str(a_4_2)) |
|||
Out[30]: 19729 |
|||
</pre> |
|||
=={{header|Quackery}}== |
|||
<syntaxhighlight lang="quackery"> forward is ackermann ( m n --> r ) |
|||
[ over 0 = iff |
|||
[ nip 1 + ] done |
|||
dup 0 = iff |
|||
[ drop 1 - 1 |
|||
ackermann ] done |
|||
over 1 - unrot 1 - |
|||
ackermann ackermann ] resolves ackermann ( m n --> r ) |
|||
3 10 ackermann echo</syntaxhighlight> |
|||
'''Output:''' |
|||
<pre>8189</pre> |
|||
=={{header|R}}== |
=={{header|R}}== |
||
< |
<syntaxhighlight lang="r">ackermann <- function(m, n) { |
||
if ( m == 0 ) { |
if ( m == 0 ) { |
||
n+1 |
n+1 |
||
Line 5,444: | Line 8,108: | ||
ackermann(m-1, ackermann(m, n-1)) |
ackermann(m-1, ackermann(m, n-1)) |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
< |
<syntaxhighlight lang="r">for ( i in 0:3 ) { |
||
print(ackermann(i, 4)) |
print(ackermann(i, 4)) |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Racket}}== |
=={{header|Racket}}== |
||
< |
<syntaxhighlight lang="racket"> |
||
#lang racket |
#lang racket |
||
(define (ackermann m n) |
(define (ackermann m n) |
||
Line 5,456: | Line 8,120: | ||
[(zero? n) (ackermann (sub1 m) 1)] |
[(zero? n) (ackermann (sub1 m) 1)] |
||
[else (ackermann (sub1 m) (ackermann m (sub1 n)))])) |
[else (ackermann (sub1 m) (ackermann m (sub1 n)))])) |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Raku}}== |
|||
(formerly Perl 6) |
|||
{{works with|Rakudo|2018.03}} |
|||
<syntaxhighlight lang="raku" line>sub A(Int $m, Int $n) { |
|||
if $m == 0 { $n + 1 } |
|||
elsif $n == 0 { A($m - 1, 1) } |
|||
else { A($m - 1, A($m, $n - 1)) } |
|||
}</syntaxhighlight> |
|||
An implementation using multiple dispatch: |
|||
<syntaxhighlight lang="raku" line>multi sub A(0, Int $n) { $n + 1 } |
|||
multi sub A(Int $m, 0 ) { A($m - 1, 1) } |
|||
multi sub A(Int $m, Int $n) { A($m - 1, A($m, $n - 1)) }</syntaxhighlight> |
|||
Note that in either case, Int is defined to be arbitrary precision in Raku. |
|||
Here's a caching version of that, written in the sigilless style, with liberal use of Unicode, and the extra optimizing terms to make A(4,2) possible: |
|||
<syntaxhighlight lang="raku" line>proto A(Int \𝑚, Int \𝑛) { (state @)[𝑚][𝑛] //= {*} } |
|||
multi A(0, Int \𝑛) { 𝑛 + 1 } |
|||
multi A(1, Int \𝑛) { 𝑛 + 2 } |
|||
multi A(2, Int \𝑛) { 3 + 2 * 𝑛 } |
|||
multi A(3, Int \𝑛) { 5 + 8 * (2 ** 𝑛 - 1) } |
|||
multi A(Int \𝑚, 0 ) { A(𝑚 - 1, 1) } |
|||
multi A(Int \𝑚, Int \𝑛) { A(𝑚 - 1, A(𝑚, 𝑛 - 1)) } |
|||
# Testing: |
|||
say A(4,1); |
|||
say .chars, " digits starting with ", .substr(0,50), "..." given A(4,2);</syntaxhighlight> |
|||
{{out}} |
|||
<pre>65533 |
|||
19729 digits starting with 20035299304068464649790723515602557504478254755697...</pre> |
|||
=={{header|REBOL}}== |
=={{header|REBOL}}== |
||
Line 5,466: | Line 8,163: | ||
] |
] |
||
]</pre> |
]</pre> |
||
=={{header|Refal}}== |
|||
<syntaxhighlight lang="refal">$ENTRY Go { |
|||
= <Prout 'A(3,9) = ' <A 3 9>>; |
|||
}; |
|||
A { |
|||
0 s.N = <+ s.N 1>; |
|||
s.M 0 = <A <- s.M 1> 1>; |
|||
s.M s.N = <A <- s.M 1> <A s.M <- s.N 1>>>; |
|||
};</syntaxhighlight> |
|||
{{out}} |
|||
<pre>A(3,9) = 4093</pre> |
|||
=={{header|ReScript}}== |
|||
<syntaxhighlight lang="rescript">let _m = Sys.argv[2] |
|||
let _n = Sys.argv[3] |
|||
let m = int_of_string(_m) |
|||
let n = int_of_string(_n) |
|||
let rec a = (m, n) => |
|||
switch (m, n) { |
|||
| (0, n) => (n+1) |
|||
| (m, 0) => a(m-1, 1) |
|||
| (m, n) => a(m-1, a(m, n-1)) |
|||
} |
|||
Js.log("ackermann(" ++ _m ++ ", " ++ _n ++ ") = " |
|||
++ string_of_int(a(m, n)))</syntaxhighlight> |
|||
{{out}} |
|||
<pre>$ bsc acker.res > acker.bs.js |
|||
$ node acker.bs.js 2 3 |
|||
ackermann(2, 3) = 9 |
|||
$ node acker.bs.js 3 4 |
|||
ackermann(3, 4) = 125 |
|||
</pre> |
|||
=={{header|REXX}}== |
=={{header|REXX}}== |
||
===no optimization=== |
===no optimization=== |
||
< |
<syntaxhighlight lang="rexx">/*REXX program calculates and displays some values for the Ackermann function. */ |
||
/*╔════════════════════════════════════════════════════════════════════════╗ |
/*╔════════════════════════════════════════════════════════════════════════╗ |
||
║ Note: the Ackermann function (as implemented here) utilizes deep ║ |
║ Note: the Ackermann function (as implemented here) utilizes deep ║ |
||
Line 5,493: | Line 8,229: | ||
if m==0 then return n+1 |
if m==0 then return n+1 |
||
if n==0 then return ackermann(m-1, 1) |
if n==0 then return ackermann(m-1, 1) |
||
return ackermann(m-1, ackermann(m, n-1) )</ |
return ackermann(m-1, ackermann(m, n-1) )</syntaxhighlight> |
||
{{out|output|text= when using the internal default input:}} |
|||
'''output''' |
|||
<pre style="height:60ex"> |
<pre style="height:60ex"> |
||
Ackermann(0, 0)= 1 calls= 1 |
Ackermann(0, 0)= 1 calls= 1 |
||
Line 5,572: | Line 8,308: | ||
Ackermann(3, 8)= 2045 calls= 2785999 |
Ackermann(3, 8)= 2045 calls= 2785999 |
||
</pre> |
</pre> |
||
This output is from Regina and takes about 4 seconds. Running under ooRexx, the last line displayed is 'Ackermann(3, 6)...' and then the program just stops. Looks like deep recursion is more limited in ooRexx. |
|||
===optimized for m ≤ 2=== |
===optimized for m ≤ 2=== |
||
< |
<syntaxhighlight lang="rexx">/*REXX program calculates and displays some values for the Ackermann function. */ |
||
high=24 |
high=24 |
||
do j=0 to 3; say |
do j=0 to 3; say |
||
Line 5,594: | Line 8,331: | ||
if n==0 then return ackermann(m-1, 1) |
if n==0 then return ackermann(m-1, 1) |
||
if m==2 then return n + 3 + n |
if m==2 then return n + 3 + n |
||
return ackermann(m-1, ackermann(m, n-1) )</ |
return ackermann(m-1, ackermann(m, n-1) )</syntaxhighlight> |
||
{{out|output|text= when using the internal default input:}} |
|||
'''output''' |
|||
<pre style="height:60ex"> |
<pre style="height:60ex"> |
||
Ackermann(0, 0)= 1 calls= 1 |
Ackermann(0, 0)= 1 calls= 1 |
||
Line 5,678: | Line 8,415: | ||
<br><br>If the '''numeric digits 100''' were to be increased to '''20000''', then the value of '''Ackermann(4,2)''' |
<br><br>If the '''numeric digits 100''' were to be increased to '''20000''', then the value of '''Ackermann(4,2)''' |
||
<br>(the last line of output) would be presented with the full '''19,729''' decimal digits. |
<br>(the last line of output) would be presented with the full '''19,729''' decimal digits. |
||
< |
<syntaxhighlight lang="rexx">/*REXX program calculates and displays some values for the Ackermann function. */ |
||
numeric digits 100 /*use up to 100 decimal digit integers.*/ |
numeric digits 100 /*use up to 100 decimal digit integers.*/ |
||
/*╔═════════════════════════════════════════════════════════════╗ |
/*╔═════════════════════════════════════════════════════════════╗ |
||
Line 5,713: | Line 8,450: | ||
end |
end |
||
if n==0 then return ackermann(m-1, 1) |
if n==0 then return ackermann(m-1, 1) |
||
return ackermann(m-1, ackermann(m, n-1) )</ |
return ackermann(m-1, ackermann(m, n-1) )</syntaxhighlight> |
||
Output note: none of the numbers shown below use recursion to compute. |
Output note: <u>none</u> of the numbers shown below use recursion to compute. |
||
{{out|output|text= when using the internal default input:}} |
|||
'''output''' |
|||
<pre style="height:60ex"> |
<pre style="height:60ex"> |
||
Ackermann(0, 0)= 1 calls= 1 |
Ackermann(0, 0)= 1 calls= 1 |
||
Line 5,798: | Line 8,535: | ||
Ackermann(4, 2)=89506130880933368E+19728 calls= 1 |
Ackermann(4, 2)=89506130880933368E+19728 calls= 1 |
||
</pre> |
</pre> |
||
The last value is correct in magnitude, but not in value (only last digits plus exponent). Some other entries and Wikipedia give 2.0035...E+19728.<br> |
|||
But leaving out the formatting and running with 20000 digits, the last value is correct shown in its full 19728 digits. <br> |
|||
By the way, this version does not illustrate recursion anymore, because all workable values are captured as special values. Ackermann(4,2) = 2^65536-3 (19768 digits) and Ackerman(4,3) = 2^(2^65536)-3, far beyond REXX' (and other languages) capabilities in expressing numbers. |
|||
=={{header|Ring}}== |
=={{header|Ring}}== |
||
{{trans|C#}} |
{{trans|C#}} |
||
< |
<syntaxhighlight lang="ring">for m = 0 to 3 |
||
for n = 0 to 4 |
for n = 0 to 4 |
||
see "Ackermann(" + m + ", " + n + ") = " + Ackermann(m, n) + nl |
see "Ackermann(" + m + ", " + n + ") = " + Ackermann(m, n) + nl |
||
Line 5,819: | Line 8,559: | ||
ok |
ok |
||
ok |
ok |
||
Raise("Incorrect Numerical input !!!") </ |
Raise("Incorrect Numerical input !!!") </syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>Ackermann(0, 0) = 1 |
<pre>Ackermann(0, 0) = 1 |
||
Line 5,841: | Line 8,581: | ||
Ackermann(3, 3) = 61 |
Ackermann(3, 3) = 61 |
||
Ackermann(3, 4) = 125</pre> |
Ackermann(3, 4) = 125</pre> |
||
=={{header|RISC-V Assembly}}== |
|||
the basic recursive function, because memorization and other improvements would blow the clarity. |
|||
<syntaxhighlight lang="risc-v">ackermann: #x: a1, y: a2, return: a0 |
|||
beqz a1, npe #case m = 0 |
|||
beqz a2, mme #case m > 0 & n = 0 |
|||
addi sp, sp, -8 #case m > 0 & n > 0 |
|||
sw ra, 4(sp) |
|||
sw a1, 0(sp) |
|||
addi a2, a2, -1 |
|||
jal ackermann |
|||
lw a1, 0(sp) |
|||
addi a1, a1, -1 |
|||
mv a2, a0 |
|||
jal ackermann |
|||
lw t0, 4(sp) |
|||
addi sp, sp, 8 |
|||
jr t0, 0 |
|||
npe: |
|||
addi a0, a2, 1 |
|||
jr ra, 0 |
|||
mme: |
|||
addi sp, sp, -4 |
|||
sw ra, 0(sp) |
|||
addi a1, a1, -1 |
|||
li a2, 1 |
|||
jal ackermann |
|||
lw t0, 0(sp) |
|||
addi sp, sp, 4 |
|||
jr t0, 0 |
|||
</syntaxhighlight> |
|||
=={{header|RPL}}== |
|||
{{works with|RPL|HP49-C}} |
|||
« '''CASE''' |
|||
OVER NOT '''THEN''' NIP 1 + '''END''' |
|||
DUP NOT '''THEN''' DROP 1 - 1 <span style="color:blue">ACKER</span> '''END''' |
|||
OVER 1 - ROT ROT 1 - <span style="color:blue">ACKER</span> <span style="color:blue">ACKER</span> |
|||
'''END''' |
|||
» '<span style="color:blue">ACKER</span>' STO |
|||
3 4 <span style="color:blue">ACKER</span> |
|||
{{out}} |
|||
<pre> |
|||
1: 125 |
|||
</pre> |
|||
Runs in 7 min 13 secs on a HP-50g. Speed could be increased by replacing every <code>1</code> by <code>1.</code>, which would force calculations to be made with floating-point numbers, but we would then lose the arbitrary precision. |
|||
=={{header|Ruby}}== |
=={{header|Ruby}}== |
||
{{trans|Ada}} |
{{trans|Ada}} |
||
< |
<syntaxhighlight lang="ruby">def ack(m, n) |
||
if m == 0 |
if m == 0 |
||
n + 1 |
n + 1 |
||
Line 5,852: | Line 8,639: | ||
ack(m-1, ack(m, n-1)) |
ack(m-1, ack(m, n-1)) |
||
end |
end |
||
end</ |
end</syntaxhighlight> |
||
Example: |
Example: |
||
< |
<syntaxhighlight lang="ruby">(0..3).each do |m| |
||
puts (0..6).map { |n| ack(m, n) }.join(' ') |
puts (0..6).map { |n| ack(m, n) }.join(' ') |
||
end</ |
end</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> 1 2 3 4 5 6 7 |
<pre> 1 2 3 4 5 6 7 |
||
Line 5,864: | Line 8,651: | ||
=={{header|Run BASIC}}== |
=={{header|Run BASIC}}== |
||
< |
<syntaxhighlight lang="runbasic">print ackermann(1, 2) |
||
function ackermann(m, n) |
function ackermann(m, n) |
||
Line 5,870: | Line 8,657: | ||
if (m > 0) and (n = 0) then ackermann = ackermann((m - 1), 1) |
if (m > 0) and (n = 0) then ackermann = ackermann((m - 1), 1) |
||
if (m > 0) and (n > 0) then ackermann = ackermann((m - 1), ackermann(m, (n - 1))) |
if (m > 0) and (n > 0) then ackermann = ackermann((m - 1), ackermann(m, (n - 1))) |
||
end function</ |
end function</syntaxhighlight> |
||
=={{header|Rust}}== |
=={{header|Rust}}== |
||
< |
<syntaxhighlight lang="rust">fn ack(m: isize, n: isize) -> isize { |
||
if m == 0 { |
if m == 0 { |
||
n + 1 |
n + 1 |
||
Line 5,887: | Line 8,674: | ||
println!("{}", a); // 125 |
println!("{}", a); // 125 |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
Or: |
Or: |
||
< |
<syntaxhighlight lang="rust"> |
||
fn ack(m: u64, n: u64) -> u64 { |
fn ack(m: u64, n: u64) -> u64 { |
||
match (m, n) { |
match (m, n) { |
||
Line 5,899: | Line 8,686: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Sather}}== |
=={{header|Sather}}== |
||
< |
<syntaxhighlight lang="sather">class MAIN is |
||
ackermann(m, n:INT):INT |
ackermann(m, n:INT):INT |
||
Line 5,920: | Line 8,707: | ||
end; |
end; |
||
end; |
end; |
||
end;</ |
end;</syntaxhighlight> |
||
Instead of <code>INT</code>, the class <code>INTI</code> could be used, even though we need to use a workaround since in the GNU Sather v1.2.3 compiler the INTI literals are not implemented yet. |
Instead of <code>INT</code>, the class <code>INTI</code> could be used, even though we need to use a workaround since in the GNU Sather v1.2.3 compiler the INTI literals are not implemented yet. |
||
< |
<syntaxhighlight lang="sather">class MAIN is |
||
ackermann(m, n:INTI):INTI is |
ackermann(m, n:INTI):INTI is |
||
Line 5,940: | Line 8,727: | ||
end; |
end; |
||
end; |
end; |
||
end;</ |
end;</syntaxhighlight> |
||
=={{header|Scala}}== |
=={{header|Scala}}== |
||
<lang scala>def ack(m: BigInt, n: BigInt): BigInt = { |
|||
<syntaxhighlight lang="scala">def ack(m: BigInt, n: BigInt): BigInt = { |
|||
if (m==0) n+1 |
if (m==0) n+1 |
||
else if (n==0) ack(m-1, 1) |
else if (n==0) ack(m-1, 1) |
||
else ack(m-1, ack(m, n-1)) |
else ack(m-1, ack(m, n-1)) |
||
}</ |
}</syntaxhighlight> |
||
{{out|Example}} |
{{out|Example}} |
||
<pre> |
|||
<lang scala>scala> for ( m <- 0 to 3; n <- 0 to 6 ) yield ack(m,n) |
|||
scala> for ( m <- 0 to 3; n <- 0 to 6 ) yield ack(m,n) |
|||
res0: Seq.Projection[BigInt] = RangeG(1, 2, 3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 7, 8, 3, 5, 7, 9, 11, 13, 15, 5, 13, 29, 61, 125, 253, 509)</lang> |
|||
res0: Seq.Projection[BigInt] = RangeG(1, 2, 3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 7, 8, 3, 5, 7, 9, 11, 13, 15, 5, 13, 29, 61, 125, 253, 509) |
|||
{{field attention|Scala|Scala programming: Stream|The following part of this "heavily recursive"??? is a way too complex solution and displays not the idiom of Scala. Memoization is by Stream (Last lesson of the Coursera course "Functional Programming Principles in Scala") which is much simpler and displays the power of the language.}}I saw that this was one of the problems that needed an implementation in Scala, but when I made it, there was already one. |
|||
</pre> |
|||
But because ackerman is heavy recursive, I implemented it with memoization. So I still post it. |
|||
Memoized version using a mutable hash map: |
|||
<syntaxhighlight lang="scala">val ackMap = new mutable.HashMap[(BigInt,BigInt),BigInt] |
|||
Could still be done better, but that I leave to the reader. ;-) |
|||
def ackMemo(m: BigInt, n: BigInt): BigInt = { |
|||
ackMap.getOrElseUpdate((m,n), ack(m,n)) |
|||
<lang scala>val maxDepth = 4 |
|||
}</syntaxhighlight> |
|||
val ackMMap = scala.collection.mutable.Map[BigInt, BigInt]() |
|||
val ackNMaps = Array.fill(maxDepth + 1) { scala.collection.mutable.Map[BigInt, BigInt]() } |
|||
def ack(m: Int, n: BigInt): BigInt = { |
|||
if ((m < 0) || (n < 0)) { |
|||
throw new Exception("Negative parameters are not allowed: ack(%s, %s)".format(m, n)) |
|||
} |
|||
if (m > maxDepth) { |
|||
throw new Exception("First parameter is greater as %s: ack(%s, %s)".format(maxDepth, m, n)) |
|||
} |
|||
val newM = m - 1 |
|||
val newN = n - 1 |
|||
if (m == 0) { |
|||
n + 1 |
|||
} else if (n == 0) { |
|||
ackMMap.getOrElseUpdate(newM, ack(newM, 1)) |
|||
} else { |
|||
val createStep = 125 |
|||
val index = m |
|||
val mapCurrent = ackNMaps(index) |
|||
val mapPrevious = ackNMaps(index - 1) |
|||
val maxRecursion = 2 * createStep |
|||
val nrOfElements : BigInt = if (mapCurrent.isEmpty) 0 else mapCurrent.max._1 |
|||
if ((nrOfElements + maxRecursion) < n) { |
|||
for (i <- nrOfElements + createStep to n by createStep) { |
|||
mapCurrent.getOrElseUpdate(i, ack(m, i)) |
|||
} |
|||
} |
|||
mapCurrent.getOrElseUpdate(n, { |
|||
val ackVal = mapCurrent.getOrElseUpdate(newN, ack(m, newN)) |
|||
mapPrevious.getOrElseUpdate(ackVal, ack(newM, ackVal)) |
|||
}) |
|||
} |
|||
} |
|||
</lang> |
|||
One important optimization is: |
|||
<lang scala> if ((nrOfElements + maxRecursion) < n) { |
|||
for (i <- nrOfElements + createStep to n by createStep) { |
|||
mapCurrent.getOrElseUpdate(i, ack(m, i)) |
|||
} |
|||
} |
|||
</lang> |
|||
The recursion with ackermann can become very deep indeed. In this way it is still calculable without needing a very big stack. And because memoization is used, you circumvent a stack overflow without a (real) cost. |
|||
=={{header|Scheme}}== |
=={{header|Scheme}}== |
||
< |
<syntaxhighlight lang="scheme">(define (A m n) |
||
(cond |
(cond |
||
((= m 0) (+ n 1)) |
((= m 0) (+ n 1)) |
||
((= n 0) (A (- m 1) 1)) |
((= n 0) (A (- m 1) 1)) |
||
(else (A (- m 1) (A m (- n 1))))))</ |
(else (A (- m 1) (A m (- n 1))))))</syntaxhighlight> |
||
An improved solution that uses a lazy data structure, streams, and defines [[Knuth up-arrow]]s to calculate iterative exponentiation: |
|||
<syntaxhighlight lang="scheme">(define (A m n) |
|||
(letrec ((A-stream |
|||
(cons-stream |
|||
(ints-from 1) ;; m = 0 |
|||
(cons-stream |
|||
(ints-from 2) ;; m = 1 |
|||
(cons-stream |
|||
;; m = 2 |
|||
(stream-map (lambda (n) |
|||
(1+ (* 2 (1+ n)))) |
|||
(ints-from 0)) |
|||
(cons-stream |
|||
;; m = 3 |
|||
(stream-map (lambda (n) |
|||
(- (knuth-up-arrow 2 (- m 2) (+ n 3)) 3)) |
|||
(ints-from 0)) |
|||
;; m = 4... |
|||
(stream-tail A-stream 3))))))) |
|||
(stream-ref (stream-ref A-stream m) n))) |
|||
(define (ints-from n) |
|||
(letrec ((ints-rec (cons-stream n (stream-map 1+ ints-rec)))) |
|||
ints-rec)) |
|||
(define (knuth-up-arrow a n b) |
|||
(let loop ((n n) (b b)) |
|||
(cond ((= b 0) 1) |
|||
((= n 1) (expt a b)) |
|||
(else (loop (-1+ n) (loop n (-1+ b)))))))</syntaxhighlight> |
|||
=={{header|Scilab}}== |
=={{header|Scilab}}== |
||
<lang>clear |
<syntaxhighlight lang="text">clear |
||
function acker=ackermann(m,n) |
function acker=ackermann(m,n) |
||
global calls |
global calls |
||
Line 6,036: | Line 8,809: | ||
printacker(i,j) |
printacker(i,j) |
||
end |
end |
||
end</ |
end</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre style="height:20ex">ackermann(0,0)=1 calls=1 |
<pre style="height:20ex">ackermann(0,0)=1 calls=1 |
||
Line 6,068: | Line 8,841: | ||
=={{header|Seed7}}== |
=={{header|Seed7}}== |
||
===Basic version=== |
|||
<lang seed7>const func integer: ackermann (in integer: m, in integer: n) is func |
|||
<syntaxhighlight lang="seed7">const func integer: ackermann (in integer: m, in integer: n) is func |
|||
result |
result |
||
var integer: result is 0; |
var integer: result is 0; |
||
Line 6,079: | Line 8,853: | ||
result := ackermann(pred(m), ackermann(m, pred(n))); |
result := ackermann(pred(m), ackermann(m, pred(n))); |
||
end if; |
end if; |
||
end func;</ |
end func;</syntaxhighlight> |
||
Original source: [http://seed7.sourceforge.net/algorith/math.htm#ackermann] |
Original source: [http://seed7.sourceforge.net/algorith/math.htm#ackermann] |
||
===Improved version=== |
|||
<syntaxhighlight lang="seed7">$ include "seed7_05.s7i"; |
|||
include "bigint.s7i"; |
|||
const func bigInteger: ackermann (in bigInteger: m, in bigInteger: n) is func |
|||
result |
|||
var bigInteger: ackermann is 0_; |
|||
begin |
|||
case m of |
|||
when {0_}: ackermann := succ(n); |
|||
when {1_}: ackermann := n + 2_; |
|||
when {2_}: ackermann := 3_ + 2_ * n; |
|||
when {3_}: ackermann := 5_ + 8_ * pred(2_ ** ord(n)); |
|||
otherwise: |
|||
if n = 0_ then |
|||
ackermann := ackermann(pred(m), 1_); |
|||
else |
|||
ackermann := ackermann(pred(m), ackermann(m, pred(n))); |
|||
end if; |
|||
end case; |
|||
end func; |
|||
const proc: main is func |
|||
local |
|||
var bigInteger: m is 0_; |
|||
var bigInteger: n is 0_; |
|||
var string: stri is ""; |
|||
begin |
|||
for m range 0_ to 3_ do |
|||
for n range 0_ to 9_ do |
|||
writeln("A(" <& m <& ", " <& n <& ") = " <& ackermann(m, n)); |
|||
end for; |
|||
end for; |
|||
writeln("A(4, 0) = " <& ackermann(4_, 0_)); |
|||
writeln("A(4, 1) = " <& ackermann(4_, 1_)); |
|||
stri := str(ackermann(4_, 2_)); |
|||
writeln("A(4, 2) = (" <& length(stri) <& " digits)"); |
|||
writeln(stri[1 len 80]); |
|||
writeln("..."); |
|||
writeln(stri[length(stri) - 79 ..]); |
|||
end func;</syntaxhighlight> |
|||
Original source: [https://seed7.sourceforge.net/algorith/math.htm#bigInteger_ackermann] |
|||
{{out}} |
|||
<pre> |
|||
A(0, 0) = 1 |
|||
A(0, 1) = 2 |
|||
A(0, 2) = 3 |
|||
A(0, 3) = 4 |
|||
A(0, 4) = 5 |
|||
A(0, 5) = 6 |
|||
A(0, 6) = 7 |
|||
A(0, 7) = 8 |
|||
A(0, 8) = 9 |
|||
A(0, 9) = 10 |
|||
A(1, 0) = 2 |
|||
A(1, 1) = 3 |
|||
A(1, 2) = 4 |
|||
A(1, 3) = 5 |
|||
A(1, 4) = 6 |
|||
A(1, 5) = 7 |
|||
A(1, 6) = 8 |
|||
A(1, 7) = 9 |
|||
A(1, 8) = 10 |
|||
A(1, 9) = 11 |
|||
A(2, 0) = 3 |
|||
A(2, 1) = 5 |
|||
A(2, 2) = 7 |
|||
A(2, 3) = 9 |
|||
A(2, 4) = 11 |
|||
A(2, 5) = 13 |
|||
A(2, 6) = 15 |
|||
A(2, 7) = 17 |
|||
A(2, 8) = 19 |
|||
A(2, 9) = 21 |
|||
A(3, 0) = 5 |
|||
A(3, 1) = 13 |
|||
A(3, 2) = 29 |
|||
A(3, 3) = 61 |
|||
A(3, 4) = 125 |
|||
A(3, 5) = 253 |
|||
A(3, 6) = 509 |
|||
A(3, 7) = 1021 |
|||
A(3, 8) = 2045 |
|||
A(3, 9) = 4093 |
|||
A(4, 0) = 13 |
|||
A(4, 1) = 65533 |
|||
A(4, 2) = (19729 digits) |
|||
20035299304068464649790723515602557504478254755697514192650169737108940595563114 |
|||
... |
|||
84717124577965048175856395072895337539755822087777506072339445587895905719156733 |
|||
</pre> |
|||
=={{header|SETL}}== |
=={{header|SETL}}== |
||
< |
<syntaxhighlight lang="setl">program ackermann; |
||
(for m in [0..3]) |
(for m in [0..3]) |
||
Line 6,093: | Line 8,959: | ||
end proc; |
end proc; |
||
end program;</ |
end program;</syntaxhighlight> |
||
=={{header|Shen}}== |
=={{header|Shen}}== |
||
< |
<syntaxhighlight lang="shen">(define ack |
||
0 N -> (+ N 1) |
0 N -> (+ N 1) |
||
M 0 -> (ack (- M 1) 1) |
M 0 -> (ack (- M 1) 1) |
||
M N -> (ack (- M 1) |
M N -> (ack (- M 1) |
||
(ack M (- N 1))))</ |
(ack M (- N 1))))</syntaxhighlight> |
||
=={{header|Sidef}}== |
=={{header|Sidef}}== |
||
< |
<syntaxhighlight lang="ruby">func A(m, n) { |
||
m == 0 ? (n + 1) |
m == 0 ? (n + 1) |
||
: (n == 0 ? (A(m - 1, 1)) |
: (n == 0 ? (A(m - 1, 1)) |
||
: (A(m - 1, A(m, n - 1)))); |
: (A(m - 1, A(m, n - 1)))); |
||
}</ |
}</syntaxhighlight> |
||
Alternatively, using multiple dispatch: |
Alternatively, using multiple dispatch: |
||
< |
<syntaxhighlight lang="ruby">func A((0), n) { n + 1 } |
||
func A(m, (0)) { A(m - 1, 1) } |
func A(m, (0)) { A(m - 1, 1) } |
||
func A(m, n) { A(m-1, A(m, n-1)) }</ |
func A(m, n) { A(m-1, A(m, n-1)) }</syntaxhighlight> |
||
Calling the function: |
Calling the function: |
||
< |
<syntaxhighlight lang="ruby">say A(3, 2); # prints: 29</syntaxhighlight> |
||
=={{header|Simula}}== |
=={{header|Simula}}== |
||
as modified by R. Péter and R. Robinson: |
as modified by R. Péter and R. Robinson: |
||
< |
<syntaxhighlight lang="simula"> BEGIN |
||
INTEGER procedure |
INTEGER procedure |
||
Ackermann(g, p); SHORT INTEGER g, p; |
Ackermann(g, p); SHORT INTEGER g, p; |
||
Line 6,131: | Line 8,999: | ||
outint(Ackermann(g, p), 0); outimage |
outint(Ackermann(g, p), 0); outimage |
||
END |
END |
||
END</ |
END</syntaxhighlight> |
||
{{Output}} |
{{Output}} |
||
<pre>Ackermann(4, 0) = 13 |
<pre>Ackermann(4, 0) = 13 |
||
Line 6,141: | Line 9,009: | ||
=={{header|Slate}}== |
=={{header|Slate}}== |
||
< |
<syntaxhighlight lang="slate">m@(Integer traits) ackermann: n@(Integer traits) |
||
[ |
[ |
||
m isZero |
m isZero |
||
Line 6,149: | Line 9,017: | ||
ifTrue: [m - 1 ackermann: n] |
ifTrue: [m - 1 ackermann: n] |
||
ifFalse: [m - 1 ackermann: (m ackermann: n - 1)]] |
ifFalse: [m - 1 ackermann: (m ackermann: n - 1)]] |
||
].</ |
].</syntaxhighlight> |
||
=={{header|Smalltalk}}== |
=={{header|Smalltalk}}== |
||
< |
<syntaxhighlight lang="smalltalk">|ackermann| |
||
ackermann := [ :n :m | |
ackermann := [ :n :m | |
||
(n = 0) ifTrue: [ (m + 1) ] |
(n = 0) ifTrue: [ (m + 1) ] |
||
Line 6,166: | Line 9,034: | ||
(ackermann value: 0 value: 0) displayNl. |
(ackermann value: 0 value: 0) displayNl. |
||
(ackermann value: 3 value: 4) displayNl.</ |
(ackermann value: 3 value: 4) displayNl.</syntaxhighlight> |
||
=={{header|SmileBASIC}}== |
|||
<syntaxhighlight lang="smilebasic">DEF ACK(M,N) |
|||
IF M==0 THEN |
|||
RETURN N+1 |
|||
ELSEIF M>0 AND N==0 THEN |
|||
RETURN ACK(M-1,1) |
|||
ELSE |
|||
RETURN ACK(M-1,ACK(M,N-1)) |
|||
ENDIF |
|||
END</syntaxhighlight> |
|||
=={{header|SNOBOL4}}== |
=={{header|SNOBOL4}}== |
||
{{works with|Macro Spitbol}} |
{{works with|Macro Spitbol}} |
||
Both Snobol4+ and CSnobol stack overflow, at ack(3,3) and ack(3,4), respectively. |
Both Snobol4+ and CSnobol stack overflow, at ack(3,3) and ack(3,4), respectively. |
||
< |
<syntaxhighlight lang="snobol4">define('ack(m,n)') :(ack_end) |
||
ack ack = eq(m,0) n + 1 :s(return) |
ack ack = eq(m,0) n + 1 :s(return) |
||
ack = eq(n,0) ack(m - 1,1) :s(return) |
ack = eq(n,0) ack(m - 1,1) :s(return) |
||
Line 6,182: | Line 9,061: | ||
output = str; str = '' |
output = str; str = '' |
||
n = 0; m = lt(m,3) m + 1 :s(L1) |
n = 0; m = lt(m,3) m + 1 :s(L1) |
||
end</ |
end</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>1 2 3 4 5 6 7 |
<pre>1 2 3 4 5 6 7 |
||
Line 6,188: | Line 9,067: | ||
3 5 7 9 11 13 15 |
3 5 7 9 11 13 15 |
||
5 13 29 61 125 253 509</pre> |
5 13 29 61 125 253 509</pre> |
||
=={{header|SNUSP}}== |
|||
<syntaxhighlight lang="snusp"> /==!/==atoi=@@@-@-----# |
|||
| | Ackermann function |
|||
| | /=========\!==\!====\ recursion: |
|||
$,@/>,@/==ack=!\?\<+# | | | A(0,j) -> j+1 |
|||
j i \<?\+>-@/# | | A(i,0) -> A(i-1,1) |
|||
\@\>@\->@/@\<-@/# A(i,j) -> A(i-1,A(i,j-1)) |
|||
| | | |
|||
# # | | | /+<<<-\ |
|||
/-<<+>>\!=/ \=====|==!/========?\>>>=?/<<# |
|||
? ? | \<<<+>+>>-/ |
|||
\>>+<<-/!==========/ |
|||
# #</syntaxhighlight> |
|||
One could employ [[:Category:Recursion|tail recursion]] elimination by replacing "@/#" with "/" in two places above. |
|||
=={{header|SPAD}}== |
=={{header|SPAD}}== |
||
{{works with|FriCAS, OpenAxiom, Axiom}} |
{{works with|FriCAS, OpenAxiom, Axiom}} |
||
<syntaxhighlight lang="spad"> |
|||
<lang SPAD> |
|||
NNI ==> NonNegativeInteger |
NNI ==> NonNegativeInteger |
||
Line 6,203: | Line 9,097: | ||
-- Example |
-- Example |
||
matrix [[A(i,j) for i in 0..3] for j in 0..3] |
matrix [[A(i,j) for i in 0..3] for j in 0..3] |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
Line 6,218: | Line 9,112: | ||
</pre> |
</pre> |
||
=={{header| |
=={{header|SQL PL}}== |
||
{{works with|Db2 LUW}} version 9.7 or higher. |
|||
<lang snusp> /==!/==atoi=@@@-@-----# |
|||
With SQL PL: |
|||
| | Ackermann function |
|||
<syntaxhighlight lang="sql pl"> |
|||
| | /=========\!==\!====\ recursion: |
|||
--#SET TERMINATOR @ |
|||
$,@/>,@/==ack=!\?\<+# | | | A(0,j) -> j+1 |
|||
j i \<?\+>-@/# | | A(i,0) -> A(i-1,1) |
|||
SET SERVEROUTPUT ON@ |
|||
\@\>@\->@/@\<-@/# A(i,j) -> A(i-1,A(i,j-1)) |
|||
| | | |
|||
CREATE OR REPLACE FUNCTION ACKERMANN( |
|||
# # | | | /+<<<-\ |
|||
IN M SMALLINT, |
|||
/-<<+>>\!=/ \=====|==!/========?\>>>=?/<<# |
|||
IN N BIGINT |
|||
? ? | \<<<+>+>>-/ |
|||
) RETURNS BIGINT |
|||
\>>+<<-/!==========/ |
|||
BEGIN |
|||
# #</lang> |
|||
DECLARE RET BIGINT; |
|||
One could employ [[:Category:Recursion|tail recursion]] elimination by replacing "@/#" with "/" in two places above. |
|||
DECLARE STMT STATEMENT; |
|||
IF (M = 0) THEN |
|||
SET RET = N + 1; |
|||
ELSEIF (N = 0) THEN |
|||
PREPARE STMT FROM 'SET ? = ACKERMANN(? - 1, 1)'; |
|||
EXECUTE STMT INTO RET USING M; |
|||
ELSE |
|||
PREPARE STMT FROM 'SET ? = ACKERMANN(? - 1, ACKERMANN(?, ? - 1))'; |
|||
EXECUTE STMT INTO RET USING M, M, N; |
|||
END IF; |
|||
RETURN RET; |
|||
END @ |
|||
BEGIN |
|||
DECLARE M SMALLINT DEFAULT 0; |
|||
DECLARE N SMALLINT DEFAULT 0; |
|||
DECLARE MAX_LEVELS CONDITION FOR SQLSTATE '54038'; |
|||
DECLARE CONTINUE HANDLER FOR MAX_LEVELS BEGIN END; |
|||
WHILE (N <= 6) DO |
|||
WHILE (M <= 3) DO |
|||
CALL DBMS_OUTPUT.PUT_LINE('ACKERMANN(' || M || ', ' || N || ') = ' || ACKERMANN(M, N)); |
|||
SET M = M + 1; |
|||
END WHILE; |
|||
SET M = 0; |
|||
SET N = N + 1; |
|||
END WHILE; |
|||
END @ |
|||
</syntaxhighlight> |
|||
Output: |
|||
<pre> |
|||
db2 -td@ |
|||
db2 => CREATE OR REPLACE FUNCTION ACKERMANN( |
|||
... |
|||
db2 (cont.) => END @ |
|||
DB20000I The SQL command completed successfully. |
|||
db2 => BEGIN |
|||
db2 (cont.) => END |
|||
... |
|||
DB20000I The SQL command completed successfully. |
|||
ACKERMANN(0, 0) = 1 |
|||
ACKERMANN(1, 0) = 2 |
|||
ACKERMANN(2, 0) = 3 |
|||
ACKERMANN(3, 0) = 5 |
|||
ACKERMANN(0, 1) = 2 |
|||
ACKERMANN(1, 1) = 3 |
|||
ACKERMANN(2, 1) = 5 |
|||
ACKERMANN(3, 1) = 13 |
|||
ACKERMANN(0, 2) = 3 |
|||
ACKERMANN(1, 2) = 4 |
|||
ACKERMANN(2, 2) = 7 |
|||
ACKERMANN(3, 2) = 29 |
|||
ACKERMANN(0, 3) = 4 |
|||
ACKERMANN(1, 3) = 5 |
|||
ACKERMANN(2, 3) = 9 |
|||
ACKERMANN(3, 3) = 61 |
|||
ACKERMANN(0, 4) = 5 |
|||
ACKERMANN(1, 4) = 6 |
|||
ACKERMANN(2, 4) = 11 |
|||
ACKERMANN(0, 5) = 6 |
|||
ACKERMANN(1, 5) = 7 |
|||
ACKERMANN(2, 5) = 13 |
|||
ACKERMANN(0, 6) = 7 |
|||
ACKERMANN(1, 6) = 8 |
|||
ACKERMANN(2, 6) = 15 |
|||
</pre> |
|||
The maximum levels of cascade calls in Db2 are 16, and in some cases when executing the Ackermann function, it arrives to this limit (SQL0724N). Thus, the code catches the exception and continues with the next try. |
|||
=={{header|Standard ML}}== |
=={{header|Standard ML}}== |
||
< |
<syntaxhighlight lang="sml">fun a (0, n) = n+1 |
||
| a (m, 0) = a (m-1, 1) |
| a (m, 0) = a (m-1, 1) |
||
| a (m, n) = a (m-1, a (m, n-1))</ |
| a (m, n) = a (m-1, a (m, n-1))</syntaxhighlight> |
||
=={{header|Stata}}== |
=={{header|Stata}}== |
||
< |
<syntaxhighlight lang="stata">mata |
||
function ackermann(m,n) { |
function ackermann(m,n) { |
||
if (m==0) { |
if (m==0) { |
||
Line 6,255: | Line 9,219: | ||
11 |
11 |
||
125 |
125 |
||
end</ |
end</syntaxhighlight> |
||
=={{header|Swift}}== |
=={{header|Swift}}== |
||
< |
<syntaxhighlight lang="swift">func ackerman(m:Int, n:Int) -> Int { |
||
if m == 0 { |
if m == 0 { |
||
return n+1 |
return n+1 |
||
Line 6,266: | Line 9,230: | ||
return ackerman(m-1, ackerman(m, n-1)) |
return ackerman(m-1, ackerman(m, n-1)) |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
||
===Simple=== |
===Simple=== |
||
{{trans|Ruby}} |
{{trans|Ruby}} |
||
< |
<syntaxhighlight lang="tcl">proc ack {m n} { |
||
if {$m == 0} { |
if {$m == 0} { |
||
expr {$n + 1} |
expr {$n + 1} |
||
Line 6,279: | Line 9,243: | ||
ack [expr {$m - 1}] [ack $m [expr {$n - 1}]] |
ack [expr {$m - 1}] [ack $m [expr {$n - 1}]] |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
===With Tail Recursion=== |
===With Tail Recursion=== |
||
With Tcl 8.6, this version is preferred (though the language supports tailcall optimization, it does not apply it automatically in order to preserve stack frame semantics): |
With Tcl 8.6, this version is preferred (though the language supports tailcall optimization, it does not apply it automatically in order to preserve stack frame semantics): |
||
< |
<syntaxhighlight lang="tcl">proc ack {m n} { |
||
if {$m == 0} { |
if {$m == 0} { |
||
expr {$n + 1} |
expr {$n + 1} |
||
Line 6,290: | Line 9,254: | ||
tailcall ack [expr {$m - 1}] [ack $m [expr {$n - 1}]] |
tailcall ack [expr {$m - 1}] [ack $m [expr {$n - 1}]] |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
===To Infinity… and Beyond!=== |
===To Infinity… and Beyond!=== |
||
If we want to explore the higher reaches of the world of Ackermann's function, we need techniques to really cut the amount of computation being done. |
If we want to explore the higher reaches of the world of Ackermann's function, we need techniques to really cut the amount of computation being done. |
||
{{works with|Tcl|8.6}} |
{{works with|Tcl|8.6}} |
||
< |
<syntaxhighlight lang="tcl">package require Tcl 8.6 |
||
# A memoization engine, from http://wiki.tcl.tk/18152 |
# A memoization engine, from http://wiki.tcl.tk/18152 |
||
Line 6,348: | Line 9,312: | ||
# Some small tweaks... |
# Some small tweaks... |
||
interp recursionlimit {} 100000 |
interp recursionlimit {} 100000 |
||
interp alias {} ack {} cacheable ack</ |
interp alias {} ack {} cacheable ack</syntaxhighlight> |
||
But even with all this, you still run into problems calculating <math>\mathit{ack}(4,3)</math> as that's kind-of large… |
But even with all this, you still run into problems calculating <math>\mathit{ack}(4,3)</math> as that's kind-of large… |
||
=={{header|TSE SAL}}== |
|||
<lang TSESAL>// library: math: get: ackermann: recursive <description></description> <version>1.0.0.0.5</version> <version control></version control> (filenamemacro=getmaare.s) [kn, ri, tu, 27-12-2011 14:46:59] |
|||
INTEGER PROC FNMathGetAckermannRecursiveI( INTEGER mI, INTEGER nI ) |
|||
IF ( mI == 0 ) |
|||
RETURN( nI + 1 ) |
|||
ENDIF |
|||
IF ( nI == 0 ) |
|||
RETURN( FNMathGetAckermannRecursiveI( mI - 1, 1 ) ) |
|||
ENDIF |
|||
RETURN( FNMathGetAckermannRecursiveI( mI - 1, FNMathGetAckermannRecursiveI( mI, nI - 1 ) ) ) |
|||
END |
|||
PROC Main() |
|||
STRING s1[255] = "2" |
|||
STRING s2[255] = "3" |
|||
IF ( NOT ( Ask( "math: get: ackermann: recursive: m = ", s1, _EDIT_HISTORY_ ) ) AND ( Length( s1 ) > 0 ) ) RETURN() ENDIF |
|||
IF ( NOT ( Ask( "math: get: ackermann: recursive: n = ", s2, _EDIT_HISTORY_ ) ) AND ( Length( s2 ) > 0 ) ) RETURN() ENDIF |
|||
Message( FNMathGetAckermannRecursiveI( Val( s1 ), Val( s2 ) ) ) // gives e.g. 9 |
|||
END</lang> |
|||
=={{header|TI-83 BASIC}}== |
=={{header|TI-83 BASIC}}== |
||
Line 6,375: | Line 9,319: | ||
This program assumes the variables N and M are the arguments of the function, and that the list L1 is empty. It stores the result in the system variable ANS. (Program names can be no longer than 8 characters, so I had to truncate the function's name.) |
This program assumes the variables N and M are the arguments of the function, and that the list L1 is empty. It stores the result in the system variable ANS. (Program names can be no longer than 8 characters, so I had to truncate the function's name.) |
||
< |
<syntaxhighlight lang="ti83b">PROGRAM:ACKERMAN |
||
:If not(M |
:If not(M |
||
:Then |
:Then |
||
Line 6,395: | Line 9,339: | ||
:prgmACKERMAN |
:prgmACKERMAN |
||
:End |
:End |
||
:End</ |
:End</syntaxhighlight> |
||
Here is a handler function that makes the previous function easier to use. (You can name it whatever you want.) |
Here is a handler function that makes the previous function easier to use. (You can name it whatever you want.) |
||
< |
<syntaxhighlight lang="ti83b">PROGRAM:AHANDLER |
||
:0→dim(L1 |
:0→dim(L1 |
||
:Prompt M |
:Prompt M |
||
:Prompt N |
:Prompt N |
||
:prgmACKERMAN |
:prgmACKERMAN |
||
:Disp Ans</ |
:Disp Ans</syntaxhighlight> |
||
=={{header|TI-89 BASIC}}== |
=={{header|TI-89 BASIC}}== |
||
< |
<syntaxhighlight lang="ti89b">Define A(m,n) = when(m=0, n+1, when(n=0, A(m-1,1), A(m-1, A(m, n-1))))</syntaxhighlight> |
||
=={{header|TorqueScript}}== |
=={{header|TorqueScript}}== |
||
< |
<syntaxhighlight lang="torquescript">function ackermann(%m,%n) |
||
{ |
{ |
||
if(%m==0) |
if(%m==0) |
||
Line 6,418: | Line 9,362: | ||
if(%m>0&&%n>0) |
if(%m>0&&%n>0) |
||
return ackermann(%m-1,ackermann(%m,%n-1)); |
return ackermann(%m-1,ackermann(%m,%n-1)); |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Transd}}== |
|||
<syntaxhighlight lang="Scheme">#lang transd |
|||
MainModule: { |
|||
Ack: Lambda<Int Int Int>(λ m Int() n Int() |
|||
(if (not m) (ret (+ n 1))) |
|||
(if (not n) (ret (exec Ack (- m 1) 1))) |
|||
(ret (exec Ack (- m 1) (exec Ack m (- n 1)))) |
|||
), |
|||
_start: (λ (textout (exec Ack 3 1) "\n" |
|||
(exec Ack 3 2) "\n" |
|||
(exec Ack 3 3))) |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
13 |
|||
29 |
|||
61 |
|||
</pre> |
|||
=={{header|TSE SAL}}== |
|||
<syntaxhighlight lang="tsesal">// library: math: get: ackermann: recursive <description></description> <version>1.0.0.0.5</version> <version control></version control> (filenamemacro=getmaare.s) [kn, ri, tu, 27-12-2011 14:46:59] |
|||
INTEGER PROC FNMathGetAckermannRecursiveI( INTEGER mI, INTEGER nI ) |
|||
IF ( mI == 0 ) |
|||
RETURN( nI + 1 ) |
|||
ENDIF |
|||
IF ( nI == 0 ) |
|||
RETURN( FNMathGetAckermannRecursiveI( mI - 1, 1 ) ) |
|||
ENDIF |
|||
RETURN( FNMathGetAckermannRecursiveI( mI - 1, FNMathGetAckermannRecursiveI( mI, nI - 1 ) ) ) |
|||
END |
|||
PROC Main() |
|||
STRING s1[255] = "2" |
|||
STRING s2[255] = "3" |
|||
IF ( NOT ( Ask( "math: get: ackermann: recursive: m = ", s1, _EDIT_HISTORY_ ) ) AND ( Length( s1 ) > 0 ) ) RETURN() ENDIF |
|||
IF ( NOT ( Ask( "math: get: ackermann: recursive: n = ", s2, _EDIT_HISTORY_ ) ) AND ( Length( s2 ) > 0 ) ) RETURN() ENDIF |
|||
Message( FNMathGetAckermannRecursiveI( Val( s1 ), Val( s2 ) ) ) // gives e.g. 9 |
|||
END</syntaxhighlight> |
|||
=={{header|TXR}}== |
=={{header|TXR}}== |
||
Line 6,425: | Line 9,409: | ||
with memoization. |
with memoization. |
||
< |
<syntaxhighlight lang="txrlisp">(defmacro defmemofun (name (. args) . body) |
||
(let ((hash (gensym "hash-")) |
(let ((hash (gensym "hash-")) |
||
(argl (gensym "args-")) |
(argl (gensym "args-")) |
||
Line 6,446: | Line 9,430: | ||
(each ((i (range 0 3))) |
(each ((i (range 0 3))) |
||
(each ((j (range 0 4))) |
(each ((j (range 0 4))) |
||
(format t "ack(~a, ~a) = ~a\n" i j (ack i j))))</ |
(format t "ack(~a, ~a) = ~a\n" i j (ack i j))))</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 6,473: | Line 9,457: | ||
=={{header|UNIX Shell}}== |
=={{header|UNIX Shell}}== |
||
{{works with|Bash}} |
{{works with|Bash}} |
||
< |
<syntaxhighlight lang="bash">ack() { |
||
local m=$1 |
local m=$1 |
||
local n=$2 |
local n=$2 |
||
Line 6,483: | Line 9,467: | ||
ack $((m-1)) $(ack $m $((n-1))) |
ack $((m-1)) $(ack $m $((n-1))) |
||
fi |
fi |
||
}</ |
}</syntaxhighlight> |
||
Example: |
Example: |
||
< |
<syntaxhighlight lang="bash">for ((m=0;m<=3;m++)); do |
||
for ((n=0;n<=6;n++)); do |
for ((n=0;n<=6;n++)); do |
||
ack $m $n |
ack $m $n |
||
Line 6,491: | Line 9,475: | ||
done |
done |
||
echo |
echo |
||
done</ |
done</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>1 2 3 4 5 6 7 |
<pre>1 2 3 4 5 6 7 |
||
Line 6,497: | Line 9,481: | ||
3 5 7 9 11 13 15 |
3 5 7 9 11 13 15 |
||
5 13 29 61 125 253 509</pre> |
5 13 29 61 125 253 509</pre> |
||
=={{header|Ursalang}}== |
|||
<syntaxhighlight lang="ursalang">let A = fn(m, n) { |
|||
if m == 0 {n + 1} |
|||
else if m > 0 and n == 0 {A(m - 1, 1)} |
|||
else {A(m - 1, A(m, n - 1))} |
|||
} |
|||
print(A(0, 0)) |
|||
print(A(3, 4)) |
|||
print(A(3, 1))</syntaxhighlight> |
|||
=={{header|Ursala}}== |
=={{header|Ursala}}== |
||
Anonymous recursion is the usual way of doing things like this. |
Anonymous recursion is the usual way of doing things like this. |
||
< |
<syntaxhighlight lang="ursala">#import std |
||
#import nat |
#import nat |
||
Line 6,507: | Line 9,502: | ||
~&al^?\successor@ar ~&ar?( |
~&al^?\successor@ar ~&ar?( |
||
^R/~&f ^/predecessor@al ^|R/~& ^|/~& predecessor, |
^R/~&f ^/predecessor@al ^|R/~& ^|/~& predecessor, |
||
^|R/~& ~&\1+ predecessor@l)</ |
^|R/~& ~&\1+ predecessor@l)</syntaxhighlight> |
||
test program for the first 4 by 7 numbers: |
test program for the first 4 by 7 numbers: |
||
< |
<syntaxhighlight lang="ursala">#cast %nLL |
||
test = block7 ackermann*K0 iota~~/4 7</ |
test = block7 ackermann*K0 iota~~/4 7</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 6,522: | Line 9,517: | ||
=={{header|V}}== |
=={{header|V}}== |
||
{{trans|Joy}} |
{{trans|Joy}} |
||
< |
<syntaxhighlight lang="v">[ack |
||
[ [pop zero?] [popd succ] |
[ [pop zero?] [popd succ] |
||
[zero?] [pop pred 1 ack] |
[zero?] [pop pred 1 ack] |
||
[true] [[dup pred swap] dip pred ack ack ] |
[true] [[dup pred swap] dip pred ack ack ] |
||
] when].</ |
] when].</syntaxhighlight> |
||
using destructuring view |
using destructuring view |
||
< |
<syntaxhighlight lang="v">[ack |
||
[ [pop zero?] [ [m n : [n succ]] view i] |
[ [pop zero?] [ [m n : [n succ]] view i] |
||
[zero?] [ [m n : [m pred 1 ack]] view i] |
[zero?] [ [m n : [m pred 1 ack]] view i] |
||
[true] [ [m n : [m pred m n pred ack ack]] view i] |
[true] [ [m n : [m pred m n pred ack ack]] view i] |
||
] when].</ |
] when].</syntaxhighlight> |
||
=={{header|Vala}}== |
|||
<syntaxhighlight lang="vala">uint64 ackermann(uint64 m, uint64 n) { |
|||
if (m == 0) return n + 1; |
|||
if (n == 0) return ackermann(m - 1, 1); |
|||
return ackermann(m - 1, ackermann(m, n - 1)); |
|||
} |
|||
void main () { |
|||
for (uint64 m = 0; m < 4; ++m) { |
|||
for (uint64 n = 0; n < 10; ++n) { |
|||
print(@"A($m,$n) = $(ackermann(m,n))\n"); |
|||
} |
|||
} |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
A(0,0) = 1 |
|||
A(0,1) = 2 |
|||
A(0,2) = 3 |
|||
A(0,3) = 4 |
|||
A(0,4) = 5 |
|||
A(0,5) = 6 |
|||
A(0,6) = 7 |
|||
A(0,7) = 8 |
|||
A(0,8) = 9 |
|||
A(0,9) = 10 |
|||
A(1,0) = 2 |
|||
A(1,1) = 3 |
|||
A(1,2) = 4 |
|||
A(1,3) = 5 |
|||
A(1,4) = 6 |
|||
A(1,5) = 7 |
|||
A(1,6) = 8 |
|||
A(1,7) = 9 |
|||
A(1,8) = 10 |
|||
A(1,9) = 11 |
|||
A(2,0) = 3 |
|||
A(2,1) = 5 |
|||
A(2,2) = 7 |
|||
A(2,3) = 9 |
|||
A(2,4) = 11 |
|||
A(2,5) = 13 |
|||
A(2,6) = 15 |
|||
A(2,7) = 17 |
|||
A(2,8) = 19 |
|||
A(2,9) = 21 |
|||
A(3,0) = 5 |
|||
A(3,1) = 13 |
|||
A(3,2) = 29 |
|||
A(3,3) = 61 |
|||
A(3,4) = 125 |
|||
A(3,5) = 253 |
|||
A(3,6) = 509 |
|||
A(3,7) = 1021 |
|||
A(3,8) = 2045 |
|||
A(3,9) = 4093 |
|||
</pre> |
|||
=={{header|VBA}}== |
|||
<syntaxhighlight lang="vb">Private Function Ackermann_function(m As Variant, n As Variant) As Variant |
|||
Dim result As Variant |
|||
Debug.Assert m >= 0 |
|||
Debug.Assert n >= 0 |
|||
If m = 0 Then |
|||
result = CDec(n + 1) |
|||
Else |
|||
If n = 0 Then |
|||
result = Ackermann_function(m - 1, 1) |
|||
Else |
|||
result = Ackermann_function(m - 1, Ackermann_function(m, n - 1)) |
|||
End If |
|||
End If |
|||
Ackermann_function = CDec(result) |
|||
End Function |
|||
Public Sub main() |
|||
Debug.Print " n=", |
|||
For j = 0 To 7 |
|||
Debug.Print j, |
|||
Next j |
|||
Debug.Print |
|||
For i = 0 To 3 |
|||
Debug.Print "m=" & i, |
|||
For j = 0 To 7 |
|||
Debug.Print Ackermann_function(i, j), |
|||
Next j |
|||
Debug.Print |
|||
Next i |
|||
End Sub</syntaxhighlight>{{out}} |
|||
<pre> n= 0 1 2 3 4 5 6 7 |
|||
m=0 1 2 3 4 5 6 7 8 |
|||
m=1 2 3 4 5 6 7 8 9 |
|||
m=2 3 5 7 9 11 13 15 17 |
|||
m=3 5 13 29 61 125 253 509 1021 </pre> |
|||
=={{header|VBScript}}== |
=={{header|VBScript}}== |
||
Based on BASIC version. Uncomment all the lines referring to <code>depth</code> and see just how deep the recursion goes. |
Based on BASIC version. Uncomment all the lines referring to <code>depth</code> and see just how deep the recursion goes. |
||
;Implementation |
;Implementation |
||
< |
<syntaxhighlight lang="vb">option explicit |
||
'~ dim depth |
'~ dim depth |
||
function ack(m, n) |
function ack(m, n) |
||
Line 6,556: | Line 9,646: | ||
end if |
end if |
||
end function</ |
end function</syntaxhighlight> |
||
;Invocation |
;Invocation |
||
< |
<syntaxhighlight lang="vb">wscript.echo ack( 1, 10 ) |
||
'~ depth = 0 |
'~ depth = 0 |
||
wscript.echo ack( 2, 1 ) |
wscript.echo ack( 2, 1 ) |
||
'~ depth = 0 |
'~ depth = 0 |
||
wscript.echo ack( 4, 4 )</ |
wscript.echo ack( 4, 4 )</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 6,573: | Line 9,663: | ||
{{trans|Rexx}} |
{{trans|Rexx}} |
||
{{works with|Visual Basic|VB6 Standard}} |
{{works with|Visual Basic|VB6 Standard}} |
||
<syntaxhighlight lang="vb"> |
|||
<lang vb> |
|||
Option Explicit |
Option Explicit |
||
Dim calls As Long |
Dim calls As Long |
||
Line 6,602: | Line 9,692: | ||
End If |
End If |
||
End If |
End If |
||
End Function 'ackermann</ |
End Function 'ackermann</syntaxhighlight> |
||
{{Out}} |
{{Out}} |
||
<pre style="height:20ex">ackermann( 0 , 0 )= 1 calls= 1 |
<pre style="height:20ex">ackermann( 0 , 0 )= 1 calls= 1 |
||
Line 6,646: | Line 9,736: | ||
ackermann( 4 , 0 )= 13 calls= 107 |
ackermann( 4 , 0 )= 13 calls= 107 |
||
ackermann( 4 , 1 )= out of stack space</pre> |
ackermann( 4 , 1 )= out of stack space</pre> |
||
=={{header|V (Vlang)}}== |
|||
<syntaxhighlight lang="v">fn ackermann(m int, n int ) int { |
|||
if m == 0 { |
|||
return n + 1 |
|||
} |
|||
else if n == 0 { |
|||
return ackermann(m - 1, 1) |
|||
} |
|||
return ackermann(m - 1, ackermann(m, n - 1) ) |
|||
} |
|||
fn main() { |
|||
for m := 0; m <= 4; m++ { |
|||
for n := 0; n < ( 6 - m ); n++ { |
|||
println('Ackermann($m, $n) = ${ackermann(m, n)}') |
|||
} |
|||
} |
|||
} |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre>Ackermann(0, 0) = 1 |
|||
Ackermann(0, 1) = 2 |
|||
Ackermann(0, 2) = 3 |
|||
Ackermann(0, 3) = 4 |
|||
Ackermann(0, 4) = 5 |
|||
Ackermann(0, 5) = 6 |
|||
Ackermann(1, 0) = 2 |
|||
Ackermann(1, 1) = 3 |
|||
Ackermann(1, 2) = 4 |
|||
Ackermann(1, 3) = 5 |
|||
Ackermann(1, 4) = 6 |
|||
Ackermann(2, 0) = 3 |
|||
Ackermann(2, 1) = 5 |
|||
Ackermann(2, 2) = 7 |
|||
Ackermann(2, 3) = 9 |
|||
Ackermann(3, 0) = 5 |
|||
Ackermann(3, 1) = 13 |
|||
Ackermann(3, 2) = 29 |
|||
Ackermann(4, 0) = 13 |
|||
Ackermann(4, 1) = 65533 |
|||
</pre> |
|||
=={{header|Wart}}== |
=={{header|Wart}}== |
||
< |
<syntaxhighlight lang="wart">def (ackermann m n) |
||
(if m=0 |
(if m=0 |
||
n+1 |
n+1 |
||
Line 6,654: | Line 9,787: | ||
(ackermann m-1 1) |
(ackermann m-1 1) |
||
:else |
:else |
||
(ackermann m-1 (ackermann m n-1)))</ |
(ackermann m-1 (ackermann m n-1)))</syntaxhighlight> |
||
=={{header|WDTE}}== |
=={{header|WDTE}}== |
||
< |
<syntaxhighlight lang="wdte">let memo a m n => true { |
||
== m 0 => + n 1; |
== m 0 => + n 1; |
||
== n 0 => a (- m 1) 1; |
== n 0 => a (- m 1) 1; |
||
true => a (- m 1) (a m (- n 1)); |
|||
};</ |
};</syntaxhighlight> |
||
=={{header|Wren}}== |
=={{header|Wren}}== |
||
<syntaxhighlight lang="wren">// To use recursion definition and declaration must be on separate lines |
|||
<lang wren> |
|||
// To use recursion definition and declaration must be on separate lines |
|||
var Ackermann |
var Ackermann |
||
Ackermann = Fn.new {|m, n| |
Ackermann = Fn.new {|m, n| |
||
Line 6,673: | Line 9,805: | ||
} |
} |
||
var pairs = [ [1, 3], [2, 3], [3, 3], [1, 5], [2, 5], [3, 5] ] |
|||
</lang> |
|||
for (pair in pairs) { |
|||
var p1 = pair[0] |
|||
var p2 = pair[1] |
|||
System.print("A[%(p1), %(p2)] = %(Ackermann.call(p1, p2))") |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
A[1, 3] = 5 |
|||
A[2, 3] = 9 |
|||
A[3, 3] = 61 |
|||
A[1, 5] = 7 |
|||
A[2, 5] = 13 |
|||
A[3, 5] = 253 |
|||
</pre> |
|||
=={{header|X86 Assembly}}== |
|||
{{works with|nasm}} |
|||
{{works with|windows}} |
|||
<syntaxhighlight lang="asm"> |
|||
section .text |
|||
global _main |
|||
_main: |
|||
mov eax, 3 ;m |
|||
mov ebx, 4 ;n |
|||
call ack ;returns number in ebx |
|||
ret |
|||
ack: |
|||
cmp eax, 0 |
|||
je M0 ;if M == 0 |
|||
cmp ebx, 0 |
|||
je N0 ;if N == 0 |
|||
dec ebx ;else N-1 |
|||
push eax ;save M |
|||
call ack1 ;ack(m,n) -> returned in ebx so no further instructions needed |
|||
pop eax ;restore M |
|||
dec eax ;M - 1 |
|||
call ack1 ;return ack(m-1,ack(m,n-1)) |
|||
ret |
|||
M0: |
|||
inc ebx ;return n + 1 |
|||
ret |
|||
N0: |
|||
dec eax |
|||
inc ebx ;ebx always 0: inc -> ebx = 1 |
|||
call ack1 ;return ack(M-1,1) |
|||
ret |
|||
</syntaxhighlight> |
|||
=={{header|XLISP}}== |
=={{header|XLISP}}== |
||
< |
<syntaxhighlight lang="lisp">(defun ackermann (m n) |
||
(cond |
(cond |
||
((= m 0) (+ n 1)) |
((= m 0) (+ n 1)) |
||
((= n 0) (ackermann (- m 1) 1)) |
((= n 0) (ackermann (- m 1) 1)) |
||
(t (ackermann (- m 1) (ackermann m (- n 1))))))</ |
(t (ackermann (- m 1) (ackermann m (- n 1))))))</syntaxhighlight> |
||
Test it: |
Test it: |
||
< |
<syntaxhighlight lang="lisp">(print (ackermann 3 9))</syntaxhighlight> |
||
Output (after a very perceptible pause): |
Output (after a very perceptible pause): |
||
<pre>4093</pre> |
<pre>4093</pre> |
||
That worked well. Test it again: |
That worked well. Test it again: |
||
< |
<syntaxhighlight lang="lisp">(print (ackermann 4 1))</syntaxhighlight> |
||
Output (after another pause): |
Output (after another pause): |
||
<pre>Abort: control stack overflow |
<pre>Abort: control stack overflow |
||
Line 6,692: | Line 9,874: | ||
=={{header|XPL0}}== |
=={{header|XPL0}}== |
||
< |
<syntaxhighlight lang="xpl0">include c:\cxpl\codes; |
||
func Ackermann(M, N); |
func Ackermann(M, N); |
||
Line 6,707: | Line 9,889: | ||
CrLf(0); |
CrLf(0); |
||
]; |
]; |
||
]</ |
]</syntaxhighlight> |
||
Recursion overflows the stack if either M or N is extended by a single count. |
Recursion overflows the stack if either M or N is extended by a single count. |
||
{{out}} |
{{out}} |
||
Line 6,720: | Line 9,902: | ||
The following named template calculates the Ackermann function: |
The following named template calculates the Ackermann function: |
||
< |
<syntaxhighlight lang="xml"> |
||
<xsl:template name="ackermann"> |
<xsl:template name="ackermann"> |
||
<xsl:param name="m"/> |
<xsl:param name="m"/> |
||
Line 6,750: | Line 9,932: | ||
</xsl:choose> |
</xsl:choose> |
||
</xsl:template> |
</xsl:template> |
||
</syntaxhighlight> |
|||
</lang> |
|||
Here it is as part of a template |
Here it is as part of a template |
||
< |
<syntaxhighlight lang="xml"> |
||
<?xml version="1.0" encoding="UTF-8"?> |
<?xml version="1.0" encoding="UTF-8"?> |
||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> |
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> |
||
Line 6,799: | Line 9,981: | ||
</xsl:template> |
</xsl:template> |
||
</xsl:stylesheet> |
</xsl:stylesheet> |
||
</syntaxhighlight> |
|||
</lang> |
|||
Which will transform this input |
Which will transform this input |
||
< |
<syntaxhighlight lang="xml"> |
||
<?xml version="1.0" ?> |
<?xml version="1.0" ?> |
||
<?xml-stylesheet type="text/xsl" href="ackermann.xslt"?> |
<?xml-stylesheet type="text/xsl" href="ackermann.xslt"?> |
||
Line 6,951: | Line 10,133: | ||
</args> |
</args> |
||
</arguments> |
</arguments> |
||
</syntaxhighlight> |
|||
</lang> |
|||
into this output |
into this output |
||
Line 6,994: | Line 10,176: | ||
=={{header|Yabasic}}== |
=={{header|Yabasic}}== |
||
< |
<syntaxhighlight lang="yabasic">sub ack(M,N) |
||
if M = 0 return N + 1 |
if M = 0 return N + 1 |
||
if N = 0 return ack(M-1,1) |
if N = 0 return ack(M-1,1) |
||
Line 7,001: | Line 10,183: | ||
print ack(3, 4) |
print ack(3, 4) |
||
</syntaxhighlight> |
|||
</lang> |
|||
What smart code can get. Fast as lightning! |
|||
{{trans|Phix}} |
|||
<syntaxhighlight lang="yabasic">sub ack(m, n) |
|||
if m=0 then |
|||
return n+1 |
|||
elsif m=1 then |
|||
return n+2 |
|||
elsif m=2 then |
|||
return 2*n+3 |
|||
elsif m=3 then |
|||
return 2^(n+3)-3 |
|||
elsif m>0 and n=0 then |
|||
return ack(m-1,1) |
|||
else |
|||
return ack(m-1,ack(m,n-1)) |
|||
end if |
|||
end sub |
|||
sub Ackermann() |
|||
local i, j |
|||
for i=0 to 3 |
|||
for j=0 to 10 |
|||
print ack(i,j) using "#####"; |
|||
next |
|||
print |
|||
next |
|||
print "ack(4,1) ";: print ack(4,1) using "#####" |
|||
end sub |
|||
Ackermann()</syntaxhighlight> |
|||
=={{header|Yorick}}== |
=={{header|Yorick}}== |
||
< |
<syntaxhighlight lang="yorick">func ack(m, n) { |
||
if(m == 0) |
if(m == 0) |
||
return n + 1; |
return n + 1; |
||
Line 7,011: | Line 10,224: | ||
else |
else |
||
return ack(m - 1, ack(m, n - 1)); |
return ack(m - 1, ack(m, n - 1)); |
||
}</ |
}</syntaxhighlight> |
||
Example invocation: |
Example invocation: |
||
< |
<syntaxhighlight lang="yorick">for(m = 0; m <= 3; m++) { |
||
for(n = 0; n <= 6; n++) |
for(n = 0; n <= 6; n++) |
||
write, format="%d ", ack(m, n); |
write, format="%d ", ack(m, n); |
||
write, ""; |
write, ""; |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>1 2 3 4 5 6 7 |
<pre>1 2 3 4 5 6 7 |
||
Line 7,024: | Line 10,237: | ||
5 13 29 61 125 253 509</pre> |
5 13 29 61 125 253 509</pre> |
||
{{omit from|LaTeX}} |
|||
=={{header|Z80 Assembly}}== |
|||
{{omit from|Make}} |
|||
This function does 16-bit math. Sjasmplus syntax, CP/M executable. |
|||
{{omit from|PlainTeX}} |
|||
<syntaxhighlight lang="z80"> OPT --syntax=abf : OUTPUT "ackerman.com" |
|||
ORG $100 |
|||
jr demo_start |
|||
;-------------------------------------------------------------------------------------------------------------------- |
|||
; entry: ackermann_fn |
|||
; input: bc = m, hl = n |
|||
; output: hl = A(m,n) (16bit only) |
|||
ackermann_fn.inc_n: |
|||
inc hl |
|||
ackermann_fn: |
|||
inc hl |
|||
ld a,c |
|||
or b |
|||
ret z ; m == 0 -> return n+1 |
|||
; m > 0 case ; bc = m, hl = n+1 |
|||
dec bc |
|||
dec hl ; m-1, n restored |
|||
ld a,l |
|||
or h |
|||
jr z,.inc_n ; n == 0 -> return A(m-1, 1) |
|||
; m > 0, n > 0 ; bc = m-1, hl = n |
|||
push bc |
|||
inc bc |
|||
dec hl |
|||
call ackermann_fn ; n = A(m, n-1) |
|||
pop bc |
|||
jp ackermann_fn ; return A(m-1,A(m, n-1)) |
|||
;-------------------------------------------------------------------------------------------------------------------- |
|||
; helper functions for demo printing 4x9 table |
|||
print_str: |
|||
push bc |
|||
push hl |
|||
ld c,9 |
|||
.call_cpm: |
|||
call 5 |
|||
pop hl |
|||
pop bc |
|||
ret |
|||
print_hl: |
|||
ld b,' ' |
|||
ld e,b |
|||
call print_char |
|||
ld de,-10000 |
|||
call extract_digit |
|||
ld de,-1000 |
|||
call extract_digit |
|||
ld de,-100 |
|||
call extract_digit |
|||
ld de,-10 |
|||
call extract_digit |
|||
ld a,l |
|||
print_digit: |
|||
ld b,'0' |
|||
add a,b |
|||
ld e,a |
|||
print_char: |
|||
push bc |
|||
push hl |
|||
ld c,2 |
|||
jr print_str.call_cpm |
|||
extract_digit: |
|||
ld a,-1 |
|||
.digit_loop: |
|||
inc a |
|||
add hl,de |
|||
jr c,.digit_loop |
|||
sbc hl,de |
|||
or a |
|||
jr nz,print_digit |
|||
ld e,b |
|||
jr print_char |
|||
;-------------------------------------------------------------------------------------------------------------------- |
|||
demo_start: ; do m: [0,4) cross n: [0,9) table |
|||
ld bc,0 |
|||
.loop_m: |
|||
ld hl,0 ; bc = m, hl = n = 0 |
|||
ld de,txt_m_is |
|||
call print_str |
|||
ld a,c |
|||
or '0' |
|||
ld e,a |
|||
call print_char |
|||
ld e,':' |
|||
call print_char |
|||
.loop_n: |
|||
push bc |
|||
push hl |
|||
call ackermann_fn |
|||
call print_hl |
|||
pop hl |
|||
pop bc |
|||
inc hl |
|||
ld a,l |
|||
cp 9 |
|||
jr c,.loop_n |
|||
ld de,crlf |
|||
call print_str |
|||
inc bc |
|||
ld a,c |
|||
cp 4 |
|||
jr c,.loop_m |
|||
rst 0 ; return to CP/M |
|||
txt_m_is: db "m=$" |
|||
crlf: db 10,13,'$'</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
m=0: 1 2 3 4 5 6 7 8 9 |
|||
m=1: 2 3 4 5 6 7 8 9 10 |
|||
m=2: 3 5 7 9 11 13 15 17 19 |
|||
m=3: 5 13 29 61 125 253 509 1021 2045 |
|||
</pre> |
|||
=={{header|ZED}}== |
=={{header|ZED}}== |
||
Source -> http://ideone.com/53FzPA |
Source -> http://ideone.com/53FzPA |
||
Compiled -> http://ideone.com/OlS7zL |
Compiled -> http://ideone.com/OlS7zL |
||
< |
<syntaxhighlight lang="zed">(A) m n |
||
comment: |
comment: |
||
(=) m 0 |
(=) m 0 |
||
Line 7,059: | Line 10,387: | ||
comment: |
comment: |
||
#true |
#true |
||
(003) "=" n1 n2</ |
(003) "=" n1 n2</syntaxhighlight> |
||
=={{header|Zig}}== |
|||
<syntaxhighlight lang="zig">pub fn ack(m: u64, n: u64) u64 { |
|||
if (m == 0) return n + 1; |
|||
if (n == 0) return ack(m - 1, 1); |
|||
return ack(m - 1, ack(m, n - 1)); |
|||
} |
|||
pub fn main() !void { |
|||
const stdout = @import("std").io.getStdOut().writer(); |
|||
var m: u8 = 0; |
|||
while (m <= 3) : (m += 1) { |
|||
var n: u8 = 0; |
|||
while (n <= 8) : (n += 1) |
|||
try stdout.print("{d:>8}", .{ack(m, n)}); |
|||
try stdout.print("\n", .{}); |
|||
} |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> 1 2 3 4 5 6 7 8 9 |
|||
2 3 4 5 6 7 8 9 10 |
|||
3 5 7 9 11 13 15 17 19 |
|||
5 13 29 61 125 253 509 1021 2045</pre> |
|||
=={{header|ZX Spectrum Basic}}== |
=={{header|ZX Spectrum Basic}}== |
||
{{trans|BASIC256}} |
{{trans|BASIC256}} |
||
< |
<syntaxhighlight lang="zxbasic">10 DIM s(2000,3) |
||
20 LET s(1,1)=3: REM M |
20 LET s(1,1)=3: REM M |
||
30 LET s(1,2)=7: REM N |
30 LET s(1,2)=7: REM N |
||
Line 7,081: | Line 10,433: | ||
190 LET s(lev-1,3)=s(lev,3) |
190 LET s(lev-1,3)=s(lev,3) |
||
200 LET lev=lev-1 |
200 LET lev=lev-1 |
||
210 RETURN </ |
210 RETURN </syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>A(3,7) = 1021</pre> |
<pre>A(3,7) = 1021</pre> |
||
{{omit from|LaTeX}} |
|||
{{omit from|Make}} |
|||
{{omit from|PlainTeX}} |
Latest revision as of 13:03, 22 July 2024
![Task](http://static.miraheze.org/rosettacodewiki/thumb/b/ba/Rcode-button-task-crushed.png/64px-Rcode-button-task-crushed.png)
You are encouraged to solve this task according to the task description, using any language you may know.
The Ackermann function is a classic example of a recursive function, notable especially because it is not a primitive recursive function. It grows very quickly in value, as does the size of its call tree.
The Ackermann function is usually defined as follows:
Its arguments are never negative and it always terminates.
- Task
Write a function which returns the value of . Arbitrary precision is preferred (since the function grows so quickly), but not required.
- See also
- Conway chained arrow notation for the Ackermann function.
11l
F ack2(m, n) -> Int
R I m == 0 {(n + 1)
} E I m == 1 {(n + 2)
} E I m == 2 {(2 * n + 3)
} E I m == 3 {(8 * (2 ^ n - 1) + 5)
} E I n == 0 {ack2(m - 1, 1)
} E ack2(m - 1, ack2(m, n - 1))
print(ack2(0, 0))
print(ack2(3, 4))
print(ack2(4, 1))
- Output:
1 125 65533
360 Assembly
The OS/360 linkage is a bit tricky with the S/360 basic instruction set. To simplify, the program is recursive not reentrant.
* Ackermann function 07/09/2015
&LAB XDECO ®,&TARGET
.*-----------------------------------------------------------------*
.* THIS MACRO DISPLAYS THE REGISTER CONTENTS AS A TRUE *
.* DECIMAL VALUE. XDECO IS NOT PART OF STANDARD S360 MACROS! *
*------------------------------------------------------------------*
AIF (T'® EQ 'O').NOREG
AIF (T'&TARGET EQ 'O').NODEST
&LAB B I&SYSNDX BRANCH AROUND WORK AREA
W&SYSNDX DS XL8 CONVERSION WORK AREA
I&SYSNDX CVD ®,W&SYSNDX CONVERT TO DECIMAL
MVC &TARGET,=XL12'402120202020202020202020'
ED &TARGET,W&SYSNDX+2 MAKE FIELD PRINTABLE
BC 2,*+12 BYPASS NEGATIVE
MVI &TARGET+12,C'-' INSERT NEGATIVE SIGN
B *+8 BYPASS POSITIVE
MVI &TARGET+12,C'+' INSERT POSITIVE SIGN
MEXIT
.NOREG MNOTE 8,'INPUT REGISTER OMITTED'
MEXIT
.NODEST MNOTE 8,'TARGET FIELD OMITTED'
MEXIT
MEND
ACKERMAN CSECT
USING ACKERMAN,R12 r12 : base register
LR R12,R15 establish base register
ST R14,SAVER14A save r14
LA R4,0 m=0
LOOPM CH R4,=H'3' do m=0 to 3
BH ELOOPM
LA R5,0 n=0
LOOPN CH R5,=H'8' do n=0 to 8
BH ELOOPN
LR R1,R4 m
LR R2,R5 n
BAL R14,ACKER r1=acker(m,n)
XDECO R1,PG+19
XDECO R4,XD
MVC PG+10(2),XD+10
XDECO R5,XD
MVC PG+13(2),XD+10
XPRNT PG,44 print buffer
LA R5,1(R5) n=n+1
B LOOPN
ELOOPN LA R4,1(R4) m=m+1
B LOOPM
ELOOPM L R14,SAVER14A restore r14
BR R14 return to caller
SAVER14A DS F static save r14
PG DC CL44'Ackermann(xx,xx) = xxxxxxxxxxxx'
XD DS CL12
ACKER CNOP 0,4 function r1=acker(r1,r2)
LR R3,R1 save argument r1 in r3
LR R9,R10 save stackptr (r10) in r9 temp
LA R1,STACKLEN amount of storage required
GETMAIN RU,LV=(R1) allocate storage for stack
USING STACK,R10 make storage addressable
LR R10,R1 establish stack addressability
ST R14,SAVER14B save previous r14
ST R9,SAVER10B save previous r10
LR R1,R3 restore saved argument r1
START ST R1,M stack m
ST R2,N stack n
IF1 C R1,=F'0' if m<>0
BNE IF2 then goto if2
LR R11,R2 n
LA R11,1(R11) return n+1
B EXIT
IF2 C R2,=F'0' else if m<>0
BNE IF3 then goto if3
BCTR R1,0 m=m-1
LA R2,1 n=1
BAL R14,ACKER r1=acker(m)
LR R11,R1 return acker(m-1,1)
B EXIT
IF3 BCTR R2,0 n=n-1
BAL R14,ACKER r1=acker(m,n-1)
LR R2,R1 acker(m,n-1)
L R1,M m
BCTR R1,0 m=m-1
BAL R14,ACKER r1=acker(m-1,acker(m,n-1))
LR R11,R1 return acker(m-1,1)
EXIT L R14,SAVER14B restore r14
L R9,SAVER10B restore r10 temp
LA R0,STACKLEN amount of storage to free
FREEMAIN A=(R10),LV=(R0) free allocated storage
LR R1,R11 value returned
LR R10,R9 restore r10
BR R14 return to caller
LTORG
DROP R12 base no longer needed
STACK DSECT dynamic area
SAVER14B DS F saved r14
SAVER10B DS F saved r10
M DS F m
N DS F n
STACKLEN EQU *-STACK
YREGS
END ACKERMAN
- Output:
Ackermann( 0, 0) = 1 Ackermann( 0, 1) = 2 Ackermann( 0, 2) = 3 Ackermann( 0, 3) = 4 Ackermann( 0, 4) = 5 Ackermann( 0, 5) = 6 Ackermann( 0, 6) = 7 Ackermann( 0, 7) = 8 Ackermann( 0, 8) = 9 Ackermann( 1, 0) = 2 Ackermann( 1, 1) = 3 Ackermann( 1, 2) = 4 Ackermann( 1, 3) = 5 Ackermann( 1, 4) = 6 Ackermann( 1, 5) = 7 Ackermann( 1, 6) = 8 Ackermann( 1, 7) = 9 Ackermann( 1, 8) = 10 Ackermann( 2, 0) = 3 Ackermann( 2, 1) = 5 Ackermann( 2, 2) = 7 Ackermann( 2, 3) = 9 Ackermann( 2, 4) = 11 Ackermann( 2, 5) = 13 Ackermann( 2, 6) = 15 Ackermann( 2, 7) = 17 Ackermann( 2, 8) = 19 Ackermann( 3, 0) = 5 Ackermann( 3, 1) = 13 Ackermann( 3, 2) = 29 Ackermann( 3, 3) = 61 Ackermann( 3, 4) = 125 Ackermann( 3, 5) = 253 Ackermann( 3, 6) = 509 Ackermann( 3, 7) = 1021 Ackermann( 3, 8) = 2045
68000 Assembly
This implementation is based on the code shown in the computerphile episode in the youtube link at the top of this page (time index 5:00).
;
; Ackermann function for Motorola 68000 under AmigaOs 2+ by Thorham
;
; Set stack space to 60000 for m = 3, n = 5.
;
; The program will print the ackermann values for the range m = 0..3, n = 0..5
;
_LVOOpenLibrary equ -552
_LVOCloseLibrary equ -414
_LVOVPrintf equ -954
m equ 3 ; Nr of iterations for the main loop.
n equ 5 ; Do NOT set them higher, or it will take hours to complete on
; 68k, not to mention that the stack usage will become astronomical.
; Perhaps n can be a little higher... If you do increase the ranges
; then don't forget to increase the stack size.
execBase=4
start
move.l execBase,a6
lea dosName,a1
moveq #36,d0
jsr _LVOOpenLibrary(a6)
move.l d0,dosBase
beq exit
move.l dosBase,a6
lea printfArgs,a2
clr.l d3 ; m
.loopn
clr.l d4 ; n
.loopm
bsr ackermann
move.l d3,0(a2)
move.l d4,4(a2)
move.l d5,8(a2)
move.l #outString,d1
move.l a2,d2
jsr _LVOVPrintf(a6)
addq.l #1,d4
cmp.l #n,d4
ble .loopm
addq.l #1,d3
cmp.l #m,d3
ble .loopn
exit
move.l execBase,a6
move.l dosBase,a1
jsr _LVOCloseLibrary(a6)
rts
;
; ackermann function
;
; in:
;
; d3 = m
; d4 = n
;
; out:
;
; d5 = ans
;
ackermann
move.l d3,-(sp)
move.l d4,-(sp)
tst.l d3
bne .l1
move.l d4,d5
addq.l #1,d5
bra .return
.l1
tst.l d4
bne .l2
subq.l #1,d3
moveq #1,d4
bsr ackermann
bra .return
.l2
subq.l #1,d4
bsr ackermann
move.l d5,d4
subq.l #1,d3
bsr ackermann
.return
move.l (sp)+,d4
move.l (sp)+,d3
rts
;
; variables
;
dosBase
dc.l 0
printfArgs
dcb.l 3
;
; strings
;
dosName
dc.b "dos.library",0
outString
dc.b "ackermann (%ld,%ld) is: %ld",10,0
8080 Assembly
This function does 16-bit math. The test code prints a table of ack(m,n)
for m ∊ [0,4)
and n ∊ [0,9)
, on a real 8080 this takes a little over two minutes.
org 100h
jmp demo
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; ACK(M,N); DE=M, HL=N, return value in HL.
ack: mov a,d ; M=0?
ora e
jnz ackm
inx h ; If so, N+1.
ret
ackm: mov a,h ; N=0?
ora l
jnz ackmn
lxi h,1 ; If so, N=1,
dcx d ; N-=1,
jmp ack ; A(M,N) - tail recursion
ackmn: push d ; M>0 and N>0: store M on the stack
dcx h ; N-=1
call ack ; N = ACK(M,N-1)
pop d ; Restore previous M
dcx d ; M-=1
jmp ack ; A(M,N) - tail recursion
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Print table of ack(m,n)
MMAX: equ 4 ; Size of table to print. Note that math is done in
NMAX: equ 9 ; 16 bits.
demo: lhld 6 ; Put stack pointer at top of available memory
sphl
lxi b,0 ; let B,C hold 8-bit M and N.
acknum: xra a ; Set high bit of M and N to zero
mov d,a ; DE = B (M)
mov e,b
mov h,a ; HL = C (N)
mov l,c
call ack ; HL = ack(DE,HL)
call prhl ; Print the number
inr c ; N += 1
mvi a,NMAX ; Time for next line?
cmp c
jnz acknum ; If not, print next number
push b ; Otherwise, save BC
mvi c,9 ; Print newline
lxi d,nl
call 5
pop b ; Restore BC
mvi c,0 ; Set N to 0
inr b ; M += 1
mvi a,MMAX ; Time to stop?
cmp b
jnz acknum ; If not, print next number
rst 0
;;; Print HL as ASCII number.
prhl: push h ; Save all registers
push d
push b
lxi b,pnum ; Store pointer to num string on stack
push b
lxi b,-10 ; Divisor
prdgt: lxi d,-1
prdgtl: inx d ; Divide by 10 through trial subtraction
dad b
jc prdgtl
mvi a,'0'+10
add l ; L = remainder - 10
pop h ; Get pointer from stack
dcx h ; Store digit
mov m,a
push h ; Put pointer back on stack
xchg ; Put quotient in HL
mov a,h ; Check if zero
ora l
jnz prdgt ; If not, next digit
pop d ; Get pointer and put in DE
mvi c,9 ; CP/M print string
call 5
pop b ; Restore registers
pop d
pop h
ret
db '*****' ; Placeholder for number
pnum: db 9,'$'
nl: db 13,10,'$'
- Output:
1 2 3 4 5 6 7 8 9 2 3 4 5 6 7 8 9 10 3 5 7 9 11 13 15 17 19 5 13 29 61 125 253 509 1021 2045
8086 Assembly
This code does 16-bit math just like the 8080 version.
cpu 8086
bits 16
org 100h
section .text
jmp demo
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; ACK(M,N); DX=M, AX=N, return value in AX.
ack: and dx,dx ; N=0?
jnz .m
inc ax ; If so, return N+1
ret
.m: and ax,ax ; M=0?
jnz .mn
mov ax,1 ; If so, N=1,
dec dx ; M -= 1
jmp ack ; ACK(M-1,1) - tail recursion
.mn: push dx ; Keep M on the stack
dec ax ; N-=1
call ack ; N = ACK(M,N-1)
pop dx ; Restore M
dec dx ; M -= 1
jmp ack ; ACK(M-1,ACK(M,N-1)) - tail recursion
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Print table of ack(m,n)
MMAX: equ 4 ; Size of table to print. Noe that math is done
NMAX: equ 9 ; in 16 bits.
demo: xor si,si ; Let SI hold M,
xor di,di ; and DI hold N.
acknum: mov dx,si ; Calculate ack(M,N)
mov ax,di
call ack
call prax ; Print number
inc di ; N += 1
cmp di,NMAX ; Row done?
jb acknum ; If not, print next number on row
xor di,di ; Otherwise, N=0,
inc si ; M += 1
mov dx,nl ; Print newline
call prstr
cmp si,MMAX ; Done?
jb acknum ; If not, start next row
ret ; Otherwise, stop.
;;; Print AX as ASCII number.
prax: mov bx,pnum ; Pointer to number string
mov cx,10 ; Divisor
.dgt: xor dx,dx ; Divide AX by ten
div cx
add dl,'0' ; DX holds remainder - add ASCII 0
dec bx ; Move pointer backwards
mov [bx],dl ; Save digit in string
and ax,ax ; Are we done yet?
jnz .dgt ; If not, next digit
mov dx,bx ; Tell DOS to print the string
prstr: mov ah,9
int 21h
ret
section .data
db '*****' ; Placeholder for ASCII number
pnum: db 9,'$'
nl: db 13,10,'$'
- Output:
1 2 3 4 5 6 7 8 9 2 3 4 5 6 7 8 9 10 3 5 7 9 11 13 15 17 19 5 13 29 61 125 253 509 1021 2045
8th
\ Ackermann function, illustrating use of "memoization".
\ Memoization is a technique whereby intermediate computed values are stored
\ away against later need. It is particularly valuable when calculating those
\ values is time or resource intensive, as with the Ackermann function.
\ make the stack much bigger so this can complete!
100000 stack-size
\ This is where memoized values are stored:
{} var, dict
\ Simple accessor words
: dict! \ "key" val --
dict @ -rot m:! drop ;
: dict@ \ "key" -- val
dict @ swap m:@ nip ;
defer: ack1
\ We just jam the string representation of the two numbers together for a key:
: makeKey \ m n -- m n key
2dup >s swap >s s:+ ;
: ack2 \ m n -- A
makeKey dup
dict@ null?
if \ can't find key in dict
\ m n key null
drop \ m n key
-rot \ key m n
ack1 \ key A
tuck \ A key A
dict! \ A
else \ found value
\ m n key value
>r drop 2drop r>
then ;
: ack \ m n -- A
over not
if
nip n:1+
else
dup not
if
drop n:1- 1 ack2
else
over swap n:1- ack2
swap n:1- swap ack2
then
then ;
' ack is ack1
: ackOf \ m n --
2dup
"Ack(" . swap . ", " . . ") = " . ack . cr ;
0 0 ackOf
0 4 ackOf
1 0 ackOf
1 1 ackOf
2 1 ackOf
2 2 ackOf
3 1 ackOf
3 3 ackOf
4 0 ackOf
\ this last requires a very large data stack. So start 8th with a parameter '-k 100000'
4 1 ackOf
bye
- The output:
Ack(0, 0) = 1 Ack(0, 4) = 5 Ack(1, 0) = 2 Ack(1, 1) = 3 Ack(2, 1) = 5 Ack(2, 2) = 7 Ack(3, 1) = 13 Ack(3, 3) = 61 Ack(4, 0) = 13 Ack(4, 1) = 65533
AArch64 Assembly
/* ARM assembly AARCH64 Raspberry PI 3B or android 64 bits */
/* program ackermann64.s */
/*******************************************/
/* Constantes file */
/*******************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeConstantesARM64.inc"
.equ MMAXI, 4
.equ NMAXI, 10
/*********************************/
/* Initialized data */
/*********************************/
.data
sMessResult: .asciz "Result for @ @ : @ \n"
szMessError: .asciz "Overflow !!.\n"
szCarriageReturn: .asciz "\n"
/*********************************/
/* UnInitialized data */
/*********************************/
.bss
sZoneConv: .skip 24
/*********************************/
/* code section */
/*********************************/
.text
.global main
main: // entry of program
mov x3,#0
mov x4,#0
1:
mov x0,x3
mov x1,x4
bl ackermann
mov x5,x0
mov x0,x3
ldr x1,qAdrsZoneConv // else display odd message
bl conversion10 // call decimal conversion
ldr x0,qAdrsMessResult
ldr x1,qAdrsZoneConv // insert value conversion in message
bl strInsertAtCharInc
mov x6,x0
mov x0,x4
ldr x1,qAdrsZoneConv // else display odd message
bl conversion10 // call decimal conversion
mov x0,x6
ldr x1,qAdrsZoneConv // insert value conversion in message
bl strInsertAtCharInc
mov x6,x0
mov x0,x5
ldr x1,qAdrsZoneConv // else display odd message
bl conversion10 // call decimal conversion
mov x0,x6
ldr x1,qAdrsZoneConv // insert value conversion in message
bl strInsertAtCharInc
bl affichageMess
add x4,x4,#1
cmp x4,#NMAXI
blt 1b
mov x4,#0
add x3,x3,#1
cmp x3,#MMAXI
blt 1b
100: // standard end of the program
mov x0, #0 // return code
mov x8, #EXIT // request to exit program
svc #0 // perform the system call
qAdrszCarriageReturn: .quad szCarriageReturn
qAdrsMessResult: .quad sMessResult
qAdrsZoneConv: .quad sZoneConv
/***************************************************/
/* fonction ackermann */
/***************************************************/
// x0 contains a number m
// x1 contains a number n
// x0 return résult
ackermann:
stp x1,lr,[sp,-16]! // save registres
stp x2,x3,[sp,-16]! // save registres
cmp x0,0
beq 5f
mov x3,-1
csel x0,x3,x0,lt // error
blt 100f
cmp x1,#0
csel x0,x3,x0,lt // error
blt 100f
bgt 1f
sub x0,x0,#1
mov x1,#1
bl ackermann
b 100f
1:
mov x2,x0
sub x1,x1,#1
bl ackermann
mov x1,x0
sub x0,x2,#1
bl ackermann
b 100f
5:
adds x0,x1,#1
bcc 100f
ldr x0,qAdrszMessError
bl affichageMess
mov x0,-1
100:
ldp x2,x3,[sp],16 // restaur des 2 registres
ldp x1,lr,[sp],16 // restaur des 2 registres
ret
qAdrszMessError: .quad szMessError
/********************************************************/
/* File Include fonctions */
/********************************************************/
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"
- Output:
Result for 0 0 : 1 Result for 0 1 : 2 Result for 0 2 : 3 Result for 0 3 : 4 Result for 0 4 : 5 Result for 0 5 : 6 Result for 0 6 : 7 Result for 0 7 : 8 Result for 0 8 : 9 Result for 0 9 : 10 Result for 1 0 : 2 Result for 1 1 : 3 Result for 1 2 : 4 Result for 1 3 : 5 Result for 1 4 : 6 Result for 1 5 : 7 Result for 1 6 : 8 Result for 1 7 : 9 Result for 1 8 : 10 Result for 1 9 : 11 Result for 2 0 : 3 Result for 2 1 : 5 Result for 2 2 : 7 Result for 2 3 : 9 Result for 2 4 : 11 Result for 2 5 : 13 Result for 2 6 : 15 Result for 2 7 : 17 Result for 2 8 : 19 Result for 2 9 : 21 Result for 3 0 : 5 Result for 3 1 : 13 Result for 3 2 : 29 Result for 3 3 : 61 Result for 3 4 : 125 Result for 3 5 : 253 Result for 3 6 : 509 Result for 3 7 : 1021 Result for 3 8 : 2045 Result for 3 9 : 4093
ABAP
REPORT zhuberv_ackermann.
CLASS zcl_ackermann DEFINITION.
PUBLIC SECTION.
CLASS-METHODS ackermann IMPORTING m TYPE i
n TYPE i
RETURNING value(v) TYPE i.
ENDCLASS. "zcl_ackermann DEFINITION
CLASS zcl_ackermann IMPLEMENTATION.
METHOD: ackermann.
DATA: lv_new_m TYPE i,
lv_new_n TYPE i.
IF m = 0.
v = n + 1.
ELSEIF m > 0 AND n = 0.
lv_new_m = m - 1.
lv_new_n = 1.
v = ackermann( m = lv_new_m n = lv_new_n ).
ELSEIF m > 0 AND n > 0.
lv_new_m = m - 1.
lv_new_n = n - 1.
lv_new_n = ackermann( m = m n = lv_new_n ).
v = ackermann( m = lv_new_m n = lv_new_n ).
ENDIF.
ENDMETHOD. "ackermann
ENDCLASS. "zcl_ackermann IMPLEMENTATION
PARAMETERS: pa_m TYPE i,
pa_n TYPE i.
DATA: lv_result TYPE i.
START-OF-SELECTION.
lv_result = zcl_ackermann=>ackermann( m = pa_m n = pa_n ).
WRITE: / lv_result.
ABC
HOW TO RETURN m ack n:
SELECT:
m=0: RETURN n+1
m>0 AND n=0: RETURN (m-1) ack 1
m>0 AND n>0: RETURN (m-1) ack (m ack (n-1))
FOR m IN {0..3}:
FOR n IN {0..8}:
WRITE (m ack n)>>6
WRITE /
- Output:
1 2 3 4 5 6 7 8 9 2 3 4 5 6 7 8 9 10 3 5 7 9 11 13 15 17 19 5 13 29 61 125 253 509 1021 2045
Acornsoft Lisp
(defun ack (m n)
(cond ((zerop m) (add1 n))
((zerop n) (ack (sub1 m) 1))
(t (ack (sub1 m) (ack m (sub1 n))))))
- Output:
Evaluate : (ack 3 5) Value is : 253
Action!
Action! language does not support recursion. Therefore an iterative approach with a stack has been proposed.
DEFINE MAXSIZE="1000"
CARD ARRAY stack(MAXSIZE)
CARD stacksize=[0]
BYTE FUNC IsEmpty()
IF stacksize=0 THEN
RETURN (1)
FI
RETURN (0)
PROC Push(BYTE v)
IF stacksize=maxsize THEN
PrintE("Error: stack is full!")
Break()
FI
stack(stacksize)=v
stacksize==+1
RETURN
BYTE FUNC Pop()
IF IsEmpty() THEN
PrintE("Error: stack is empty!")
Break()
FI
stacksize==-1
RETURN (stack(stacksize))
CARD FUNC Ackermann(CARD m,n)
Push(m)
WHILE IsEmpty()=0
DO
m=Pop()
IF m=0 THEN
n==+1
ELSEIF n=0 THEN
n=1
Push(m-1)
ELSE
n==-1
Push(m-1)
Push(m)
FI
OD
RETURN (n)
PROC Main()
CARD m,n,res
FOR m=0 TO 3
DO
FOR n=0 TO 4
DO
res=Ackermann(m,n)
PrintF("Ack(%U,%U)=%U%E",m,n,res)
OD
OD
RETURN
- Output:
Screenshot from Atari 8-bit computer
Ack(0,0)=1 Ack(0,1)=2 Ack(0,2)=3 Ack(0,3)=4 Ack(0,4)=5 Ack(1,0)=2 Ack(1,1)=3 Ack(1,2)=4 Ack(1,3)=5 Ack(1,4)=6 Ack(2,0)=3 Ack(2,1)=5 Ack(2,2)=7 Ack(2,3)=9 Ack(2,4)=11 Ack(3,0)=5 Ack(3,1)=13 Ack(3,2)=29 Ack(3,3)=61 Ack(3,4)=125
ActionScript
public function ackermann(m:uint, n:uint):uint
{
if (m == 0)
{
return n + 1;
}
if (n == 0)
{
return ackermann(m - 1, 1);
}
return ackermann(m - 1, ackermann(m, n - 1));
}
Ada
with Ada.Text_IO; use Ada.Text_IO;
procedure Test_Ackermann is
function Ackermann (M, N : Natural) return Natural is
begin
if M = 0 then
return N + 1;
elsif N = 0 then
return Ackermann (M - 1, 1);
else
return Ackermann (M - 1, Ackermann (M, N - 1));
end if;
end Ackermann;
begin
for M in 0..3 loop
for N in 0..6 loop
Put (Natural'Image (Ackermann (M, N)));
end loop;
New_Line;
end loop;
end Test_Ackermann;
The implementation does not care about arbitrary precision numbers because the Ackermann function does not only grow, but also slow quickly, when computed recursively.
- Output:
the first 4x7 Ackermann's numbers
1 2 3 4 5 6 7 2 3 4 5 6 7 8 3 5 7 9 11 13 15 5 13 29 61 125 253 509
Agda
module Ackermann where
open import Data.Nat using (ℕ ; zero ; suc ; _+_)
ack : ℕ → ℕ → ℕ
ack zero n = n + 1
ack (suc m) zero = ack m 1
ack (suc m) (suc n) = ack m (ack (suc m) n)
open import Agda.Builtin.IO using (IO)
open import Agda.Builtin.Unit using (⊤)
open import Agda.Builtin.String using (String)
open import Data.Nat.Show using (show)
postulate putStrLn : String → IO ⊤
{-# FOREIGN GHC import qualified Data.Text as T #-}
{-# COMPILE GHC putStrLn = putStrLn . T.unpack #-}
main : IO ⊤
main = putStrLn (show (ack 3 9))
-- Output:
-- 4093
The Unicode characters can be entered in Emacs Agda as follows:
- ℕ : \bN
- → : \to
- ⊤ : \top
Running in Bash:
agda --compile Ackermann.agda
./Ackermann
- Output:
4093
ALGOL 60
begin
integer procedure ackermann(m,n);value m,n;integer m,n;
ackermann:=if m=0 then n+1
else if n=0 then ackermann(m-1,1)
else ackermann(m-1,ackermann(m,n-1));
integer m,n;
for m:=0 step 1 until 3 do begin
for n:=0 step 1 until 6 do
outinteger(1,ackermann(m,n));
outstring(1,"\n")
end
end
- Output:
1 2 3 4 5 6 7 2 3 4 5 6 7 8 3 5 7 9 11 13 15 5 13 29 61 125 253 509
ALGOL 68
PROC test ackermann = VOID:
BEGIN
PROC ackermann = (INT m, n)INT:
BEGIN
IF m = 0 THEN
n + 1
ELIF n = 0 THEN
ackermann (m - 1, 1)
ELSE
ackermann (m - 1, ackermann (m, n - 1))
FI
END # ackermann #;
FOR m FROM 0 TO 3 DO
FOR n FROM 0 TO 6 DO
print(ackermann (m, n))
OD;
new line(stand out)
OD
END # test ackermann #;
test ackermann
- Output:
+1 +2 +3 +4 +5 +6 +7 +2 +3 +4 +5 +6 +7 +8 +3 +5 +7 +9 +11 +13 +15 +5 +13 +29 +61 +125 +253 +509
ALGOL W
begin
integer procedure ackermann( integer value m,n ) ;
if m=0 then n+1
else if n=0 then ackermann(m-1,1)
else ackermann(m-1,ackermann(m,n-1));
for m := 0 until 3 do begin
write( ackermann( m, 0 ) );
for n := 1 until 6 do writeon( ackermann( m, n ) );
end for_m
end.
- Output:
1 2 3 4 5 6 7 2 3 4 5 6 7 8 3 5 7 9 11 13 15 5 13 29 61 125 253 509
APL
ackermann←{
0=1⊃⍵:1+2⊃⍵
0=2⊃⍵:∇(¯1+1⊃⍵)1
∇(¯1+1⊃⍵),∇(1⊃⍵),¯1+2⊃⍵
}
AppleScript
on ackermann(m, n)
if m is equal to 0 then return n + 1
if n is equal to 0 then return ackermann(m - 1, 1)
return ackermann(m - 1, ackermann(m, n - 1))
end ackermann
Argile
use std
for each (val nat n) from 0 to 6
for each (val nat m) from 0 to 3
print "A("m","n") = "(A m n)
.:A <nat m, nat n>:. -> nat
return (n+1) if m == 0
return (A (m - 1) 1) if n == 0
A (m - 1) (A m (n - 1))
ARM Assembly
/* ARM assembly Raspberry PI or android 32 bits */
/* program ackermann.s */
/* REMARK 1 : this program use routines in a include file
see task Include a file language arm assembly
for the routine affichageMess conversion10
see at end of this program the instruction include */
/* for constantes see task include a file in arm assembly */
/************************************/
/* Constantes */
/************************************/
.include "../constantes.inc"
.equ MMAXI, 4
.equ NMAXI, 10
/*********************************/
/* Initialized data */
/*********************************/
.data
sMessResult: .asciz "Result for @ @ : @ \n"
szMessError: .asciz "Overflow !!.\n"
szCarriageReturn: .asciz "\n"
/*********************************/
/* UnInitialized data */
/*********************************/
.bss
sZoneConv: .skip 24
/*********************************/
/* code section */
/*********************************/
.text
.global main
main: @ entry of program
mov r3,#0
mov r4,#0
1:
mov r0,r3
mov r1,r4
bl ackermann
mov r5,r0
mov r0,r3
ldr r1,iAdrsZoneConv @ else display odd message
bl conversion10 @ call decimal conversion
ldr r0,iAdrsMessResult
ldr r1,iAdrsZoneConv @ insert value conversion in message
bl strInsertAtCharInc
mov r6,r0
mov r0,r4
ldr r1,iAdrsZoneConv @ else display odd message
bl conversion10 @ call decimal conversion
mov r0,r6
ldr r1,iAdrsZoneConv @ insert value conversion in message
bl strInsertAtCharInc
mov r6,r0
mov r0,r5
ldr r1,iAdrsZoneConv @ else display odd message
bl conversion10 @ call decimal conversion
mov r0,r6
ldr r1,iAdrsZoneConv @ insert value conversion in message
bl strInsertAtCharInc
bl affichageMess
add r4,#1
cmp r4,#NMAXI
blt 1b
mov r4,#0
add r3,#1
cmp r3,#MMAXI
blt 1b
100: @ standard end of the program
mov r0, #0 @ return code
mov r7, #EXIT @ request to exit program
svc #0 @ perform the system call
iAdrszCarriageReturn: .int szCarriageReturn
iAdrsMessResult: .int sMessResult
iAdrsZoneConv: .int sZoneConv
/***************************************************/
/* fonction ackermann */
/***************************************************/
// r0 contains a number m
// r1 contains a number n
// r0 return résult
ackermann:
push {r1-r2,lr} @ save registers
cmp r0,#0
beq 5f
movlt r0,#-1 @ error
blt 100f
cmp r1,#0
movlt r0,#-1 @ error
blt 100f
bgt 1f
sub r0,r0,#1
mov r1,#1
bl ackermann
b 100f
1:
mov r2,r0
sub r1,r1,#1
bl ackermann
mov r1,r0
sub r0,r2,#1
bl ackermann
b 100f
5:
adds r0,r1,#1
bcc 100f
ldr r0,iAdrszMessError
bl affichageMess
bkpt
100:
pop {r1-r2,lr} @ restaur registers
bx lr @ return
iAdrszMessError: .int szMessError
/***************************************************/
/* ROUTINES INCLUDE */
/***************************************************/
.include "../affichage.inc"
- Output:
Result for 0 0 : 1 Result for 0 1 : 2 Result for 0 2 : 3 Result for 0 3 : 4 Result for 0 4 : 5 Result for 0 5 : 6 Result for 0 6 : 7 Result for 0 7 : 8 Result for 0 8 : 9 Result for 0 9 : 10 Result for 1 0 : 2 Result for 1 1 : 3 Result for 1 2 : 4 Result for 1 3 : 5 Result for 1 4 : 6 Result for 1 5 : 7 Result for 1 6 : 8 Result for 1 7 : 9 Result for 1 8 : 10 Result for 1 9 : 11 Result for 2 0 : 3 Result for 2 1 : 5 Result for 2 2 : 7 Result for 2 3 : 9 Result for 2 4 : 11 Result for 2 5 : 13 Result for 2 6 : 15 Result for 2 7 : 17 Result for 2 8 : 19 Result for 2 9 : 21 Result for 3 0 : 5 Result for 3 1 : 13 Result for 3 2 : 29 Result for 3 3 : 61 Result for 3 4 : 125 Result for 3 5 : 253 Result for 3 6 : 509 Result for 3 7 : 1021 Result for 3 8 : 2045 Result for 3 9 : 4093
Arturo
ackermann: function [m,n][
(m=0)? -> n+1 [
(n=0)? -> ackermann m-1 1
-> ackermann m-1 ackermann m n-1
]
]
loop 0..3 'a [
loop 0..4 'b [
print ["ackermann" a b "=>" ackermann a b]
]
]
- Output:
ackermann 0 0 => 1 ackermann 0 1 => 2 ackermann 0 2 => 3 ackermann 0 3 => 4 ackermann 0 4 => 5 ackermann 1 0 => 2 ackermann 1 1 => 3 ackermann 1 2 => 4 ackermann 1 3 => 5 ackermann 1 4 => 6 ackermann 2 0 => 3 ackermann 2 1 => 5 ackermann 2 2 => 7 ackermann 2 3 => 9 ackermann 2 4 => 11 ackermann 3 0 => 5 ackermann 3 1 => 13 ackermann 3 2 => 29 ackermann 3 3 => 61 ackermann 3 4 => 125
ATS
fun ackermann
{m,n:nat} .<m,n>.
(m: int m, n: int n): Nat =
case+ (m, n) of
| (0, _) => n+1
| (_, 0) =>> ackermann (m-1, 1)
| (_, _) =>> ackermann (m-1, ackermann (m, n-1))
// end of [ackermann]
AutoHotkey
A(m, n) {
If (m > 0) && (n = 0)
Return A(m-1,1)
Else If (m > 0) && (n > 0)
Return A(m-1,A(m, n-1))
Else If (m=0)
Return n+1
}
; Example:
MsgBox, % "A(1,2) = " A(1,2)
AutoIt
Classical version
Func Ackermann($m, $n)
If ($m = 0) Then
Return $n+1
Else
If ($n = 0) Then
Return Ackermann($m-1, 1)
Else
return Ackermann($m-1, Ackermann($m, $n-1))
EndIf
EndIf
EndFunc
Classical + cache implementation
This version works way faster than the classical one: Ackermann(3, 5) runs in 12,7 ms, while the classical version takes 402,2 ms.
Global $ackermann[2047][2047] ; Set the size to whatever you want
Func Ackermann($m, $n)
If ($ackermann[$m][$n] <> 0) Then
Return $ackermann[$m][$n]
Else
If ($m = 0) Then
$return = $n + 1
Else
If ($n = 0) Then
$return = Ackermann($m - 1, 1)
Else
$return = Ackermann($m - 1, Ackermann($m, $n - 1))
EndIf
EndIf
$ackermann[$m][$n] = $return
Return $return
EndIf
EndFunc ;==>Ackermann
AWK
function ackermann(m, n)
{
if ( m == 0 ) {
return n+1
}
if ( n == 0 ) {
return ackermann(m-1, 1)
}
return ackermann(m-1, ackermann(m, n-1))
}
BEGIN {
for(n=0; n < 7; n++) {
for(m=0; m < 4; m++) {
print "A(" m "," n ") = " ackermann(m,n)
}
}
}
Babel
main:
{((0 0) (0 1) (0 2)
(0 3) (0 4) (1 0)
(1 1) (1 2) (1 3)
(1 4) (2 0) (2 1)
(2 2) (2 3) (3 0)
(3 1) (3 2) (4 0))
{ dup
"A(" << { %d " " . << } ... ") = " <<
reverse give
ack
%d cr << } ... }
ack!:
{ dup zero?
{ <-> dup zero?
{ <->
cp
1 -
<- <- 1 - ->
ack ->
ack }
{ <->
1 -
<- 1 ->
ack }
if }
{ zap 1 + }
if }
zero?!: { 0 = }
- Output:
A(0 0 ) = 1 A(0 1 ) = 2 A(0 2 ) = 3 A(0 3 ) = 4 A(0 4 ) = 5 A(1 0 ) = 2 A(1 1 ) = 3 A(1 2 ) = 4 A(1 3 ) = 5 A(1 4 ) = 6 A(2 0 ) = 3 A(2 1 ) = 5 A(2 2 ) = 7 A(2 3 ) = 9 A(3 0 ) = 5 A(3 1 ) = 13 A(3 2 ) = 29 A(4 0 ) = 13
BASIC
Applesoft BASIC
100 DIM R%(2900),M(2900),N(2900)
110 FOR M = 0 TO 3
120 FOR N = 0 TO 4
130 GOSUB 200"ACKERMANN
140 PRINT "ACK("M","N") = "ACK
150 NEXT N, M
160 END
200 M(SP) = M
210 N(SP) = N
REM A(M - 1, A(M, N - 1))
220 IF M > 0 AND N > 0 THEN N = N - 1 : R%(SP) = 0 : SP = SP + 1 : GOTO 200
REM A(M - 1, 1)
230 IF M > 0 THEN M = M - 1 : N = 1 : R%(SP) = 1 : SP = SP + 1 : GOTO 200
REM N + 1
240 ACK = N + 1
REM RETURN
250 M = M(SP) : N = N(SP) : IF SP = 0 THEN RETURN
260 FOR SP = SP - 1 TO 0 STEP -1 : IF R%(SP) THEN M = M(SP) : N = N(SP) : NEXT SP : SP = 0 : RETURN
270 M = M - 1 : N = ACK : R%(SP) = 1 : SP = SP + 1 : GOTO 200
BASIC256
dim stack(5000, 3) # BASIC-256 lacks functions (as of ver. 0.9.6.66)
stack[0,0] = 3 # M
stack[0,1] = 7 # N
lev = 0
gosub ackermann
print "A("+stack[0,0]+","+stack[0,1]+") = "+stack[0,2]
end
ackermann:
if stack[lev,0]=0 then
stack[lev,2] = stack[lev,1]+1
return
end if
if stack[lev,1]=0 then
lev = lev+1
stack[lev,0] = stack[lev-1,0]-1
stack[lev,1] = 1
gosub ackermann
stack[lev-1,2] = stack[lev,2]
lev = lev-1
return
end if
lev = lev+1
stack[lev,0] = stack[lev-1,0]
stack[lev,1] = stack[lev-1,1]-1
gosub ackermann
stack[lev,0] = stack[lev-1,0]-1
stack[lev,1] = stack[lev,2]
gosub ackermann
stack[lev-1,2] = stack[lev,2]
lev = lev-1
return
- Output:
A(3,7) = 1021
# BASIC256 since 0.9.9.1 supports functions
for m = 0 to 3
for n = 0 to 4
print m + " " + n + " " + ackermann(m,n)
next n
next m
end
function ackermann(m,n)
if m = 0 then
ackermann = n+1
else
if n = 0 then
ackermann = ackermann(m-1,1)
else
ackermann = ackermann(m-1,ackermann(m,n-1))
endif
end if
end function
- Output:
0 0 1 0 1 2 0 2 3 0 3 4 0 4 5 1 0 2 1 1 3 1 2 4 1 3 5 1 4 6 2 0 3 2 1 5 2 2 7 2 3 9 2 4 11 3 0 5 3 1 13 3 2 29 3 3 61 3 4 125
BBC BASIC
PRINT FNackermann(3, 7)
END
DEF FNackermann(M%, N%)
IF M% = 0 THEN = N% + 1
IF N% = 0 THEN = FNackermann(M% - 1, 1)
= FNackermann(M% - 1, FNackermann(M%, N%-1))
Chipmunk Basic
100 for m = 0 to 4
110 print using "###";m;
120 for n = 0 to 6
130 if m = 4 and n = 1 then goto 160
140 print using "######";ack(m,n);
150 next n
160 print
170 next m
180 end
190 sub ack(m,n)
200 if m = 0 then ack = n+1
210 if m > 0 and n = 0 then ack = ack(m-1,1)
220 if m > 0 and n > 0 then ack = ack(m-1,ack(m,n-1))
230 end sub
True BASIC
FUNCTION ack(m, n)
IF m = 0 THEN LET ack = n+1
IF m > 0 AND n = 0 THEN LET ack = ack(m-1, 1)
IF m > 0 AND n > 0 THEN LET ack = ack(m-1, ack(m, n-1))
END FUNCTION
FOR m = 0 TO 4
PRINT USING "###": m;
FOR n = 0 TO 8
! A(4, 1) OR higher will RUN OUT of stack memory (default 1M)
! change n = 1 TO n = 2 TO calculate A(4, 2), increase stack!
IF m = 4 AND n = 1 THEN EXIT FOR
PRINT USING "######": ack(m, n);
NEXT n
PRINT
NEXT m
END
QuickBasic
BASIC runs out of stack space very quickly. The call ack(3, 4) gives a stack error.
DECLARE FUNCTION ack! (m!, n!)
FUNCTION ack (m!, n!)
IF m = 0 THEN ack = n + 1
IF m > 0 AND n = 0 THEN
ack = ack(m - 1, 1)
END IF
IF m > 0 AND n > 0 THEN
ack = ack(m - 1, ack(m, n - 1))
END IF
END FUNCTION
Batch File
Had trouble with this, so called in the gurus at StackOverflow. Thanks to Patrick Cuff for pointing out where I was going wrong.
::Ackermann.cmd
@echo off
set depth=0
:ack
if %1==0 goto m0
if %2==0 goto n0
:else
set /a n=%2-1
set /a depth+=1
call :ack %1 %n%
set t=%errorlevel%
set /a depth-=1
set /a m=%1-1
set /a depth+=1
call :ack %m% %t%
set t=%errorlevel%
set /a depth-=1
if %depth%==0 ( exit %t% ) else ( exit /b %t% )
:m0
set/a n=%2+1
if %depth%==0 ( exit %n% ) else ( exit /b %n% )
:n0
set /a m=%1-1
set /a depth+=1
call :ack %m% 1
set t=%errorlevel%
set /a depth-=1
if %depth%==0 ( exit %t% ) else ( exit /b %t% )
Because of the exit
statements, running this bare closes one's shell, so this test routine handles the calling of Ackermann.cmd
::Ack.cmd
@echo off
cmd/c ackermann.cmd %1 %2
echo Ackermann(%1, %2)=%errorlevel%
A few test runs:
D:\Documents and Settings\Bruce>ack 0 4 Ackermann(0, 4)=5 D:\Documents and Settings\Bruce>ack 1 4 Ackermann(1, 4)=6 D:\Documents and Settings\Bruce>ack 2 4 Ackermann(2, 4)=11 D:\Documents and Settings\Bruce>ack 3 4 Ackermann(3, 4)=125
bc
Requires a bc that supports long names and the print statement.
define ack(m, n) {
if ( m == 0 ) return (n+1);
if ( n == 0 ) return (ack(m-1, 1));
return (ack(m-1, ack(m, n-1)));
}
for (n=0; n<7; n++) {
for (m=0; m<4; m++) {
print "A(", m, ",", n, ") = ", ack(m,n), "\n";
}
}
quit
BCPL
GET "libhdr"
LET ack(m, n) = m=0 -> n+1,
n=0 -> ack(m-1, 1),
ack(m-1, ack(m, n-1))
LET start() = VALOF
{ FOR i = 0 TO 6 FOR m = 0 TO 3 DO
writef("ack(%n, %n) = %n*n", m, n, ack(m,n))
RESULTIS 0
}
beeswax
Iterative slow version:
>M?f@h@gMf@h3yzp if m>0 and n>0 => replace m,n with m-1,m,n-1
>@h@g'b?1f@h@gM?f@hzp if m>0 and n=0 => replace m,n with m-1,1
_ii>Ag~1?~Lpz1~2h@g'd?g?Pfzp if m=0 => replace m,n with n+1
>I;
b < <
A functional and recursive realization of the version above. Functions are realized by direct calls of functions via jumps (instruction J
) to the entry points of two distinct functions:
1st function _ii
(input function) with entry point at (row,col) = (4,1)
2nd function Ag~1....
(Ackermann function) with entry point at (row,col) = (1,1)
Each block of 1FJ
or 1fFJ
in the code is a call of the Ackermann function itself.
Ag~1?Lp1~2@g'p?g?Pf1FJ Ackermann function. if m=0 => run Ackermann function (m, n+1)
xI; x@g'p??@Mf1fFJ if m>0 and n=0 => run Ackermann (m-1,1)
xM@~gM??f~f@f1FJ if m>0 and n>0 => run Ackermann(m,Ackermann(m-1,n-1))
_ii1FJ input function. Input m,n, then execute Ackermann(m,n)
Highly optimized and fast version, returns A(4,1)/A(5,0) almost instantaneously:
>Mf@Ph?@g@2h@Mf@Php if m>4 and n>0 => replace m,n with m-1,m,n-1
>~4~L#1~2hg'd?1f@hgM?f2h p if m>4 and n=0 => replace m,n with m-1,1
# q < /n+3 times \
#X~4K#?2Fg?PPP>@B@M"pb if m=4 => replace m,n with 2^(2^(....)))-3
# >~3K#?g?PPP~2BMMp>@MMMp if m=3 => replace m,n with 2^(n+3)-3
_ii>Ag~1?~Lpz1~2h@gX'#?g?P p M if m=0 => replace m,n with n+1
z I ~>~1K#?g?PP p if m=1 => replace m,n with n+2
f ; >2K#?g?~2.PPPp if m=2 => replace m,n with 2n+3
z b < < <
d <
Higher values than A(4,1)/(5,0) lead to UInt64 wraparound, support for numbers bigger than 2^64-1 is not implemented in these solutions.
Befunge
Befunge-93
Since Befunge-93 doesn't have recursive capabilities we need to use an iterative algorithm.
&>&>vvg0>#0\#-:#1_1v
@v:\<vp0 0:-1<\+<
^>00p>:#^_$1+\:#^_$.
Befunge-98
r[1&&{0
>v
j
u>.@
1> \:v
^ v:\_$1+
\^v_$1\1-
u^>1-0fp:1-\0fg101-
The program reads two integers (first m, then n) from command line, idles around funge space, then outputs the result of the Ackerman function. Since the latter is calculated truly recursively, the execution time becomes unwieldy for most m>3.
Binary Lambda Calculus
The Ackermann function on Church numerals (arbitrary precision), as shown in https://github.com/tromp/AIT/blob/master/fast_growing_and_conjectures/ackermann.lam is the 63 bit BLC program
010000010110000001010111110101100010110000000011100101111011010
BQN
A ← {
A 0‿n: n+1;
A m‿0: A (m-1)‿1;
A m‿n: A (m-1)‿(A m‿(n-1))
}
Example usage:
A 0‿3
4
A 1‿4
6
A 2‿4
11
A 3‿4
125
Bracmat
Three solutions are presented here. The first one is a purely recursive version, only using the formulas at the top of the page. The value of A(4,1) cannot be computed due to stack overflow. It can compute A(3,9) (4093), but probably not A(3,10)
( Ack
= m n
. !arg:(?m,?n)
& ( !m:0&!n+1
| !n:0&Ack$(!m+-1,1)
| Ack$(!m+-1,Ack$(!m,!n+-1))
)
);
The second version is a purely non-recursive solution that easily can compute A(4,1). The program uses a stack for Ackermann function calls that are to be evaluated, but that cannot be computed given the currently known function values - the "known unknowns". The currently known values are stored in a hash table. The Hash table also contains incomplete Ackermann function calls, namely those for which the second argument is not known yet - "the unknown unknowns". These function calls are associated with "known unknowns" that are going to provide the value of the second argument. As soon as such an associated known unknown becomes known, the unknown unknown becomes a known unknown and is pushed onto the stack.
Although all known values are stored in the hash table, the converse is not true: an element in the hash table is either a "known known" or an "unknown unknown" associated with an "known unknown".
( A
= m n value key eq chain
, find insert future stack va val
. ( chain
= key future skey
. !arg:(?key.?future)
& str$!key:?skey
& (cache..insert)$(!skey..!future)
&
)
& (find=.(cache..find)$(str$!arg))
& ( insert
= key value future v futureeq futurem skey
. !arg:(?key.?value)
& str$!key:?skey
& ( (cache..find)$!skey:(?key.?v.?future)
& (cache..remove)$!skey
& (cache..insert)$(!skey.!value.)
& ( !future:(?futurem.?futureeq)
& (!futurem,!value.!futureeq)
|
)
| (cache..insert)$(!skey.!value.)&
)
)
& !arg:(?m,?n)
& !n+1:?value
& :?eq:?stack
& whl
' ( (!m,!n):?key
& ( find$!key:(?.#%?value.?future)
& insert$(!eq.!value) !future
| !m:0
& !n+1:?value
& ( !eq:&insert$(!key.!value)
| insert$(!key.!value) !stack:?stack
& insert$(!eq.!value)
)
| !n:0
& (!m+-1,1.!key)
(!eq:|(!key.!eq))
| find$(!m,!n+-1):(?.?val.?)
& ( !val:#%
& ( find$(!m+-1,!val):(?.?va.?)
& !va:#%
& insert$(!key.!va)
| (!m+-1,!val.!eq)
(!m,!n.!eq)
)
|
)
| chain$(!m,!n+-1.!m+-1.!key)
& (!m,!n+-1.)
(!eq:|(!key.!eq))
)
!stack
: (?m,?n.?eq) ?stack
)
& !value
)
& new$hash:?cache
- Some results:
A$(0,0):1 A$(3,13):65533 A$(3,14):131069 A$(4,1):65533
The last solution is a recursive solution that employs some extra formulas, inspired by the Common Lisp solution further down.
( AckFormula
= m n
. !arg:(?m,?n)
& ( !m:0&!n+1
| !m:1&!n+2
| !m:2&2*!n+3
| !m:3&2^(!n+3)+-3
| !n:0&AckFormula$(!m+-1,1)
| AckFormula$(!m+-1,AckFormula$(!m,!n+-1))
)
)
- Some results:
AckFormula$(4,1):65533 AckFormula$(4,2):2003529930406846464979072351560255750447825475569751419265016973.....22087777506072339445587895905719156733
The last computation costs about 0,03 seconds.
Brat
ackermann = { m, n |
when { m == 0 } { n + 1 }
{ m > 0 && n == 0 } { ackermann(m - 1, 1) }
{ m > 0 && n > 0 } { ackermann(m - 1, ackermann(m, n - 1)) }
}
p ackermann 3, 4 #Prints 125
Bruijn
:import std/Combinator .
:import std/Number/Unary U
:import std/Math .
# unary ackermann
ackermann-unary [0 [[U.inc 0 1 (+1u)]] U.inc]
:test (ackermann-unary (+0u) (+0u)) ((+1u))
:test (ackermann-unary (+3u) (+4u)) ((+125u))
# ternary ackermann (lower space complexity)
ackermann-ternary y [[[=?1 ++0 (=?0 (2 --1 (+1)) (2 --1 (2 1 --0)))]]]
:test ((ackermann-ternary (+0) (+0)) =? (+1)) ([[1]])
:test ((ackermann-ternary (+3) (+4)) =? (+125)) ([[1]])
C
Straightforward implementation per Ackermann definition:
#include <stdio.h>
int ackermann(int m, int n)
{
if (!m) return n + 1;
if (!n) return ackermann(m - 1, 1);
return ackermann(m - 1, ackermann(m, n - 1));
}
int main()
{
int m, n;
for (m = 0; m <= 4; m++)
for (n = 0; n < 6 - m; n++)
printf("A(%d, %d) = %d\n", m, n, ackermann(m, n));
return 0;
}
- Output:
A(0, 0) = 1 A(0, 1) = 2 A(0, 2) = 3 A(0, 3) = 4 A(0, 4) = 5 A(0, 5) = 6 A(1, 0) = 2 A(1, 1) = 3 A(1, 2) = 4 A(1, 3) = 5 A(1, 4) = 6 A(2, 0) = 3 A(2, 1) = 5 A(2, 2) = 7 A(2, 3) = 9 A(3, 0) = 5 A(3, 1) = 13 A(3, 2) = 29 A(4, 0) = 13 A(4, 1) = 65533
Ackermann function makes a lot of recursive calls, so the above program is a bit naive. We need to be slightly less naive, by doing some simple caching:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int m_bits, n_bits;
int *cache;
int ackermann(int m, int n)
{
int idx, res;
if (!m) return n + 1;
if (n >= 1<<n_bits) {
printf("%d, %d\n", m, n);
idx = 0;
} else {
idx = (m << n_bits) + n;
if (cache[idx]) return cache[idx];
}
if (!n) res = ackermann(m - 1, 1);
else res = ackermann(m - 1, ackermann(m, n - 1));
if (idx) cache[idx] = res;
return res;
}
int main()
{
int m, n;
m_bits = 3;
n_bits = 20; /* can save n values up to 2**20 - 1, that's 1 meg */
cache = malloc(sizeof(int) * (1 << (m_bits + n_bits)));
memset(cache, 0, sizeof(int) * (1 << (m_bits + n_bits)));
for (m = 0; m <= 4; m++)
for (n = 0; n < 6 - m; n++)
printf("A(%d, %d) = %d\n", m, n, ackermann(m, n));
return 0;
}
- Output:
A(0, 0) = 1 A(0, 1) = 2 A(0, 2) = 3 A(0, 3) = 4 A(0, 4) = 5 A(0, 5) = 6 A(1, 0) = 2 A(1, 1) = 3 A(1, 2) = 4 A(1, 3) = 5 A(1, 4) = 6 A(2, 0) = 3 A(2, 1) = 5 A(2, 2) = 7 A(2, 3) = 9 A(3, 0) = 5 A(3, 1) = 13 A(3, 2) = 29 A(4, 0) = 13 A(4, 1) = 65533
Whee. Well, with some extra work, we calculated one more n value, big deal, right?
But see, A(4, 2) = A(3, A(4, 1)) = A(3, 65533) = A(2, A(3, 65532)) = ...
you can see how fast it blows up. In fact, no amount of caching will help you calculate large m values; on the machine I use A(4, 2) segfaults because the recursions run out of stack space--not a whole lot I can do about it. At least it runs out of stack space quickly, unlike the first solution...
A couple of alternative approaches...
/* Thejaka Maldeniya */
#include <conio.h>
unsigned long long HR(unsigned int n, unsigned long long a, unsigned long long b) {
// (Internal) Recursive Hyperfunction: Perform a Hyperoperation...
unsigned long long r = 1;
while(b--)
r = n - 3 ? HR(n - 1, a, r) : /* Exponentiation */ r * a;
return r;
}
unsigned long long H(unsigned int n, unsigned long long a, unsigned long long b) {
// Hyperfunction (Recursive-Iterative-O(1) Hybrid): Perform a Hyperoperation...
switch(n) {
case 0:
// Increment
return ++b;
case 1:
// Addition
return a + b;
case 2:
// Multiplication
return a * b;
}
return HR(n, a, b);
}
unsigned long long APH(unsigned int m, unsigned int n) {
// Ackermann-Péter Function (Recursive-Iterative-O(1) Hybrid)
return H(m, 2, n + 3) - 3;
}
unsigned long long * p = 0;
unsigned long long APRR(unsigned int m, unsigned int n) {
if (!m) return ++n;
unsigned long long r = p ? p[m] : APRR(m - 1, 1);
--m;
while(n--)
r = APRR(m, r);
return r;
}
unsigned long long APRA(unsigned int m, unsigned int n) {
return
m ?
n ?
APRR(m, n)
: p ? p[m] : APRA(--m, 1)
: ++n
;
}
unsigned long long APR(unsigned int m, unsigned int n) {
unsigned long long r = 0;
// Allocate
p = (unsigned long long *) malloc(sizeof(unsigned long long) * (m + 1));
// Initialize
for(; r <= m; ++r)
p[r] = r ? APRA(r - 1, 1) : APRA(r, 0);
// Calculate
r = APRA(m, n);
// Free
free(p);
return r;
}
unsigned long long AP(unsigned int m, unsigned int n) {
return APH(m, n);
return APR(m, n);
}
int main(int n, char ** a) {
unsigned int M, N;
if (n != 3) {
printf("Usage: %s <m> <n>\n", *a);
return 1;
}
printf("AckermannPeter(%u, %u) = %llu\n", M = atoi(a[1]), N = atoi(a[2]), AP(M, N));
//printf("\nPress any key...");
//getch();
return 0;
}
A couple of more iterative techniques...
/* Thejaka Maldeniya */
#include <conio.h>
unsigned long long HI(unsigned int n, unsigned long long a, unsigned long long b) {
// Hyperfunction (Iterative): Perform a Hyperoperation...
unsigned long long *I, r = 1;
unsigned int N = n - 3;
if (!N)
// Exponentiation
while(b--)
r *= a;
else if(b) {
n -= 2;
// Allocate
I = (unsigned long long *) malloc(sizeof(unsigned long long) * n--);
// Initialize
I[n] = b;
// Calculate
for(;;) {
if(I[n]) {
--I[n];
if (n)
I[--n] = r, r = 1;
else
r *= a;
} else
for(;;)
if (n == N)
goto a;
else if(I[++n])
break;
}
a:
// Free
free(I);
}
return r;
}
unsigned long long H(unsigned int n, unsigned long long a, unsigned long long b) {
// Hyperfunction (Iterative-O(1) Hybrid): Perform a Hyperoperation...
switch(n) {
case 0:
// Increment
return ++b;
case 1:
// Addition
return a + b;
case 2:
// Multiplication
return a * b;
}
return HI(n, a, b);
}
unsigned long long APH(unsigned int m, unsigned int n) {
// Ackermann-Péter Function (Recursive-Iterative-O(1) Hybrid)
return H(m, 2, n + 3) - 3;
}
unsigned long long * p = 0;
unsigned long long APIA(unsigned int m, unsigned int n) {
if (!m) return ++n;
// Initialize
unsigned long long *I, r = p ? p[m] : APIA(m - 1, 1);
unsigned int M = m;
if (n) {
// Allocate
I = (unsigned long long *) malloc(sizeof(unsigned long long) * (m + 1));
// Initialize
I[m] = n;
// Calculate
for(;;) {
if(I[m]) {
if (m)
--I[m], I[--m] = r, r = p ? p[m] : APIA(m - 1, 1);
else
r += I[m], I[m] = 0;
} else
for(;;)
if (m == M)
goto a;
else if(I[++m])
break;
}
a:
// Free
free(I);
}
return r;
}
unsigned long long API(unsigned int m, unsigned int n) {
unsigned long long r = 0;
// Allocate
p = (unsigned long long *) malloc(sizeof(unsigned long long) * (m + 1));
// Initialize
for(; r <= m; ++r)
p[r] = r ? APIA(r - 1, 1) : APIA(r, 0);
// Calculate
r = APIA(m, n);
// Free
free(p);
return r;
}
unsigned long long AP(unsigned int m, unsigned int n) {
return APH(m, n);
return API(m, n);
}
int main(int n, char ** a) {
unsigned int M, N;
if (n != 3) {
printf("Usage: %s <m> <n>\n", *a);
return 1;
}
printf("AckermannPeter(%u, %u) = %llu\n", M = atoi(a[1]), N = atoi(a[2]), AP(M, N));
//printf("\nPress any key...");
//getch();
return 0;
}
A few further tweaks/optimizations may be possible.
C#
Basic Version
using System;
class Program
{
public static long Ackermann(long m, long n)
{
if(m > 0)
{
if (n > 0)
return Ackermann(m - 1, Ackermann(m, n - 1));
else if (n == 0)
return Ackermann(m - 1, 1);
}
else if(m == 0)
{
if(n >= 0)
return n + 1;
}
throw new System.ArgumentOutOfRangeException();
}
static void Main()
{
for (long m = 0; m <= 3; ++m)
{
for (long n = 0; n <= 4; ++n)
{
Console.WriteLine("Ackermann({0}, {1}) = {2}", m, n, Ackermann(m, n));
}
}
}
}
- Output:
Ackermann(0, 0) = 1 Ackermann(0, 1) = 2 Ackermann(0, 2) = 3 Ackermann(0, 3) = 4 Ackermann(0, 4) = 5 Ackermann(1, 0) = 2 Ackermann(1, 1) = 3 Ackermann(1, 2) = 4 Ackermann(1, 3) = 5 Ackermann(1, 4) = 6 Ackermann(2, 0) = 3 Ackermann(2, 1) = 5 Ackermann(2, 2) = 7 Ackermann(2, 3) = 9 Ackermann(2, 4) = 11 Ackermann(3, 0) = 5 Ackermann(3, 1) = 13 Ackermann(3, 2) = 29 Ackermann(3, 3) = 61 Ackermann(3, 4) = 125
Efficient Version
using System;
using System.Numerics;
using System.IO;
using System.Diagnostics;
namespace Ackermann_Function
{
class Program
{
static void Main(string[] args)
{
int _m = 0;
int _n = 0;
Console.Write("m = ");
try
{
_m = Convert.ToInt32(Console.ReadLine());
}
catch (Exception)
{
Console.WriteLine("Please enter a number.");
}
Console.Write("n = ");
try
{
_n = Convert.ToInt32(Console.ReadLine());
}
catch (Exception)
{
Console.WriteLine("Please enter a number.");
}
//for (long m = 0; m <= 10; ++m)
//{
// for (long n = 0; n <= 10; ++n)
// {
// DateTime now = DateTime.Now;
// Console.WriteLine("Ackermann({0}, {1}) = {2}", m, n, Ackermann(m, n));
// Console.WriteLine("Time taken:{0}", DateTime.Now - now);
// }
//}
DateTime now = DateTime.Now;
Console.WriteLine("Ackermann({0}, {1}) = {2}", _m, _n, Ackermann(_m, _n));
Console.WriteLine("Time taken:{0}", DateTime.Now - now);
File.WriteAllText("number.txt", Ackermann(_m, _n).ToString());
Process.Start("number.txt");
Console.ReadKey();
}
public class OverflowlessStack<T>
{
internal sealed class SinglyLinkedNode
{
private const int ArraySize = 2048;
T[] _array;
int _size;
public SinglyLinkedNode Next;
public SinglyLinkedNode()
{
_array = new T[ArraySize];
}
public bool IsEmpty { get { return _size == 0; } }
public SinglyLinkedNode Push(T item)
{
if (_size == ArraySize - 1)
{
SinglyLinkedNode n = new SinglyLinkedNode();
n.Next = this;
n.Push(item);
return n;
}
_array[_size++] = item;
return this;
}
public T Pop()
{
return _array[--_size];
}
}
private SinglyLinkedNode _head = new SinglyLinkedNode();
public T Pop()
{
T ret = _head.Pop();
if (_head.IsEmpty && _head.Next != null)
_head = _head.Next;
return ret;
}
public void Push(T item)
{
_head = _head.Push(item);
}
public bool IsEmpty
{
get { return _head.Next == null && _head.IsEmpty; }
}
}
public static BigInteger Ackermann(BigInteger m, BigInteger n)
{
var stack = new OverflowlessStack<BigInteger>();
stack.Push(m);
while (!stack.IsEmpty)
{
m = stack.Pop();
skipStack:
if (m == 0)
n = n + 1;
else if (m == 1)
n = n + 2;
else if (m == 2)
n = n * 2 + 3;
else if (n == 0)
{
--m;
n = 1;
goto skipStack;
}
else
{
stack.Push(m - 1);
--n;
goto skipStack;
}
}
return n;
}
}
}
Possibly the most efficient implementation of Ackermann in C#. It successfully runs Ack(4,2) when executed in Visual Studio. Don't forget to add a reference to System.Numerics.
C++
Basic version
#include <iostream>
unsigned int ackermann(unsigned int m, unsigned int n) {
if (m == 0) {
return n + 1;
}
if (n == 0) {
return ackermann(m - 1, 1);
}
return ackermann(m - 1, ackermann(m, n - 1));
}
int main() {
for (unsigned int m = 0; m < 4; ++m) {
for (unsigned int n = 0; n < 10; ++n) {
std::cout << "A(" << m << ", " << n << ") = " << ackermann(m, n) << "\n";
}
}
}
Efficient version
C++11 with boost's big integer type. Compile with:
g++ -std=c++11 -I /path/to/boost ackermann.cpp.
#include <iostream>
#include <sstream>
#include <string>
#include <boost/multiprecision/cpp_int.hpp>
using big_int = boost::multiprecision::cpp_int;
big_int ipow(big_int base, big_int exp) {
big_int result(1);
while (exp) {
if (exp & 1) {
result *= base;
}
exp >>= 1;
base *= base;
}
return result;
}
big_int ackermann(unsigned m, unsigned n) {
static big_int (*ack)(unsigned, big_int) =
[](unsigned m, big_int n)->big_int {
switch (m) {
case 0:
return n + 1;
case 1:
return n + 2;
case 2:
return 3 + 2 * n;
case 3:
return 5 + 8 * (ipow(big_int(2), n) - 1);
default:
return n == 0 ? ack(m - 1, big_int(1)) : ack(m - 1, ack(m, n - 1));
}
};
return ack(m, big_int(n));
}
int main() {
for (unsigned m = 0; m < 4; ++m) {
for (unsigned n = 0; n < 10; ++n) {
std::cout << "A(" << m << ", " << n << ") = " << ackermann(m, n) << "\n";
}
}
std::cout << "A(4, 1) = " << ackermann(4, 1) << "\n";
std::stringstream ss;
ss << ackermann(4, 2);
auto text = ss.str();
std::cout << "A(4, 2) = (" << text.length() << " digits)\n"
<< text.substr(0, 80) << "\n...\n"
<< text.substr(text.length() - 80) << "\n";
}
<pre> A(0, 0) = 1 A(0, 1) = 2 A(0, 2) = 3 A(0, 3) = 4 A(0, 4) = 5 A(0, 5) = 6 A(0, 6) = 7 A(0, 7) = 8 A(0, 8) = 9 A(0, 9) = 10 A(1, 0) = 2 A(1, 1) = 3 A(1, 2) = 4 A(1, 3) = 5 A(1, 4) = 6 A(1, 5) = 7 A(1, 6) = 8 A(1, 7) = 9 A(1, 8) = 10 A(1, 9) = 11 A(2, 0) = 3 A(2, 1) = 5 A(2, 2) = 7 A(2, 3) = 9 A(2, 4) = 11 A(2, 5) = 13 A(2, 6) = 15 A(2, 7) = 17 A(2, 8) = 19 A(2, 9) = 21 A(3, 0) = 5 A(3, 1) = 13 A(3, 2) = 29 A(3, 3) = 61 A(3, 4) = 125 A(3, 5) = 253 A(3, 6) = 509 A(3, 7) = 1021 A(3, 8) = 2045 A(3, 9) = 4093 A(4, 1) = 65533 A(4, 2) = (19729 digits) 2003529930406846464979072351560255750447825475569751419265016973710894059556311 ... 4717124577965048175856395072895337539755822087777506072339445587895905719156733
Chapel
proc A(m:int, n:int):int {
if m == 0 then
return n + 1;
else if n == 0 then
return A(m - 1, 1);
else
return A(m - 1, A(m, n - 1));
}
Clay
ackermann(m, n) {
if(m == 0)
return n + 1;
if(n == 0)
return ackermann(m - 1, 1);
return ackermann(m - 1, ackermann(m, n - 1));
}
CLIPS
Functional solution
(deffunction ackerman
(?m ?n)
(if (= 0 ?m)
then (+ ?n 1)
else (if (= 0 ?n)
then (ackerman (- ?m 1) 1)
else (ackerman (- ?m 1) (ackerman ?m (- ?n 1)))
)
)
)
- Example usage:
CLIPS> (ackerman 0 4) 5 CLIPS> (ackerman 1 4) 6 CLIPS> (ackerman 2 4) 11 CLIPS> (ackerman 3 4) 125
Fact-based solution
(deffacts solve-items
(solve 0 4)
(solve 1 4)
(solve 2 4)
(solve 3 4)
)
(defrule acker-m-0
?compute <- (compute 0 ?n)
=>
(retract ?compute)
(assert (ackerman 0 ?n (+ ?n 1)))
)
(defrule acker-n-0-pre
(compute ?m&:(> ?m 0) 0)
(not (ackerman =(- ?m 1) 1 ?))
=>
(assert (compute (- ?m 1) 1))
)
(defrule acker-n-0
?compute <- (compute ?m&:(> ?m 0) 0)
(ackerman =(- ?m 1) 1 ?val)
=>
(retract ?compute)
(assert (ackerman ?m 0 ?val))
)
(defrule acker-m-n-pre-1
(compute ?m&:(> ?m 0) ?n&:(> ?n 0))
(not (ackerman ?m =(- ?n 1) ?))
=>
(assert (compute ?m (- ?n 1)))
)
(defrule acker-m-n-pre-2
(compute ?m&:(> ?m 0) ?n&:(> ?n 0))
(ackerman ?m =(- ?n 1) ?newn)
(not (ackerman =(- ?m 1) ?newn ?))
=>
(assert (compute (- ?m 1) ?newn))
)
(defrule acker-m-n
?compute <- (compute ?m&:(> ?m 0) ?n&:(> ?n 0))
(ackerman ?m =(- ?n 1) ?newn)
(ackerman =(- ?m 1) ?newn ?val)
=>
(retract ?compute)
(assert (ackerman ?m ?n ?val))
)
(defrule acker-solve
(solve ?m ?n)
(not (compute ?m ?n))
(not (ackerman ?m ?n ?))
=>
(assert (compute ?m ?n))
)
(defrule acker-solved
?solve <- (solve ?m ?n)
(ackerman ?m ?n ?result)
=>
(retract ?solve)
(printout t "A(" ?m "," ?n ") = " ?result crlf)
)
When invoked, each required A(m,n) needed to solve the requested (solve ?m ?n) facts gets generated as its own fact. Below shows the invocation of the above, as well as an excerpt of the final facts list. Regardless of how many input (solve ?m ?n) requests are made, each possible A(m,n) is only solved once.
CLIPS> (reset) CLIPS> (facts) f-0 (initial-fact) f-1 (solve 0 4) f-2 (solve 1 4) f-3 (solve 2 4) f-4 (solve 3 4) For a total of 5 facts. CLIPS> (run) A(3,4) = 125 A(2,4) = 11 A(1,4) = 6 A(0,4) = 5 CLIPS> (facts) f-0 (initial-fact) f-15 (ackerman 0 1 2) f-16 (ackerman 1 0 2) f-18 (ackerman 0 2 3) ... f-632 (ackerman 1 123 125) f-633 (ackerman 2 61 125) f-634 (ackerman 3 4 125) For a total of 316 facts. CLIPS>
Clojure
(defn ackermann [m n]
(cond (zero? m) (inc n)
(zero? n) (ackermann (dec m) 1)
:else (ackermann (dec m) (ackermann m (dec n)))))
CLU
% Ackermann function
ack = proc (m, n: int) returns (int)
if m=0 then return(n+1)
elseif n=0 then return(ack(m-1, 1))
else return(ack(m-1, ack(m, n-1)))
end
end ack
% Print a table of ack( 0..3, 0..8 )
start_up = proc ()
po: stream := stream$primary_output()
for m: int in int$from_to(0, 3) do
for n: int in int$from_to(0, 8) do
stream$putright(po, int$unparse(ack(m,n)), 8)
end
stream$putl(po, "")
end
end start_up
- Output:
1 2 3 4 5 6 7 8 9 2 3 4 5 6 7 8 9 10 3 5 7 9 11 13 15 17 19 5 13 29 61 125 253 509 1021 2045
COBOL
IDENTIFICATION DIVISION.
PROGRAM-ID. Ackermann.
DATA DIVISION.
LINKAGE SECTION.
01 M USAGE UNSIGNED-LONG.
01 N USAGE UNSIGNED-LONG.
01 Return-Val USAGE UNSIGNED-LONG.
PROCEDURE DIVISION USING M N Return-Val.
EVALUATE M ALSO N
WHEN 0 ALSO ANY
ADD 1 TO N GIVING Return-Val
WHEN NOT 0 ALSO 0
SUBTRACT 1 FROM M
CALL "Ackermann" USING BY CONTENT M BY CONTENT 1
BY REFERENCE Return-Val
WHEN NOT 0 ALSO NOT 0
SUBTRACT 1 FROM N
CALL "Ackermann" USING BY CONTENT M BY CONTENT N
BY REFERENCE Return-Val
SUBTRACT 1 FROM M
CALL "Ackermann" USING BY CONTENT M
BY CONTENT Return-Val BY REFERENCE Return-Val
END-EVALUATE
GOBACK
.
CoffeeScript
ackermann = (m, n) ->
if m is 0 then n + 1
else if m > 0 and n is 0 then ackermann m - 1, 1
else ackermann m - 1, ackermann m, n - 1
Comal
0010 //
0020 // Ackermann function
0030 //
0040 FUNC a#(m#,n#)
0050 IF m#=0 THEN RETURN n#+1
0060 IF n#=0 THEN RETURN a#(m#-1,1)
0070 RETURN a#(m#-1,a#(m#,n#-1))
0080 ENDFUNC a#
0090 //
0100 // Print table of Ackermann values
0110 //
0120 ZONE 5
0130 FOR m#:=0 TO 3 DO
0140 FOR n#:=0 TO 4 DO PRINT a#(m#,n#),
0150 PRINT
0160 ENDFOR m#
0170 END
- Output:
1 2 3 4 5 2 3 4 5 6 3 5 7 9 11 5 13 29 61 125
Common Lisp
(defun ackermann (m n)
(cond ((zerop m) (1+ n))
((zerop n) (ackermann (1- m) 1))
(t (ackermann (1- m) (ackermann m (1- n))))))
More elaborately:
(defun ackermann (m n)
(case m ((0) (1+ n))
((1) (+ 2 n))
((2) (+ n n 3))
((3) (- (expt 2 (+ 3 n)) 3))
(otherwise (ackermann (1- m) (if (zerop n) 1 (ackermann m (1- n)))))))
(loop for m from 0 to 4 do
(loop for n from (- 5 m) to (- 6 m) do
(format t "A(~d, ~d) = ~d~%" m n (ackermann m n))))
- Output:
A(0, 5) = 6A(0, 6) = 7 A(1, 4) = 6 A(1, 5) = 7 A(2, 3) = 9 A(2, 4) = 11 A(3, 2) = 29 A(3, 3) = 61 A(4, 1) = 65533
A(4, 2) = 2003529930 <... skipping a few digits ...> 56733
Component Pascal
BlackBox Component Builder
MODULE NpctAckerman;
IMPORT StdLog;
VAR
m,n: INTEGER;
PROCEDURE Ackerman (x,y: INTEGER):INTEGER;
BEGIN
IF x = 0 THEN RETURN y + 1
ELSIF y = 0 THEN RETURN Ackerman (x - 1 , 1)
ELSE
RETURN Ackerman (x - 1 , Ackerman (x , y - 1))
END
END Ackerman;
PROCEDURE Do*;
BEGIN
FOR m := 0 TO 3 DO
FOR n := 0 TO 6 DO
StdLog.Int (Ackerman (m, n));StdLog.Char (' ')
END;
StdLog.Ln
END;
StdLog.Ln
END Do;
END NpctAckerman.
Execute: ^Q NpctAckerman.Do
<pre> 1 2 3 4 5 6 7 2 3 4 5 6 7 8 3 5 7 9 11 13 15 5 13 29 61 125 253 509
Coq
Standard
Fixpoint ack (m : nat) : nat -> nat :=
fix ack_m (n : nat) : nat :=
match m with
| 0 => S n
| S pm =>
match n with
| 0 => ack pm 1
| S pn => ack pm (ack_m pn)
end
end.
(*
Example:
A(3, 2) = 29
*)
Eval compute in ack 3 2.
- Output:
= 29 : nat
Using fold
Require Import Utf8.
Section FOLD.
Context {A : Type} (f : A → A) (a : A).
Fixpoint fold (n : nat) : A :=
match n with
| O => a
| S k => f (fold k)
end.
End FOLD.
Definition ackermann : nat → nat → nat :=
fold (λ g, fold g (g (S O))) S.
Crystal
def ack(m, n)
if m == 0
n + 1
elsif n == 0
ack(m-1, 1)
else
ack(m-1, ack(m, n-1))
end
end
#Example:
(0..3).each do |m|
puts (0..6).map { |n| ack(m, n) }.join(' ')
end
- Output:
1 2 3 4 5 6 7 2 3 4 5 6 7 8 3 5 7 9 11 13 15 5 13 29 61 125 253 509
D
Basic version
ulong ackermann(in ulong m, in ulong n) pure nothrow @nogc {
if (m == 0)
return n + 1;
if (n == 0)
return ackermann(m - 1, 1);
return ackermann(m - 1, ackermann(m, n - 1));
}
void main() {
assert(ackermann(2, 4) == 11);
}
More Efficient Version
import std.stdio, std.bigint, std.conv;
BigInt ipow(BigInt base, BigInt exp) pure nothrow {
auto result = 1.BigInt;
while (exp) {
if (exp & 1)
result *= base;
exp >>= 1;
base *= base;
}
return result;
}
BigInt ackermann(in uint m, in uint n) pure nothrow
out(result) {
assert(result >= 0);
} body {
static BigInt ack(in uint m, in BigInt n) pure nothrow {
switch (m) {
case 0: return n + 1;
case 1: return n + 2;
case 2: return 3 + 2 * n;
//case 3: return 5 + 8 * (2 ^^ n - 1);
case 3: return 5 + 8 * (ipow(2.BigInt, n) - 1);
default: return (n == 0) ?
ack(m - 1, 1.BigInt) :
ack(m - 1, ack(m, n - 1));
}
}
return ack(m, n.BigInt);
}
void main() {
foreach (immutable m; 1 .. 4)
foreach (immutable n; 1 .. 9)
writefln("ackermann(%d, %d): %s", m, n, ackermann(m, n));
writefln("ackermann(4, 1): %s", ackermann(4, 1));
immutable a = ackermann(4, 2).text;
writefln("ackermann(4, 2)) (%d digits):\n%s...\n%s",
a.length, a[0 .. 94], a[$ - 96 .. $]);
}
- Output:
ackermann(1, 1): 3 ackermann(1, 2): 4 ackermann(1, 3): 5 ackermann(1, 4): 6 ackermann(1, 5): 7 ackermann(1, 6): 8 ackermann(1, 7): 9 ackermann(1, 8): 10 ackermann(2, 1): 5 ackermann(2, 2): 7 ackermann(2, 3): 9 ackermann(2, 4): 11 ackermann(2, 5): 13 ackermann(2, 6): 15 ackermann(2, 7): 17 ackermann(2, 8): 19 ackermann(3, 1): 13 ackermann(3, 2): 29 ackermann(3, 3): 61 ackermann(3, 4): 125 ackermann(3, 5): 253 ackermann(3, 6): 509 ackermann(3, 7): 1021 ackermann(3, 8): 2045 ackermann(4, 1): 65533 ackermann(4, 2)) (19729 digits): 2003529930406846464979072351560255750447825475569751419265016973710894059556311453089506130880... 699146577530041384717124577965048175856395072895337539755822087777506072339445587895905719156733
Dart
no caching, the implementation takes ages even for A(4,1)
int A(int m, int n) => m==0 ? n+1 : n==0 ? A(m-1,1) : A(m-1,A(m,n-1));
main() {
print(A(0,0));
print(A(1,0));
print(A(0,1));
print(A(2,2));
print(A(2,3));
print(A(3,3));
print(A(3,4));
print(A(3,5));
print(A(4,0));
}
Dc
This needs a modern Dc with r
(swap) and #
(comment). It easily can be adapted to an older Dc, but it will impact readability a lot.
[ # todo: n 0 -- n+1 and break 2 levels
+ 1 + # n+1
q
] s1
[ # todo: m 0 -- A(m-1,1) and break 2 levels
+ 1 - # m-1
1 # m-1 1
lA x # A(m-1,1)
q
] s2
[ # todo: m n -- A(m,n)
r d 0=1 # n m(!=0)
r d 0=2 # m(!=0) n(!=0)
Sn # m(!=0)
d 1 - r # m-1 m
Ln 1 - # m-1 m n-1
lA x # m-1 A(m,n-1)
lA x # A(m-1,A(m,n-1))
] sA
3 9 lA x f
- Output:
4093
Delphi
function Ackermann(m,n:Int64):Int64;
begin
if m = 0 then
Result := n + 1
else if n = 0 then
Result := Ackermann(m-1, 1)
else
Result := Ackermann(m-1, Ackermann(m, n - 1));
end;
Draco
/* Ackermann function */
proc ack(word m, n) word:
if m=0 then n+1
elif n=0 then ack(m-1, 1)
else ack(m-1, ack(m, n-1))
fi
corp;
/* Write a table of Ackermann values */
proc nonrec main() void:
byte m, n;
for m from 0 upto 3 do
for n from 0 upto 8 do
write(ack(m,n) : 5)
od;
writeln()
od
corp
- Output:
1 2 3 4 5 6 7 8 9 2 3 4 5 6 7 8 9 10 3 5 7 9 11 13 15 17 19 5 13 29 61 125 253 509 1021 2045
DWScript
function Ackermann(m, n : Integer) : Integer;
begin
if m = 0 then
Result := n+1
else if n = 0 then
Result := Ackermann(m-1, 1)
else Result := Ackermann(m-1, Ackermann(m, n-1));
end;
Dylan
define method ack(m == 0, n :: <integer>)
n + 1
end;
define method ack(m :: <integer>, n :: <integer>)
ack(m - 1, if (n == 0) 1 else ack(m, n - 1) end)
end;
E
def A(m, n) {
return if (m <=> 0) { n+1 } \
else if (m > 0 && n <=> 0) { A(m-1, 1) } \
else { A(m-1, A(m,n-1)) }
}
EasyLang
func ackerm m n .
if m = 0
return n + 1
elif n = 0
return ackerm (m - 1) 1
else
return ackerm (m - 1) ackerm m (n - 1)
.
.
print ackerm 3 6
Egel
def ackermann =
[ 0 N -> N + 1
| M 0 -> ackermann (M - 1) 1
| M N -> ackermann (M - 1) (ackermann M (N - 1)) ]
Eiffel
class
ACKERMAN_EXAMPLE
feature -- Basic Operations
ackerman (m, n: NATURAL): NATURAL
-- Recursively compute the n-th term of a series.
require
non_negative_m: m >= 0
non_negative_n: n >= 0
do
if m = 0 then
Result := n + 1
elseif m > 0 and n = 0 then
Result := ackerman (m - 1, 1)
elseif m > 0 and n > 0 then
Result := ackerman (m - 1, ackerman (m, n - 1))
else
check invalid_arg_state: False end
end
end
end
Ela
ack 0 n = n+1
ack m 0 = ack (m - 1) 1
ack m n = ack (m - 1) <| ack m <| n - 1
Elena
ELENA 6.x :
import extensions;
ackermann(m,n)
{
if(n < 0 || m < 0)
{
InvalidArgumentException.raise()
};
m =>
0 { ^n + 1 }
! {
n =>
0 { ^ackermann(m - 1,1) }
! { ^ackermann(m - 1,ackermann(m,n-1)) }
}
}
public program()
{
for(int i:=0; i <= 3; i += 1)
{
for(int j := 0; j <= 5; j += 1)
{
console.printLine("A(",i,",",j,")=",ackermann(i,j))
}
};
console.readChar()
}
- Output:
A(0,0)=1 A(0,1)=2 A(0,2)=3 A(0,3)=4 A(0,4)=5 A(0,5)=6 A(1,0)=2 A(1,1)=3 A(1,2)=4 A(1,3)=5 A(1,4)=6 A(1,5)=7 A(2,0)=3 A(2,1)=5 A(2,2)=7 A(2,3)=9 A(2,4)=11 A(2,5)=13 A(3,0)=5 A(3,1)=13 A(3,2)=29 A(3,3)=61 A(3,4)=125 A(3,5)=253
Elixir
defmodule Ackermann do
def ack(0, n), do: n + 1
def ack(m, 0), do: ack(m - 1, 1)
def ack(m, n), do: ack(m - 1, ack(m, n - 1))
end
Enum.each(0..3, fn m ->
IO.puts Enum.map_join(0..6, " ", fn n -> Ackermann.ack(m, n) end)
end)
- Output:
1 2 3 4 5 6 7 2 3 4 5 6 7 8 3 5 7 9 11 13 15 5 13 29 61 125 253 509
Emacs Lisp
(defun ackermann (m n)
(cond ((zerop m) (1+ n))
((zerop n) (ackermann (1- m) 1))
(t (ackermann (1- m)
(ackermann m (1- n))))))
EMal
fun ackermann = int by int m, int n
return when(m == 0,
n + 1,
when(n == 0,
ackermann(m - 1, 1),
ackermann(m - 1, ackermann(m, n - 1))))
end
for int m = 0; m <= 3; ++m
for int n = 0; n <= 6; ++n
writeLine("Ackermann(" + m + ", " + n + ") = " + ackermann(m, n))
end
end
- Output:
Ackermann(0, 0) = 1 Ackermann(0, 1) = 2 Ackermann(0, 2) = 3 Ackermann(0, 3) = 4 Ackermann(0, 4) = 5 Ackermann(0, 5) = 6 Ackermann(0, 6) = 7 Ackermann(1, 0) = 2 Ackermann(1, 1) = 3 Ackermann(1, 2) = 4 Ackermann(1, 3) = 5 Ackermann(1, 4) = 6 Ackermann(1, 5) = 7 Ackermann(1, 6) = 8 Ackermann(2, 0) = 3 Ackermann(2, 1) = 5 Ackermann(2, 2) = 7 Ackermann(2, 3) = 9 Ackermann(2, 4) = 11 Ackermann(2, 5) = 13 Ackermann(2, 6) = 15 Ackermann(3, 0) = 5 Ackermann(3, 1) = 13 Ackermann(3, 2) = 29 Ackermann(3, 3) = 61 Ackermann(3, 4) = 125 Ackermann(3, 5) = 253 Ackermann(3, 6) = 509
Erlang
-module(ackermann).
-export([ackermann/2]).
ackermann(0, N) ->
N+1;
ackermann(M, 0) ->
ackermann(M-1, 1);
ackermann(M, N) when M > 0 andalso N > 0 ->
ackermann(M-1, ackermann(M, N-1)).
ERRE
Iterative version, using a stack. First version used various GOTOs statement, now removed and substituted with the new ERRE control statements.
PROGRAM ACKERMAN
!
! computes Ackermann function
! (second version for rosettacode.org)
!
!$INTEGER
DIM STACK[10000]
!$INCLUDE="PC.LIB"
PROCEDURE ACK(M,N->N)
LOOP
CURSOR_SAVE(->CURX%,CURY%)
LOCATE(8,1)
PRINT("Livello Stack:";S;" ")
LOCATE(CURY%,CURX%)
IF M<>0 THEN
IF N<>0 THEN
STACK[S]=M
S+=1
N-=1
ELSE
M-=1
N+=1
END IF
CONTINUE LOOP
ELSE
N+=1
S-=1
END IF
IF S<>0 THEN
M=STACK[S]
M-=1
CONTINUE LOOP
ELSE
EXIT PROCEDURE
END IF
END LOOP
END PROCEDURE
BEGIN
PRINT(CHR$(12);)
FOR X=0 TO 3 DO
FOR Y=0 TO 9 DO
S=1
ACK(X,Y->ANS)
PRINT(ANS;)
END FOR
PRINT
END FOR
END PROGRAM
Prints a list of Ackermann function values: from A(0,0) to A(3,9). Uses a stack to avoid overflow. Formating options to make this pretty are available, but for this example only basic output is used.
1 2 3 4 5 6 7 8 9 10 2 3 4 5 6 7 8 9 10 11 3 5 7 9 11 13 15 17 19 21 5 13 29 61 125 253 509 1021 2045 4093 Stack Level: 1
Euler Math Toolbox
>M=zeros(1000,1000);
>function map A(m,n) ...
$ global M;
$ if m==0 then return n+1; endif;
$ if n==0 then return A(m-1,1); endif;
$ if m<=cols(M) and n<=cols(M) then
$ M[m,n]=A(m-1,A(m,n-1));
$ return M[m,n];
$ else return A(m-1,A(m,n-1));
$ endif;
$endfunction
>shortestformat; A((0:3)',0:5)
1 2 3 4 5 6
2 3 4 5 6 7
3 5 7 9 11 13
5 13 29 61 125 253
Euphoria
This is based on the VBScript example.
function ack(atom m, atom n)
if m = 0 then
return n + 1
elsif m > 0 and n = 0 then
return ack(m - 1, 1)
else
return ack(m - 1, ack(m, n - 1))
end if
end function
for i = 0 to 3 do
for j = 0 to 6 do
printf( 1, "%5d", ack( i, j ) )
end for
puts( 1, "\n" )
end for
Ezhil
நிரல்பாகம் அகெர்மன்(முதலெண், இரண்டாமெண்)
@((முதலெண் < 0) || (இரண்டாமெண் < 0)) ஆனால்
பின்கொடு -1
முடி
@(முதலெண் == 0) ஆனால்
பின்கொடு இரண்டாமெண்+1
முடி
@((முதலெண் > 0) && (இரண்டாமெண் == 00)) ஆனால்
பின்கொடு அகெர்மன்(முதலெண் - 1, 1)
முடி
பின்கொடு அகெர்மன்(முதலெண் - 1, அகெர்மன்(முதலெண், இரண்டாமெண் - 1))
முடி
அ = int(உள்ளீடு("ஓர் எண்ணைத் தாருங்கள், அது பூஜ்ஜியமாகவோ, அதைவிடப் பெரியதாக இருக்கலாம்: "))
ஆ = int(உள்ளீடு("அதேபோல் இன்னோர் எண்ணைத் தாருங்கள், இதுவும் பூஜ்ஜியமாகவோ, அதைவிடப் பெரியதாகவோ இருக்கலாம்: "))
விடை = அகெர்மன்(அ, ஆ)
@(விடை < 0) ஆனால்
பதிப்பி "தவறான எண்களைத் தந்துள்ளீர்கள்!"
இல்லை
பதிப்பி "நீங்கள் தந்த எண்களுக்கான அகர்மென் மதிப்பு: ", விடை
முடி
F#
The following program implements the Ackermann function in F# but is not tail-recursive and so runs out of stack space quite fast.
let rec ackermann m n =
match m, n with
| 0, n -> n + 1
| m, 0 -> ackermann (m - 1) 1
| m, n -> ackermann (m - 1) ackermann m (n - 1)
do
printfn "%A" (ackermann (int fsi.CommandLineArgs.[1]) (int fsi.CommandLineArgs.[2]))
Transforming this into continuation passing style avoids limited stack space by permitting tail-recursion.
let ackermann M N =
let rec acker (m, n, k) =
match m,n with
| 0, n -> k(n + 1)
| m, 0 -> acker ((m - 1), 1, k)
| m, n -> acker (m, (n - 1), (fun x -> acker ((m - 1), x, k)))
acker (M, N, (fun x -> x))
Factor
USING: kernel math locals combinators ;
IN: ackermann
:: ackermann ( m n -- u )
{
{ [ m 0 = ] [ n 1 + ] }
{ [ n 0 = ] [ m 1 - 1 ackermann ] }
[ m 1 - m n 1 - ackermann ackermann ]
} cond ;
Falcon
function ackermann( m, n )
if m == 0: return( n + 1 )
if n == 0: return( ackermann( m - 1, 1 ) )
return( ackermann( m - 1, ackermann( m, n - 1 ) ) )
end
for M in [ 0:4 ]
for N in [ 0:7 ]
>> ackermann( M, N ), " "
end
>
end
The above will output the below. Formating options to make this pretty are available, but for this example only basic output is used.
1 2 3 4 5 6 7 2 3 4 5 6 7 8 3 5 7 9 11 13 15 5 13 29 61 125 253 509
FALSE
[$$[%
\$$[%
1-\$@@a;! { i j -> A(i-1, A(i, j-1)) }
1]?0=[
%1 { i 0 -> A(i-1, 1) }
]?
\1-a;!
1]?0=[
%1+ { 0 j -> j+1 }
]?]a: { j i }
3 3 a;! . { 61 }
Fantom
class Main
{
// assuming m,n are positive
static Int ackermann (Int m, Int n)
{
if (m == 0)
return n + 1
else if (n == 0)
return ackermann (m - 1, 1)
else
return ackermann (m - 1, ackermann (m, n - 1))
}
public static Void main ()
{
(0..3).each |m|
{
(0..6).each |n|
{
echo ("Ackerman($m, $n) = ${ackermann(m, n)}")
}
}
}
}
- Output:
Ackerman(0, 0) = 1 Ackerman(0, 1) = 2 Ackerman(0, 2) = 3 Ackerman(0, 3) = 4 Ackerman(0, 4) = 5 Ackerman(0, 5) = 6 Ackerman(0, 6) = 7 Ackerman(1, 0) = 2 Ackerman(1, 1) = 3 Ackerman(1, 2) = 4 Ackerman(1, 3) = 5 Ackerman(1, 4) = 6 Ackerman(1, 5) = 7 Ackerman(1, 6) = 8 Ackerman(2, 0) = 3 Ackerman(2, 1) = 5 Ackerman(2, 2) = 7 Ackerman(2, 3) = 9 Ackerman(2, 4) = 11 Ackerman(2, 5) = 13 Ackerman(2, 6) = 15 Ackerman(3, 0) = 5 Ackerman(3, 1) = 13 Ackerman(3, 2) = 29 Ackerman(3, 3) = 61 Ackerman(3, 4) = 125 Ackerman(3, 5) = 253 Ackerman(3, 6) = 509
FBSL
Mixed-language solution using pure FBSL, Dynamic Assembler, and Dynamic C layers of FBSL v3.5 concurrently. The following is a single script; the breaks are caused by switching between RC's different syntax highlighting schemes:
#APPTYPE CONSOLE
TestAckermann()
PAUSE
SUB TestAckermann()
FOR DIM m = 0 TO 3
FOR DIM n = 0 TO 10
PRINT AckermannF(m, n), " ";
NEXT
PRINT
NEXT
END SUB
FUNCTION AckermannF(m AS INTEGER, n AS INTEGER) AS INTEGER
IF NOT m THEN RETURN n + 1
IF NOT n THEN RETURN AckermannA(m - 1, 1)
RETURN AckermannC(m - 1, AckermannF(m, n - 1))
END FUNCTION
DYNC AckermannC(m AS INTEGER, n AS INTEGER) AS INTEGER
int Ackermann(int m, int n)
{
if (!m) return n + 1;
if (!n) return Ackermann(m - 1, 1);
return Ackermann(m - 1, Ackermann(m, n - 1));
}
int main(int m, int n)
{
return Ackermann(m, n);
}
END DYNC
DYNASM AckermannA(m AS INTEGER, n AS INTEGER) AS INTEGER
ENTER 0, 0
INVOKE Ackermann, m, n
LEAVE
RET
@Ackermann
ENTER 0, 0
.IF DWORD PTR [m] .THEN
JMP @F
.ENDIF
MOV EAX, n
INC EAX
JMP xit
@@
.IF DWORD PTR [n] .THEN
JMP @F
.ENDIF
MOV EAX, m
DEC EAX
INVOKE Ackermann, EAX, 1
JMP xit
@@
MOV EAX, n
DEC EAX
INVOKE Ackermann, m, EAX
MOV ECX, m
DEC ECX
INVOKE Ackermann, ECX, EAX
@xit
LEAVE
RET 8
END DYNASM
- Output:
1 2 3 4 5 6 7 8 9 10 11 2 3 4 5 6 7 8 9 10 11 12 3 5 7 9 11 13 15 17 19 21 23 5 13 29 61 125 253 509 1021 2045 4093 8189 Press any key to continue...
Fermat
Func A(m,n) = if m = 0 then n+1 else if n = 0 then A(m-1,1) else A(m-1,A(m,n-1)) fi fi.;
A(3,8)
- Output:
2045
Forth
: acker ( m n -- u )
over 0= IF nip 1+ EXIT THEN
swap 1- swap ( m-1 n -- )
dup 0= IF 1+ recurse EXIT THEN
1- over 1+ swap recurse recurse ;
- Example of use:
FORTH> 0 0 acker . 1 ok FORTH> 3 4 acker . 125 ok
An optimized version:
: ackermann ( m n -- u )
over ( case statement)
0 over = if drop nip 1+ else
1 over = if drop nip 2 + else
2 over = if drop nip 2* 3 + else
3 over = if drop swap 5 + swap lshift 3 - else
drop swap 1- swap dup
if
1- over 1+ swap recurse recurse exit
else
1+ recurse exit \ allow tail recursion
then
then then then then
;
Fortran
PROGRAM EXAMPLE
IMPLICIT NONE
INTEGER :: i, j
DO i = 0, 3
DO j = 0, 6
WRITE(*, "(I10)", ADVANCE="NO") Ackermann(i, j)
END DO
WRITE(*,*)
END DO
CONTAINS
RECURSIVE FUNCTION Ackermann(m, n) RESULT(ack)
INTEGER :: ack, m, n
IF (m == 0) THEN
ack = n + 1
ELSE IF (n == 0) THEN
ack = Ackermann(m - 1, 1)
ELSE
ack = Ackermann(m - 1, Ackermann(m, n - 1))
END IF
END FUNCTION Ackermann
END PROGRAM EXAMPLE
Free Pascal
FreeBASIC
' version 28-10-2016
' compile with: fbc -s console
' to do A(4, 2) the stack size needs to be increased
' compile with: fbc -s console -t 2000
Function ackerman (m As Long, n As Long) As Long
If m = 0 Then ackerman = n +1
If m > 0 Then
If n = 0 Then
ackerman = ackerman(m -1, 1)
Else
If n > 0 Then
ackerman = ackerman(m -1, ackerman(m, n -1))
End If
End If
End If
End Function
' ------=< MAIN >=------
Dim As Long m, n
Print
For m = 0 To 4
Print Using "###"; m;
For n = 0 To 10
' A(4, 1) or higher will run out of stack memory (default 1M)
' change n = 1 to n = 2 to calculate A(4, 2), increase stack!
If m = 4 And n = 1 Then Exit For
Print Using "######"; ackerman(m, n);
Next
Print
Next
' empty keyboard buffer
While InKey <> "" : Wend
Print : Print "hit any key to end program"
Sleep
End
- Output:
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
FunL
def
ackermann( 0, n ) = n + 1
ackermann( m, 0 ) = ackermann( m - 1, 1 )
ackermann( m, n ) = ackermann( m - 1, ackermann(m, n - 1) )
for m <- 0..3, n <- 0..4
printf( 'Ackermann( %d, %d ) = %d\n', m, n, ackermann(m, n) )
- Output:
Ackermann( 0, 0 ) = 1 Ackermann( 0, 1 ) = 2 Ackermann( 0, 2 ) = 3 Ackermann( 0, 3 ) = 4 Ackermann( 0, 4 ) = 5 Ackermann( 1, 0 ) = 2 Ackermann( 1, 1 ) = 3 Ackermann( 1, 2 ) = 4 Ackermann( 1, 3 ) = 5 Ackermann( 1, 4 ) = 6 Ackermann( 2, 0 ) = 3 Ackermann( 2, 1 ) = 5 Ackermann( 2, 2 ) = 7 Ackermann( 2, 3 ) = 9 Ackermann( 2, 4 ) = 11 Ackermann( 3, 0 ) = 5 Ackermann( 3, 1 ) = 13 Ackermann( 3, 2 ) = 29 Ackermann( 3, 3 ) = 61 Ackermann( 3, 4 ) = 125
Futhark
fun ackermann(m: int, n: int): int =
if m == 0 then n + 1
else if n == 0 then ackermann(m-1, 1)
else ackermann(m - 1, ackermann(m, n-1))
FutureBasic
include "NSLog.incl"
local fn Ackerman( m as NSInteger, n as NSInteger ) as NSInteger
NSInteger result
select
case m == 0 : result = ( n + 1 )
case n == 0 : result = fn Ackerman( ( m - 1 ), 1 )
case else : result = fn Ackerman( ( m - 1 ), fn Ackerman( m, ( n - 1 ) ) )
end select
end fn = result
NSInteger m, n
CFMutableStringRef mutStr
mutStr = fn StringWithCapacity( 0 )
for m = 0 to 3
for n = 0 to 9
StringAppendString( mutStr, fn StringWithFormat( @"fn Ackerman( %ld, %ld ) = %ld\n", m, n, fn Ackerman( m, n ) ) )
next
next
NSLog( @"%@", mutStr )
HandleEvents
Output:
fn Ackerman( 0, 0 ) = 1 fn Ackerman( 0, 1 ) = 2 fn Ackerman( 0, 2 ) = 3 fn Ackerman( 0, 3 ) = 4 fn Ackerman( 0, 4 ) = 5 fn Ackerman( 0, 5 ) = 6 fn Ackerman( 0, 6 ) = 7 fn Ackerman( 0, 7 ) = 8 fn Ackerman( 0, 8 ) = 9 fn Ackerman( 0, 9 ) = 10 fn Ackerman( 1, 0 ) = 2 fn Ackerman( 1, 1 ) = 3 fn Ackerman( 1, 2 ) = 4 fn Ackerman( 1, 3 ) = 5 fn Ackerman( 1, 4 ) = 6 fn Ackerman( 1, 5 ) = 7 fn Ackerman( 1, 6 ) = 8 fn Ackerman( 1, 7 ) = 9 fn Ackerman( 1, 8 ) = 10 fn Ackerman( 1, 9 ) = 11 fn Ackerman( 2, 0 ) = 3 fn Ackerman( 2, 1 ) = 5 fn Ackerman( 2, 2 ) = 7 fn Ackerman( 2, 3 ) = 9 fn Ackerman( 2, 4 ) = 11 fn Ackerman( 2, 5 ) = 13 fn Ackerman( 2, 6 ) = 15 fn Ackerman( 2, 7 ) = 17 fn Ackerman( 2, 8 ) = 19 fn Ackerman( 2, 9 ) = 21 fn Ackerman( 3, 0 ) = 5 fn Ackerman( 3, 1 ) = 13 fn Ackerman( 3, 2 ) = 29 fn Ackerman( 3, 3 ) = 61 fn Ackerman( 3, 4 ) = 125 fn Ackerman( 3, 5 ) = 253 fn Ackerman( 3, 6 ) = 509 fn Ackerman( 3, 7 ) = 1021 fn Ackerman( 3, 8 ) = 2045 fn Ackerman( 3, 9 ) = 4093
Fōrmulæ
Fōrmulæ programs are not textual, visualization/edition of programs is done showing/manipulating structures but not text. Moreover, there can be multiple visual representations of the same program. Even though it is possible to have textual representation —i.e. XML, JSON— they are intended for storage and transfer purposes more than visualization and edition.
Programs in Fōrmulæ are created/edited online in its website.
In this page you can see and run the program(s) related to this task and their results. You can also change either the programs or the parameters they are called with, for experimentation, but remember that these programs were created with the main purpose of showing a clear solution of the task, and they generally lack any kind of validation.
Solution
Test case
Gambas
Public Function Ackermann(m As Float, n As Float) As Float
If m = 0 Then
Return n + 1
End If
If n = 0 Then
Return Ackermann(m - 1, 1)
End If
Return Ackermann(m - 1, Ackermann(m, n - 1))
End
Public Sub Main()
Dim m, n As Float
For m = 0 To 3
For n = 0 To 4
Print "Ackermann("; m; ", "; n; ") = "; Ackermann(m, n)
Next
Next
End
GAP
ack := function(m, n)
if m = 0 then
return n + 1;
elif (m > 0) and (n = 0) then
return ack(m - 1, 1);
elif (m > 0) and (n > 0) then
return ack(m - 1, ack(m, n - 1));
else
return fail;
fi;
end;
Genyris
def A (m n)
cond
(equal? m 0)
+ n 1
(equal? n 0)
A (- m 1) 1
else
A (- m 1)
A m (- n 1)
GML
Define a script resource named ackermann and paste this code inside:
///ackermann(m,n)
var m, n;
m = argument0;
n = argument1;
if(m=0)
{
return (n+1)
}
else if(n == 0)
{
return (ackermann(m-1,1,1))
}
else
{
return (ackermann(m-1,ackermann(m,n-1,2),1))
}
gnuplot
A (m, n) = m == 0 ? n + 1 : n == 0 ? A (m - 1, 1) : A (m - 1, A (m, n - 1))
print A (0, 4)
print A (1, 4)
print A (2, 4)
print A (3, 4)
- Output:
5 6 11 stack overflow
Go
Classic version
func Ackermann(m, n uint) uint {
switch 0 {
case m:
return n + 1
case n:
return Ackermann(m - 1, 1)
}
return Ackermann(m - 1, Ackermann(m, n - 1))
}
Expanded version
func Ackermann2(m, n uint) uint {
switch {
case m == 0:
return n + 1
case m == 1:
return n + 2
case m == 2:
return 2*n + 3
case m == 3:
return 8 << n - 3
case n == 0:
return Ackermann2(m - 1, 1)
}
return Ackermann2(m - 1, Ackermann2(m, n - 1))
}
Expanded version with arbitrary precision
package main
import (
"fmt"
"math/big"
"math/bits" // Added in Go 1.9
)
var one = big.NewInt(1)
var two = big.NewInt(2)
var three = big.NewInt(3)
var eight = big.NewInt(8)
func Ackermann2(m, n *big.Int) *big.Int {
if m.Cmp(three) <= 0 {
switch m.Int64() {
case 0:
return new(big.Int).Add(n, one)
case 1:
return new(big.Int).Add(n, two)
case 2:
r := new(big.Int).Lsh(n, 1)
return r.Add(r, three)
case 3:
if nb := n.BitLen(); nb > bits.UintSize {
// n is too large to represent as a
// uint for use in the Lsh method.
panic(TooBigError(nb))
// If we tried to continue anyway, doing
// 8*2^n-3 as bellow, we'd use hundreds
// of megabytes and lots of CPU time
// without the Exp call even returning.
r := new(big.Int).Exp(two, n, nil)
r.Mul(eight, r)
return r.Sub(r, three)
}
r := new(big.Int).Lsh(eight, uint(n.Int64()))
return r.Sub(r, three)
}
}
if n.BitLen() == 0 {
return Ackermann2(new(big.Int).Sub(m, one), one)
}
return Ackermann2(new(big.Int).Sub(m, one),
Ackermann2(m, new(big.Int).Sub(n, one)))
}
type TooBigError int
func (e TooBigError) Error() string {
return fmt.Sprintf("A(m,n) had n of %d bits; too large", int(e))
}
func main() {
show(0, 0)
show(1, 2)
show(2, 4)
show(3, 100)
show(3, 1e6)
show(4, 1)
show(4, 2)
show(4, 3)
}
func show(m, n int64) {
defer func() {
// Ackermann2 could/should have returned an error
// instead of a panic. But here's how to recover
// from the panic, and report "expected" errors.
if e := recover(); e != nil {
if err, ok := e.(TooBigError); ok {
fmt.Println("Error:", err)
} else {
panic(e)
}
}
}()
fmt.Printf("A(%d, %d) = ", m, n)
a := Ackermann2(big.NewInt(m), big.NewInt(n))
if a.BitLen() <= 256 {
fmt.Println(a)
} else {
s := a.String()
fmt.Printf("%d digits starting/ending with: %s...%s\n",
len(s), s[:20], s[len(s)-20:],
)
}
}
- Output:
A(0, 0) = 1 A(1, 2) = 4 A(2, 4) = 11 A(3, 100) = 10141204801825835211973625643005 A(3, 1000000) = 301031 digits starting/ending with: 79205249834367186005...39107225301976875005 A(4, 1) = 65533 A(4, 2) = 19729 digits starting/ending with: 20035299304068464649...45587895905719156733 A(4, 3) = Error: A(m,n) had n of 65536 bits; too large
Golfscript
{
:_n; :_m;
_m 0= {_n 1+}
{_n 0= {_m 1- 1 ack}
{_m 1- _m _n 1- ack ack}
if}
if
}:ack;
Groovy
def ack ( m, n ) {
assert m >= 0 && n >= 0 : 'both arguments must be non-negative'
m == 0 ? n + 1 : n == 0 ? ack(m-1, 1) : ack(m-1, ack(m, n-1))
}
Test program:
def ackMatrix = (0..3).collect { m -> (0..8).collect { n -> ack(m, n) } }
ackMatrix.each { it.each { elt -> printf "%7d", elt }; println() }
- Output:
1 2 3 4 5 6 7 8 9 2 3 4 5 6 7 8 9 10 3 5 7 9 11 13 15 17 19 5 13 29 61 125 253 509 1021 2045
Note: In the default groovyConsole configuration for WinXP, "ack(4,1)" caused a stack overflow error!
Hare
use fmt;
fn ackermann(m: u64, n: u64) u64 = {
if (m == 0) {
return n + 1;
};
if (n == 0) {
return ackermann(m - 1, 1);
};
return ackermann(m - 1, ackermann(m, n - 1));
};
export fn main() void = {
for (let m = 0u64; m < 4; m += 1) {
for (let n = 0u64; n < 10; n += 1) {
fmt::printfln("A({}, {}) = {}", m, n, ackermann(m, n))!;
};
fmt::println()!;
};
};
Haskell
ack :: Int -> Int -> Int
ack 0 n = succ n
ack m 0 = ack (pred m) 1
ack m n = ack (pred m) (ack m (pred n))
main :: IO ()
main = mapM_ print $ uncurry ack <$> [(0, 0), (3, 4)]
- Output:
1 125
Generating a list instead:
import Data.List (mapAccumL)
-- everything here are [Int] or [[Int]], which would overflow
-- * had it not overrun the stack first *
ackermann = iterate ack [1..] where
ack a = s where
s = snd $ mapAccumL f (tail a) (1 : zipWith (-) s (1:s))
f a b = (aa, head aa) where aa = drop b a
main = mapM_ print $ map (\n -> take (6 - n) $ ackermann !! n) [0..5]
Haxe
class RosettaDemo
{
static public function main()
{
Sys.print(ackermann(3, 4));
}
static function ackermann(m : Int, n : Int)
{
if (m == 0)
{
return n + 1;
}
else if (n == 0)
{
return ackermann(m-1, 1);
}
return ackermann(m-1, ackermann(m, n-1));
}
}
Hoon
|= [m=@ud n=@ud]
?: =(m 0)
+(n)
?: =(n 0)
$(n 1, m (dec m))
$(m (dec m), n $(n (dec n)))
Icon and Unicon
Taken from the public domain Icon Programming Library's acker in memrfncs, written by Ralph E. Griswold.
- Output:
1 2 3 4 5 6 7 8 9 2 3 4 5 6 7 8 9 10 3 5 7 9 11 13 15 17 19 5 13 29 61 125 253 509 1021 2045
Idris
A : Nat -> Nat -> Nat
A Z n = S n
A (S m) Z = A m (S Z)
A (S m) (S n) = A m (A (S m) n)
Ioke
ackermann = method(m,n,
cond(
m zero?, n succ,
n zero?, ackermann(m pred, 1),
ackermann(m pred, ackermann(m, n pred)))
)
J
As posted at the J wiki
ack=: c1`c1`c2`c3 @. (#.@,&*) M.
c1=: >:@] NB. if 0=x, 1+y
c2=: <:@[ ack 1: NB. if 0=y, (x-1) ack 1
c3=: <:@[ ack [ ack <:@] NB. else, (x-1) ack x ack y-1
- Example use:
0 ack 3
4
1 ack 3
5
2 ack 3
9
3 ack 3
61
J's stack was too small for me to compute 4 ack 1.
Alternative Primitive Recursive Version
This version works by first generating verbs (functions) and then applying them to compute the rows of the related Buck function; then the Ackermann function is obtained in terms of the Buck function. It uses extended precision to be able to compute 4 Ack 2.
The Ackermann function derived in this fashion is primitive recursive. This is possible because in J (as in some other languages) functions, or representations of them, are first-class values.
Ack=. 3 -~ [ ({&(2 4$'>: 2x&+') ::(,&'&1'&'2x&*'@:(-&2))"0@:[ 128!:2 ]) 3 + ]
- Example use:
0 1 2 3 Ack 0 1 2 3 4 5 6 7
1 2 3 4 5 6 7 8
2 3 4 5 6 7 8 9
3 5 7 9 11 13 15 17
5 13 29 61 125 253 509 1021
3 4 Ack 0 1 2
5 13 ...
13 65533 2003529930406846464979072351560255750447825475569751419265016973710894059556311453089506130880933348101038234342907263181822949382118812668869506364761547029165041871916351587966347219442930927982084309104855990570159318959639524863372367203002916...
4 # @: ": @: Ack 2 NB. Number of digits of 4 Ack 2
19729
5 Ack 0
65533
A structured derivation of Ack follows:
o=. @: NB. Composition of verbs (functions)
x=. o[ NB. Composing the left noun (argument)
(rows2up=. ,&'&1'&'2x&*') o i. 4
2x&*
2x&*&1
2x&*&1&1
2x&*&1&1&1
NB. 2's multiplication, exponentiation, tetration, pentation, etc.
0 1 2 (BuckTruncated=. (rows2up x apply ]) f.) 0 1 2 3 4 5
0 2 4 6 8 ...
1 2 4 8 16 ...
1 2 4 16 65536 2003529930406846464979072351560255750447825475569751419265016973710894059556311453089506130880933348101038234342907263181822949382118812668869506364761547029165041871916351587966347219442930927982084309104855990570159318959639524863372367203...
NB. Buck truncated function (missing the first two rows)
BuckTruncated NB. Buck truncated function-level code
,&'&1'&'2x&*'@:[ 128!:2 ]
(rows01=. {&('>:',:'2x&+')) 0 1 NB. The missing first two rows
>:
2x&+
Buck=. (rows01 :: (rows2up o (-&2)))"0 x apply ]
(Ack=. (3 -~ [ Buck 3 + ])f.) NB. Ackermann function-level code
3 -~ [ ({&(2 4$'>: 2x&+') ::(,&'&1'&'2x&*'@:(-&2))"0@:[ 128!:2 ]) 3 + ]
Java
import java.math.BigInteger;
public static BigInteger ack(BigInteger m, BigInteger n) {
return m.equals(BigInteger.ZERO)
? n.add(BigInteger.ONE)
: ack(m.subtract(BigInteger.ONE),
n.equals(BigInteger.ZERO) ? BigInteger.ONE : ack(m, n.subtract(BigInteger.ONE)));
}
@FunctionalInterface
public interface FunctionalField<FIELD extends Enum<?>> {
public Object untypedField(FIELD field);
@SuppressWarnings("unchecked")
public default <VALUE> VALUE field(FIELD field) {
return (VALUE) untypedField(field);
}
}
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import java.util.stream.Stream;
public interface TailRecursive {
public static <INPUT, INTERMEDIARY, OUTPUT> Function<INPUT, OUTPUT> new_(Function<INPUT, INTERMEDIARY> toIntermediary, UnaryOperator<INTERMEDIARY> unaryOperator, Predicate<INTERMEDIARY> predicate, Function<INTERMEDIARY, OUTPUT> toOutput) {
return input ->
$.new_(
Stream.iterate(
toIntermediary.apply(input),
unaryOperator
),
predicate,
toOutput
)
;
}
public static <INPUT1, INPUT2, INTERMEDIARY, OUTPUT> BiFunction<INPUT1, INPUT2, OUTPUT> new_(BiFunction<INPUT1, INPUT2, INTERMEDIARY> toIntermediary, UnaryOperator<INTERMEDIARY> unaryOperator, Predicate<INTERMEDIARY> predicate, Function<INTERMEDIARY, OUTPUT> toOutput) {
return (input1, input2) ->
$.new_(
Stream.iterate(
toIntermediary.apply(input1, input2),
unaryOperator
),
predicate,
toOutput
)
;
}
public enum $ {
$$;
private static <INTERMEDIARY, OUTPUT> OUTPUT new_(Stream<INTERMEDIARY> stream, Predicate<INTERMEDIARY> predicate, Function<INTERMEDIARY, OUTPUT> function) {
return stream
.filter(predicate)
.map(function)
.findAny()
.orElseThrow(RuntimeException::new)
;
}
}
}
import java.math.BigInteger;
import java.util.Stack;
import java.util.function.BinaryOperator;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public interface Ackermann {
public static Ackermann new_(BigInteger number1, BigInteger number2, Stack<BigInteger> stack, boolean flag) {
return $.new_(number1, number2, stack, flag);
}
public static void main(String... arguments) {
$.main(arguments);
}
public BigInteger number1();
public BigInteger number2();
public Stack<BigInteger> stack();
public boolean flag();
public enum $ {
$$;
private static final BigInteger ZERO = BigInteger.ZERO;
private static final BigInteger ONE = BigInteger.ONE;
private static final BigInteger TWO = BigInteger.valueOf(2);
private static final BigInteger THREE = BigInteger.valueOf(3);
private static final BigInteger FOUR = BigInteger.valueOf(4);
private static Ackermann new_(BigInteger number1, BigInteger number2, Stack<BigInteger> stack, boolean flag) {
return (FunctionalAckermann) field -> {
switch (field) {
case number1: return number1;
case number2: return number2;
case stack: return stack;
case flag: return flag;
default: throw new UnsupportedOperationException(
field instanceof Field
? "Field checker has not been updated properly."
: "Field is not of the correct type."
);
}
};
}
private static final BinaryOperator<BigInteger> ACKERMANN =
TailRecursive.new_(
(BigInteger number1, BigInteger number2) ->
new_(
number1,
number2,
Stream.of(number1).collect(
Collectors.toCollection(Stack::new)
),
false
)
,
ackermann -> {
BigInteger number1 = ackermann.number1();
BigInteger number2 = ackermann.number2();
Stack<BigInteger> stack = ackermann.stack();
if (!stack.empty() && !ackermann.flag()) {
number1 = stack.pop();
}
switch (number1.intValue()) {
case 0:
return new_(
number1,
number2.add(ONE),
stack,
false
);
case 1:
return new_(
number1,
number2.add(TWO),
stack,
false
);
case 2:
return new_(
number1,
number2.multiply(TWO).add(THREE),
stack,
false
);
default:
if (ZERO.equals(number2)) {
return new_(
number1.subtract(ONE),
ONE,
stack,
true
);
} else {
stack.push(number1.subtract(ONE));
return new_(
number1,
number2.subtract(ONE),
stack,
true
);
}
}
},
ackermann -> ackermann.stack().empty(),
Ackermann::number2
)::apply
;
private static void main(String... arguments) {
System.out.println(ACKERMANN.apply(FOUR, TWO));
}
private enum Field {
number1,
number2,
stack,
flag
}
@FunctionalInterface
private interface FunctionalAckermann extends FunctionalField<Field>, Ackermann {
@Override
public default BigInteger number1() {
return field(Field.number1);
}
@Override
public default BigInteger number2() {
return field(Field.number2);
}
@Override
public default Stack<BigInteger> stack() {
return field(Field.stack);
}
@Override
public default boolean flag() {
return field(Field.flag);
}
}
}
}
/*
* Source https://stackoverflow.com/a/51092690/5520417
*/
package matematicas;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Stack;
/**
* @author rodri
*
*/
public class IterativeAckermannMemoryOptimization extends Thread {
/**
* Max percentage of free memory that the program will use. Default is 10% since
* the majority of the used devices are mobile and therefore it is more likely
* that the user will have more opened applications at the same time than in a
* desktop device
*/
private static Double SYSTEM_MEMORY_LIMIT_PERCENTAGE = 0.1;
/**
* Attribute of the type IterativeAckermann
*/
private IterativeAckermann iterativeAckermann;
/**
* @param iterativeAckermann
*/
public IterativeAckermannMemoryOptimization(IterativeAckermann iterativeAckermann) {
super();
this.iterativeAckermann = iterativeAckermann;
}
/**
* @return
*/
public IterativeAckermann getIterativeAckermann() {
return iterativeAckermann;
}
/**
* @param iterativeAckermann
*/
public void setIterativeAckermann(IterativeAckermann iterativeAckermann) {
this.iterativeAckermann = iterativeAckermann;
}
public static Double getSystemMemoryLimitPercentage() {
return SYSTEM_MEMORY_LIMIT_PERCENTAGE;
}
/**
* Principal method of the thread. Checks that the memory used doesn't exceed or
* equal the limit, and informs the user when that happens.
*/
@Override
public void run() {
String operating_system = System.getProperty("os.name").toLowerCase();
if ( operating_system.equals("windows") || operating_system.equals("linux") || operating_system.equals("macintosh") ) {
SYSTEM_MEMORY_LIMIT_PERCENTAGE = 0.25;
}
while ( iterativeAckermann.getConsumed_heap() >= SYSTEM_MEMORY_LIMIT_PERCENTAGE * Runtime.getRuntime().freeMemory() ) {
try {
wait();
}
catch ( InterruptedException e ) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if ( ! iterativeAckermann.isAlive() )
iterativeAckermann.start();
else
notifyAll();
}
}
public class IterativeAckermann extends Thread {
/*
* Adjust parameters conveniently
*/
/**
*
*/
private static final int HASH_SIZE_LIMIT = 636;
/**
*
*/
private BigInteger m;
/**
*
*/
private BigInteger n;
/**
*
*/
private Integer hash_size;
/**
*
*/
private Long consumed_heap;
/**
* @param m
* @param n
* @param invalid
* @param invalid2
*/
public IterativeAckermann(BigInteger m, BigInteger n, Integer invalid, Long invalid2) {
super();
this.m = m;
this.n = n;
this.hash_size = invalid;
this.consumed_heap = invalid2;
}
/**
*
*/
public IterativeAckermann() {
// TODO Auto-generated constructor stub
super();
m = null;
n = null;
hash_size = 0;
consumed_heap = 0l;
}
/**
* @return
*/
public static BigInteger getLimit() {
return LIMIT;
}
/**
* @author rodri
*
* @param <T1>
* @param <T2>
*/
/**
* @author rodri
*
* @param <T1>
* @param <T2>
*/
static class Pair<T1, T2> {
/**
*
*/
/**
*
*/
T1 x;
/**
*
*/
/**
*
*/
T2 y;
/**
* @param x_
* @param y_
*/
/**
* @param x_
* @param y_
*/
Pair(T1 x_, T2 y_) {
x = x_;
y = y_;
}
/**
*
*/
/**
*
*/
@Override
public int hashCode() {
return x.hashCode() ^ y.hashCode();
}
/**
*
*/
/**
*
*/
@Override
public boolean equals(Object o_) {
if ( o_ == null ) {
return false;
}
if ( o_.getClass() != this.getClass() ) {
return false;
}
Pair<?, ?> o = (Pair<?, ?>) o_;
return x.equals(o.x) && y.equals(o.y);
}
}
/**
*
*/
private static final BigInteger LIMIT = new BigInteger("6");
/**
* @param m
* @param n
* @return
*/
/**
*
*/
@Override
public void run() {
while ( hash_size >= HASH_SIZE_LIMIT ) {
try {
this.wait();
}
catch ( InterruptedException e ) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
for ( BigInteger i = BigInteger.ZERO; i.compareTo(LIMIT) == - 1; i = i.add(BigInteger.ONE) ) {
for ( BigInteger j = BigInteger.ZERO; j.compareTo(LIMIT) == - 1; j = j.add(BigInteger.ONE) ) {
IterativeAckermann iterativeAckermann = new IterativeAckermann(i, j, null, null);
System.out.printf("Ackmermann(%d, %d) = %d\n", i, j, iterativeAckermann.iterative_ackermann(i, j));
}
}
}
/**
* @return
*/
public BigInteger getM() {
return m;
}
/**
* @param m
*/
public void setM(BigInteger m) {
this.m = m;
}
/**
* @return
*/
public BigInteger getN() {
return n;
}
/**
* @param n
*/
public void setN(BigInteger n) {
this.n = n;
}
/**
* @return
*/
public Integer getHash_size() {
return hash_size;
}
/**
* @param hash_size
*/
public void setHash_size(Integer hash_size) {
this.hash_size = hash_size;
}
/**
* @return
*/
public Long getConsumed_heap() {
return consumed_heap;
}
/**
* @param consumed_heap
*/
public void setConsumed_heap(Long consumed_heap) {
this.consumed_heap = consumed_heap;
}
/**
* @param m
* @param n
* @return
*/
public BigInteger iterative_ackermann(BigInteger m, BigInteger n) {
if ( m.compareTo(BigInteger.ZERO) != - 1 && m.compareTo(BigInteger.ZERO) != - 1 )
try {
HashMap<Pair<BigInteger, BigInteger>, BigInteger> solved_set = new HashMap<Pair<BigInteger, BigInteger>, BigInteger>(900000);
Stack<Pair<BigInteger, BigInteger>> to_solve = new Stack<Pair<BigInteger, BigInteger>>();
to_solve.push(new Pair<BigInteger, BigInteger>(m, n));
while ( ! to_solve.isEmpty() ) {
Pair<BigInteger, BigInteger> head = to_solve.peek();
if ( head.x.equals(BigInteger.ZERO) ) {
solved_set.put(head, head.y.add(BigInteger.ONE));
to_solve.pop();
}
else if ( head.y.equals(BigInteger.ZERO) ) {
Pair<BigInteger, BigInteger> next = new Pair<BigInteger, BigInteger>(head.x.subtract(BigInteger.ONE), BigInteger.ONE);
BigInteger result = solved_set.get(next);
if ( result == null ) {
to_solve.push(next);
}
else {
solved_set.put(head, result);
to_solve.pop();
}
}
else {
Pair<BigInteger, BigInteger> next0 = new Pair<BigInteger, BigInteger>(head.x, head.y.subtract(BigInteger.ONE));
BigInteger result0 = solved_set.get(next0);
if ( result0 == null ) {
to_solve.push(next0);
}
else {
Pair<BigInteger, BigInteger> next = new Pair<BigInteger, BigInteger>(head.x.subtract(BigInteger.ONE), result0);
BigInteger result = solved_set.get(next);
if ( result == null ) {
to_solve.push(next);
}
else {
solved_set.put(head, result);
to_solve.pop();
}
}
}
}
this.hash_size = solved_set.size();
System.out.println("Hash Size: " + hash_size);
consumed_heap = (Runtime.getRuntime().totalMemory() / (1024 * 1024));
System.out.println("Consumed Heap: " + consumed_heap + "m");
setHash_size(hash_size);
setConsumed_heap(consumed_heap);
return solved_set.get(new Pair<BigInteger, BigInteger>(m, n));
}
catch ( OutOfMemoryError e ) {
// TODO: handle exception
e.printStackTrace();
}
throw new IllegalArgumentException("The arguments must be non-negative integers.");
}
/**
* @param args
*/
/**
* @param args
*/
public static void main(String[] args) {
IterativeAckermannMemoryOptimization iterative_ackermann_memory_optimization = new IterativeAckermannMemoryOptimization(
new IterativeAckermann());
iterative_ackermann_memory_optimization.start();
}
}
JavaScript
ES5
function ack(m, n) {
return m === 0 ? n + 1 : ack(m - 1, n === 0 ? 1 : ack(m, n - 1));
}
Eliminating Tail Calls
function ack(M,N) {
for (; M > 0; M--) {
N = N === 0 ? 1 : ack(M,N-1);
}
return N+1;
}
Iterative, With Explicit Stack
function stackermann(M, N) {
const stack = [];
for (;;) {
if (M === 0) {
N++;
if (stack.length === 0) return N;
const r = stack[stack.length-1];
if (r[1] === 1) stack.length--;
else r[1]--;
M = r[0];
} else if (N === 0) {
M--;
N = 1;
} else {
M--
stack.push([M, N]);
N = 1;
}
}
}
Stackless Iterative
#!/usr/bin/env nodejs
function ack(M, N){
const next = new Float64Array(M + 1);
const goal = new Float64Array(M + 1).fill(1, 0, M);
const n = N + 1;
// This serves as a sentinel value;
// next[M] never equals goal[M] == -1,
// so we don't need an extra check for
// loop termination below.
goal[M] = -1;
let v;
do {
v = next[0] + 1;
let m = 0;
while (next[m] === goal[m]) {
goal[m] = v;
next[m++]++;
}
next[m]++;
} while (next[M] !== n);
return v;
}
var args = process.argv;
console.log(ack(parseInt(args[2]), parseInt(args[3])));
- Output:
> time ./ack.js 4 1 65533 ./ack.js 4 1 0,48s user 0,03s system 100% cpu 0,505 total ; AMD FX-8350 @ 4 GHz
ES6
(() => {
'use strict';
// ackermann :: Int -> Int -> Int
const ackermann = m => n => {
const go = (m, n) =>
0 === m ? (
succ(n)
) : go(pred(m), 0 === n ? (
1
) : go(m, pred(n)));
return go(m, n);
};
// TEST -----------------------------------------------
const main = () => console.log(JSON.stringify(
[0, 1, 2, 3].map(
flip(ackermann)(3)
)
));
// GENERAL FUNCTIONS ----------------------------------
// flip :: (a -> b -> c) -> b -> a -> c
const flip = f =>
x => y => f(y)(x);
// pred :: Enum a => a -> a
const pred = x => x - 1;
// succ :: Enum a => a -> a
const succ = x => 1 + x;
// MAIN ---
return main();
})();
- Output:
[4,5,9,61]
Joy
DEFINE ack == [[[pop null] popd succ]
[[null] pop pred 1 ack]
[[dup pred swap] dip pred ack ack]]
cond.
another using a combinator:
DEFINE ack == [[[pop null] [popd succ]]
[[null] [pop pred 1] []]
[[[dup pred swap] dip pred] [] []]]
condnestrec.
jq
Also works with gojq, the Go implementation of jq.
Except for a minor tweak to the line using string interpolation, the following have also been tested using jaq, the Rust implementation of jq, as of April 13, 2023.
For infinite-precision integer arithmetic, use gojq or fq.
Without Memoization
# input: [m,n]
def ack:
.[0] as $m | .[1] as $n
| if $m == 0 then $n + 1
elif $n == 0 then [$m-1, 1] | ack
else [$m-1, ([$m, $n-1 ] | ack)] | ack
end ;
Example:
range(0;5) as $i
| range(0; if $i > 3 then 1 else 6 end) as $j
| "A(\($i),\($j)) = \( [$i,$j] | ack )"
- Output:
# jq -n -r -f ackermann.jq
A(0,0) = 1
A(0,1) = 2
A(0,2) = 3
A(0,3) = 4
A(0,4) = 5
A(0,5) = 6
A(1,0) = 2
A(1,1) = 3
A(1,2) = 4
A(1,3) = 5
A(1,4) = 6
A(1,5) = 7
A(2,0) = 3
A(2,1) = 5
A(2,2) = 7
A(2,3) = 9
A(2,4) = 11
A(2,5) = 13
A(3,0) = 5
A(3,1) = 13
A(3,2) = 29
A(3,3) = 61
A(3,4) = 125
A(3,5) = 253
A(4,0) = 13
With Memoization and Optimization
# input: [m,n, cache]
# output [value, updatedCache]
def ack:
# input: [value,cache]; output: [value, updatedCache]
def cache(key): .[1] += { (key): .[0] };
def pow2: reduce range(0; .) as $i (1; .*2);
.[0] as $m | .[1] as $n | .[2] as $cache
| if $m == 0 then [$n + 1, $cache]
elif $m == 1 then [$n + 2, $cache]
elif $m == 2 then [2 * $n + 3, $cache]
elif $m == 3 then [8 * ($n|pow2) - 3, $cache]
else
(.[0:2]|tostring) as $key
| $cache[$key] as $value
| if $value then [$value, $cache]
elif $n == 0 then
([$m-1, 1, $cache] | ack)
| cache($key)
else
([$m, $n-1, $cache ] | ack)
| [$m-1, .[0], .[1]] | ack
| cache($key)
end
end;
def A(m;n): [m,n,{}] | ack | .[0];
Examples:
A(4;1)
- Output:
65533
Using gojq:
A(4;2), A(3;1000000) | tostring | length
- Output:
19729
301031
Jsish
From javascript entry.
/* Ackermann function, in Jsish */
function ack(m, n) {
return m === 0 ? n + 1 : ack(m - 1, n === 0 ? 1 : ack(m, n - 1));
}
if (Interp.conf('unitTest')) {
Interp.conf({maxDepth:4096});
; ack(1,3);
; ack(2,3);
; ack(3,3);
; ack(1,5);
; ack(2,5);
; ack(3,5);
}
/*
=!EXPECTSTART!=
ack(1,3) ==> 5
ack(2,3) ==> 9
ack(3,3) ==> 61
ack(1,5) ==> 7
ack(2,5) ==> 13
ack(3,5) ==> 253
=!EXPECTEND!=
*/
- Output:
prompt$ jsish --U Ackermann.jsi ack(1,3) ==> 5 ack(2,3) ==> 9 ack(3,3) ==> 61 ack(1,5) ==> 7 ack(2,5) ==> 13 ack(3,5) ==> 253
Julia
function ack(m,n)
if m == 0
return n + 1
elseif n == 0
return ack(m-1,1)
else
return ack(m-1,ack(m,n-1))
end
end
One-liner:
ack2(m::Integer, n::Integer) = m == 0 ? n + 1 : n == 0 ? ack2(m - 1, 1) : ack2(m - 1, ack2(m, n - 1))
Using memoization, source:
using Memoize
@memoize ack3(m::Integer, n::Integer) = m == 0 ? n + 1 : n == 0 ? ack3(m - 1, 1) : ack3(m - 1, ack3(m, n - 1))
Benchmarking:
julia> @time ack2(4,1) elapsed time: 71.98668457 seconds (96 bytes allocated) 65533 julia> @time ack3(4,1) elapsed time: 0.49337724 seconds (30405308 bytes allocated) 65533
K
ack:{:[0=x;y+1;0=y;_f[x-1;1];_f[x-1;_f[x;y-1]]]}
ack[2;2]
7
ack[2;7]
17
Kdf9 Usercode
V6; W0;
YS26000;
RESTART; J999; J999;
PROGRAM; (main program);
V1 = B1212121212121212; (radix 10 for FRB);
V2 = B2020202020202020; (high bits for decimal digits);
V3 = B0741062107230637; ("A[3," in Flexowriter code);
V4 = B0727062200250007; ("7] = " in Flexowriter code);
V5 = B7777777777777777;
ZERO; NOT; =M1; (Q1 := 0/0/-1);
SETAYS0; =M2; I2=2; (Q2 := 0/2/AYS0: M2 is the stack pointer);
SET 3; =RC7; (Q7 := 3/1/0: C7 = m);
SET 7; =RC8; (Q8 := 7/1/0: C8 = n);
JSP1; (call Ackermann function);
V1; REV; FRB; (convert result to base 10);
V2; OR; (convert decimal digits to characters);
V5; REV;
SHLD+24; =V5; ERASE; (eliminate leading zeros);
SETAV5; =RM9;
SETAV3; =I9;
POAQ9; (write result to Flexowriter);
999; ZERO; OUT; (terminate run);
P1; (To compute A[m, n]);
99;
J1C7NZ; (to 1 if m ± 0);
I8; =+C8; (n := n + 1);
C8; (result to NEST);
EXIT 1; (return);
*1;
J2C8NZ; (to 2 if n ± 0);
I8; =C8; (n := 1);
DC7; (m := m - 1);
J99; (tail recursion for A[m-1, 1]);
*2;
LINK; =M0M2; (push return address);
C7; =M0M2QN; (push m);
DC8; (n := n - 1);
JSP1; (full recursion for A[m, n-1]);
=C8; (n := A[m, n-1]);
M1M2; =C7; (m := top of stack);
DC7; (m := m - 1);
M-I2; (pop stack);
M0M2; =LINK; (return address := top of stack);
J99; (tail recursion for A[m-1, A[m, n-1]]);
FINISH;
Klingphix
:ack
%n !n %m !m
$m 0 ==
( [$n 1 +]
[$n 0 ==
( [$m 1 - 1 ack]
[$m 1 - $m $n 1 - ack ack]
) if
]
) if
;
3 6 ack print nl
msec print
" " input
Klong
ack::{:[0=x;y+1:|0=y;.f(x-1;1);.f(x-1;.f(x;y-1))]}
ack(2;2)
Kotlin
tailrec fun A(m: Long, n: Long): Long {
require(m >= 0L) { "m must not be negative" }
require(n >= 0L) { "n must not be negative" }
if (m == 0L) {
return n + 1L
}
if (n == 0L) {
return A(m - 1L, 1L)
}
return A(m - 1L, A(m, n - 1L))
}
inline fun<T> tryOrNull(block: () -> T): T? = try { block() } catch (e: Throwable) { null }
const val N = 10L
const val M = 4L
fun main() {
(0..M)
.map { it to 0..N }
.map { (m, Ns) -> (m to Ns) to Ns.map { n -> tryOrNull { A(m, n) } } }
.map { (input, output) -> "A(${input.first}, ${input.second})" to output.map { it?.toString() ?: "?" } }
.map { (input, output) -> "$input = $output" }
.forEach(::println)
}
- Output:
A(0, 0..10) = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] A(1, 0..10) = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] A(2, 0..10) = [3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23] A(3, 0..10) = [5, 13, 29, 61, 125, 253, 509, 1021, 2045, 4093, 8189] A(4, 0..10) = [13, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?]
Lambdatalk
{def ack
{lambda {:m :n}
{if {= :m 0}
then {+ :n 1}
else {if {= :n 0}
then {ack {- :m 1} 1}
else {ack {- :m 1} {ack :m {- :n 1}}}}}}}
-> ack
{S.map {ack 0} {S.serie 0 300000}} // 2090ms
{S.map {ack 1} {S.serie 0 500}} // 2038ms
{S.map {ack 2} {S.serie 0 70}} // 2100ms
{S.map {ack 3} {S.serie 0 6}} // 1800ms
{ack 2 700} // 8900ms
-> 1403
{ack 3 7} // 6000ms
-> 1021
{ack 4 1} // too much
-> ???
Lasso
#!/usr/bin/lasso9
define ackermann(m::integer, n::integer) => {
if(#m == 0) => {
return ++#n
else(#n == 0)
return ackermann(--#m, 1)
else
return ackermann(#m-1, ackermann(#m, --#n))
}
}
with x in generateSeries(1,3),
y in generateSeries(0,8,2)
do stdoutnl(#x+', '#y+': ' + ackermann(#x, #y))
- Output:
1, 0: 2 1, 2: 4 1, 4: 6 1, 6: 8 1, 8: 10 2, 0: 3 2, 2: 7 2, 4: 11 2, 6: 15 2, 8: 19 3, 0: 5 3, 2: 29 3, 4: 125 3, 6: 509 3, 8: 2045
LFE
(defun ackermann
((0 n) (+ n 1))
((m 0) (ackermann (- m 1) 1))
((m n) (ackermann (- m 1) (ackermann m (- n 1)))))
Liberty BASIC
Print Ackermann(1, 2)
Function Ackermann(m, n)
Select Case
Case (m < 0) Or (n < 0)
Exit Function
Case (m = 0)
Ackermann = (n + 1)
Case (m > 0) And (n = 0)
Ackermann = Ackermann((m - 1), 1)
Case (m > 0) And (n > 0)
Ackermann = Ackermann((m - 1), Ackermann(m, (n - 1)))
End Select
End Function
LiveCode
function ackermann m,n
switch
Case m = 0
return n + 1
Case (m > 0 And n = 0)
return ackermann((m - 1), 1)
Case (m > 0 And n > 0)
return ackermann((m - 1), ackermann(m, (n - 1)))
end switch
end ackermann
Logo
to ack :i :j
if :i = 0 [output :j+1]
if :j = 0 [output ack :i-1 1]
output ack :i-1 ack :i :j-1
end
Logtalk
ack(0, N, V) :-
!,
V is N + 1.
ack(M, 0, V) :-
!,
M2 is M - 1,
ack(M2, 1, V).
ack(M, N, V) :-
M2 is M - 1,
N2 is N - 1,
ack(M, N2, V2),
ack(M2, V2, V).
LOLCODE
HAI 1.3
HOW IZ I ackermann YR m AN YR n
NOT m, O RLY?
YA RLY, FOUND YR SUM OF n AN 1
OIC
NOT n, O RLY?
YA RLY, FOUND YR I IZ ackermann YR DIFF OF m AN 1 AN YR 1 MKAY
OIC
FOUND YR I IZ ackermann YR DIFF OF m AN 1 AN YR...
I IZ ackermann YR m AN YR DIFF OF n AN 1 MKAY MKAY
IF U SAY SO
IM IN YR outer UPPIN YR m TIL BOTH SAEM m AN 5
IM IN YR inner UPPIN YR n TIL BOTH SAEM n AN DIFF OF 6 AN m
VISIBLE "A(" m ", " n ") = " I IZ ackermann YR m AN YR n MKAY
IM OUTTA YR inner
IM OUTTA YR outer
KTHXBYE
Lua
function ack(M,N)
if M == 0 then return N + 1 end
if N == 0 then return ack(M-1,1) end
return ack(M-1,ack(M, N-1))
end
Stackless iterative solution with multiple precision, fast
#!/usr/bin/env luajit
local gmp = require 'gmp' ('libgmp')
local mpz, z_mul, z_add, z_add_ui, z_set_d =
gmp.types.z, gmp.z_mul, gmp.z_add, gmp.z_add_ui, gmp.z_set_d
local z_cmp, z_cmp_ui, z_init_d, z_set=
gmp.z_cmp, gmp.z_cmp_ui, gmp.z_init_set_d, gmp.z_set
local printf = gmp.printf
local function ack(i,n)
local nxt=setmetatable({}, {__index=function(t,k) local z=mpz() z_init_d(z, 0) t[k]=z return z end})
local goal=setmetatable({}, {__index=function(t,k) local o=mpz() z_init_d(o, 1) t[k]=o return o end})
goal[i]=mpz() z_init_d(goal[i], -1)
local v=mpz() z_init_d(v, 0)
local ic
local END=n+1
local ntmp,gtmp
repeat
ic=0
ntmp,gtmp=nxt[ic], goal[ic]
z_add_ui(v, ntmp, 1)
while z_cmp(ntmp, gtmp) == 0 do
z_set(gtmp,v)
z_add_ui(ntmp, ntmp, 1)
nxt[ic], goal[ic]=ntmp, gtmp
ic=ic+1
ntmp,gtmp=nxt[ic], goal[ic]
end
z_add_ui(ntmp, ntmp, 1)
nxt[ic]=ntmp
until z_cmp_ui(nxt[i], END) == 0
return v
end
if #arg<1 then
print("Ackermann: "..arg[0].." <num1> [num2]")
else
printf("%Zd\n", ack(tonumber(arg[1]), arg[2] and tonumber(arg[2]) or 0))
end
- Output:
> time ./ackermann_iter.lua 4 1 65533 ./ackermann_iter.lua 4 1 0,01s user 0,01s system 95% cpu 0,015 total // AMD FX-8350@4 GHz > time ./ackermann.lua 3 10 ⏎ 8189 ./ackermann.lua 3 10 0,22s user 0,00s system 98% cpu 0,222 total // recursive solution > time ./ackermann_iter.lua 3 10 8189 ./ackermann_iter.lua 3 10 0,00s user 0,00s system 92% cpu 0,009 total
Lucid
ack(m,n)
where
ack(m,n) = if m eq 0 then n+1
else if n eq 0 then ack(m-1,1)
else ack(m-1, ack(m, n-1)) fi
fi;
end
Luck
function ackermann(m: int, n: int): int = (
if m==0 then n+1
else if n==0 then ackermann(m-1,1)
else ackermann(m-1,ackermann(m,n-1))
)
M2000 Interpreter
Module Checkit {
Def ackermann(m,n) =If(m=0-> n+1, If(n=0-> ackermann(m-1,1), ackermann(m-1,ackermann(m,n-1))))
For m = 0 to 3 {For n = 0 to 4 {Print m;" ";n;" ";ackermann(m,n)}}
}
Checkit
Module Checkit {
Module Inner (ack) {
For m = 0 to 3 {For n = 0 to 4 {Print m;" ";n;" ";ack(m,n)}}
}
Inner lambda (m,n) ->If(m=0-> n+1, If(n=0-> lambda(m-1,1),lambda(m-1,lambda(m,n-1))))
}
Checkit
M4
define(`ack',`ifelse($1,0,`incr($2)',`ifelse($2,0,`ack(decr($1),1)',`ack(decr($1),ack($1,decr($2)))')')')dnl
ack(3,3)
- Output:
61
MACRO-11
.TITLE ACKRMN
.MCALL .TTYOUT,.EXIT
ACKRMN::JMP MKTBL
; R0 = ACK(R0,R1)
ACK: MOV SP,R2 ; KEEP OLD STACK PTR
MOV #ASTK,SP ; USE PRIVATE STACK
JSR PC,1$
MOV R2,SP ; RESTORE STACK PTR
RTS PC
1$: TST R0
BNE 2$
INC R1
MOV R1,R0
RTS PC
2$: TST R1
BNE 3$
DEC R0
INC R1
BR 1$
3$: MOV R0,-(SP)
DEC R1
JSR PC,1$
MOV R0,R1
MOV (SP)+,R0
DEC R0
BR 1$
.BLKB 4000 ; BIG STACK
ASTK = .
; PRINT TABLE
MMAX = 4
NMAX = 7
MKTBL: CLR R3
1$: CLR R4
2$: MOV R3,R0
MOV R4,R1
JSR PC,ACK
JSR PC,PR0
INC R4
CMP R4,#NMAX
BLT 2$
MOV #15,R0
.TTYOUT
MOV #12,R0
.TTYOUT
INC R3
CMP R3,#MMAX
BLT 1$
.EXIT
; PRINT NUMBER IN R0 AS DECIMAL
PR0: MOV #4$,R1
1$: MOV #-1,R2
2$: INC R2
SUB #12,R0
BCC 2$
ADD #72,R0
MOVB R0,-(R1)
MOV R2,R0
BNE 1$
3$: MOVB (R1)+,R0
.TTYOUT
BNE 3$
RTS PC
.ASCII /...../
4$: .BYTE 11,0
.END ACKRMN
- Output:
1 2 3 4 5 6 7 2 3 4 5 6 7 8 3 5 7 9 11 13 15 5 13 29 61 125 253 509
MAD
While MAD supports function calls, it does not handle recursion automatically.
There is support for a stack, but the programmer has to set it up himself (by defining an array to reserve memory,
then making it the stack using the SET LIST
) command.
Values have to be pushed and popped from it by hand (using SAVE
and RESTORE
), and for
a function to be reentrant, even the return address has to be kept.
On top of this, all variables are global throughout the program (there is no scope), and argument passing is done by reference, meaning that even once the stack is set up, arguments cannot be passed in the normal way. To define a function that takes arguments, one would have to declare a helper function that then passes the arguments to the recursive function via the stack or the global variables. The following program demonstrates this.
NORMAL MODE IS INTEGER
DIMENSION LIST(3000)
SET LIST TO LIST
INTERNAL FUNCTION(DUMMY)
ENTRY TO ACKH.
LOOP WHENEVER M.E.0
FUNCTION RETURN N+1
OR WHENEVER N.E.0
M=M-1
N=1
TRANSFER TO LOOP
OTHERWISE
SAVE RETURN
SAVE DATA M
N=N-1
N=ACKH.(0)
RESTORE DATA M
RESTORE RETURN
M=M-1
TRANSFER TO LOOP
END OF CONDITIONAL
ERROR RETURN
END OF FUNCTION
INTERNAL FUNCTION(MM,NN)
ENTRY TO ACK.
M=MM
N=NN
FUNCTION RETURN ACKH.(0)
END OF FUNCTION
THROUGH SHOW, FOR I=0, 1, I.G.3
THROUGH SHOW, FOR J=0, 1, J.G.8
SHOW PRINT FORMAT ACKF,I,J,ACK.(I,J)
VECTOR VALUES ACKF = $4HACK(,I1,1H,,I1,4H) = ,I4*$
END OF PROGRAM
- Output:
ACK(0,0) = 1 ACK(0,1) = 2 ACK(0,2) = 3 ACK(0,3) = 4 ACK(0,4) = 5 ACK(0,5) = 6 ACK(0,6) = 7 ACK(0,7) = 8 ACK(0,8) = 9 ACK(1,0) = 2 ACK(1,1) = 3 ACK(1,2) = 4 ACK(1,3) = 5 ACK(1,4) = 6 ACK(1,5) = 7 ACK(1,6) = 8 ACK(1,7) = 9 ACK(1,8) = 10 ACK(2,0) = 3 ACK(2,1) = 5 ACK(2,2) = 7 ACK(2,3) = 9 ACK(2,4) = 11 ACK(2,5) = 13 ACK(2,6) = 15 ACK(2,7) = 17 ACK(2,8) = 19 ACK(3,0) = 5 ACK(3,1) = 13 ACK(3,2) = 29 ACK(3,3) = 61 ACK(3,4) = 125 ACK(3,5) = 253 ACK(3,6) = 509 ACK(3,7) = 1021 ACK(3,8) = 2045
Maple
Strictly by the definition given above, we can code this as follows.
Ackermann := proc( m :: nonnegint, n :: nonnegint )
option remember; # optional automatic memoization
if m = 0 then
n + 1
elif n = 0 then
thisproc( m - 1, 1 )
else
thisproc( m - 1, thisproc( m, n - 1 ) )
end if
end proc:
In Maple, the keyword
thisproc
refers to the currently executing procedure (closure) and is used when writing recursive procedures. (You could also use the name of the procedure, Ackermann in this case, but then a concurrently executing task or thread could re-assign that name while the recursive procedure is executing, resulting in an incorrect result.)
To make this faster, you can use known expansions for small values of . (See Wikipedia:Ackermann function)
Ackermann := proc( m :: nonnegint, n :: nonnegint )
option remember; # optional automatic memoization
if m = 0 then
n + 1
elif m = 1 then
n + 2
elif m = 2 then
2 * n + 3
elif m = 3 then
8 * 2^n - 3
elif n = 0 then
thisproc( m - 1, 1 )
else
thisproc( m - 1, thisproc( m, n - 1 ) )
end if
end proc:
This makes it possible to compute Ackermann( 4, 1 )
and Ackermann( 4, 2 )
essentially instantly, though Ackermann( 4, 3 )
is still out of reach.
To compute Ackermann( 1, i ) for i from 1 to 10 use
> map2( Ackermann, 1, [seq]( 1 .. 10 ) );
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
To get the first 10 values for m = 2 use
> map2( Ackermann, 2, [seq]( 1 .. 10 ) );
[5, 7, 9, 11, 13, 15, 17, 19, 21, 23]
For Ackermann( 4, 2 ) we get a very long number with
> length( Ackermann( 4, 2 ) );
19729
digits.
Mathcad
Mathcad is a non-text-based programming environment. The equation below is an approximation of the way that it is entered (and) displayed on a Mathcad worksheet. The worksheet is available at https://community.ptc.com/t5/PTC-Mathcad/Rosetta-Code-Ackermann-Function/m-p/750117#M197410
This particular version of Ackermann's function was created in Mathcad Prime Express 7.0, a free version of Mathcad Prime 7.0 with restrictions (such as no programming or symbolics). All Prime Express numbers are complex. There is a recursion depth limit of about 4,500.
A(m,n):=if(m=0,n+1,if(n=0,A(m-1,1),A(m-1,A(m,n-1))))
The worksheet also contains an explictly-calculated version of Ackermann's function that calls the tetration function na.
na(a,n):=if(n=0,1,ana(a,n-1))
aerror(m,n):=error(format("cannot compute a({0},{1})",m,n))
a(m,n):=if(m=0,n+1,if(m=1,n+2,if(m=2,2n+3,if(m=3,2^(n+3)-3,aerror(m,n)))))
a(m,n):=if(m=4,na(2,n+3)-3,a(m,n)
Mathematica / Wolfram Language
Two possible implementations would be:
$RecursionLimit=Infinity
Ackermann1[m_,n_]:=
If[m==0,n+1,
If[ n==0,Ackermann1[m-1,1],
Ackermann1[m-1,Ackermann1[m,n-1]]
]
]
Ackermann2[0,n_]:=n+1;
Ackermann2[m_,0]:=Ackermann1[m-1,1];
Ackermann2[m_,n_]:=Ackermann1[m-1,Ackermann1[m,n-1]]
Note that the second implementation is quite a bit faster, as doing 'if' comparisons is slower than the built-in pattern matching algorithms. Examples:
Flatten[#,1]&@Table[{"Ackermann2["<>ToString[i]<>","<>ToString[j]<>"] =",Ackermann2[i,j]},{i,3},{j,8}]//Grid
gives back:
Ackermann2[1,1] = 3
Ackermann2[1,2] = 4
Ackermann2[1,3] = 5
Ackermann2[1,4] = 6
Ackermann2[1,5] = 7
Ackermann2[1,6] = 8
Ackermann2[1,7] = 9
Ackermann2[1,8] = 10
Ackermann2[2,1] = 5
Ackermann2[2,2] = 7
Ackermann2[2,3] = 9
Ackermann2[2,4] = 11
Ackermann2[2,5] = 13
Ackermann2[2,6] = 15
Ackermann2[2,7] = 17
Ackermann2[2,8] = 19
Ackermann2[3,1] = 13
Ackermann2[3,2] = 29
Ackermann2[3,3] = 61
Ackermann2[3,4] = 125
Ackermann2[3,5] = 253
Ackermann2[3,6] = 509
Ackermann2[3,7] = 1021
Ackermann2[3,8] = 2045
If we would like to calculate Ackermann[4,1] or Ackermann[4,2] we have to optimize a little bit:
Clear[Ackermann3]
$RecursionLimit=Infinity;
Ackermann3[0,n_]:=n+1;
Ackermann3[1,n_]:=n+2;
Ackermann3[2,n_]:=3+2n;
Ackermann3[3,n_]:=5+8 (2^n-1);
Ackermann3[m_,0]:=Ackermann3[m-1,1];
Ackermann3[m_,n_]:=Ackermann3[m-1,Ackermann3[m,n-1]]
Now computing Ackermann[4,1] and Ackermann[4,2] can be done quickly (<0.01 sec): Examples 2:
Ackermann3[4, 1]
Ackermann3[4, 2]
gives back:
65533
2003529930406846464979072351560255750447825475569751419265016973710894059556311453089506130880........699146577530041384717124577965048175856395072895337539755822087777506072339445587895905719156733
Ackermann[4,2] has 19729 digits, several thousands of digits omitted in the result above for obvious reasons. Ackermann[5,0] can be computed also quite fast, and is equal to 65533. Summarizing Ackermann[0,n_], Ackermann[1,n_], Ackermann[2,n_], and Ackermann[3,n_] can all be calculated for n>>1000. Ackermann[4,0], Ackermann[4,1], Ackermann[4,2] and Ackermann[5,0] are only possible now. Maybe in the future we can calculate higher Ackermann numbers efficiently and fast. Although showing the results will always be a problem.
MATLAB
function A = ackermannFunction(m,n)
if m == 0
A = n+1;
elseif (m > 0) && (n == 0)
A = ackermannFunction(m-1,1);
else
A = ackermannFunction( m-1,ackermannFunction(m,n-1) );
end
end
Maxima
ackermann(m, n) := if integerp(m) and integerp(n) then ackermann[m, n] else 'ackermann(m, n)$
ackermann[m, n] := if m = 0 then n + 1
elseif m = 1 then 2 + (n + 3) - 3
elseif m = 2 then 2 * (n + 3) - 3
elseif m = 3 then 2^(n + 3) - 3
elseif n = 0 then ackermann[m - 1, 1]
else ackermann[m - 1, ackermann[m, n - 1]]$
tetration(a, n) := if integerp(n) then block([b: a], for i from 2 thru n do b: a^b, b) else 'tetration(a, n)$
/* this should evaluate to zero */
ackermann(4, n) - (tetration(2, n + 3) - 3);
subst(n = 2, %);
ev(%, nouns);
MAXScript
Use with caution. Will cause a stack overflow for m > 3.
fn ackermann m n =
(
if m == 0 then
(
return n + 1
)
else if n == 0 then
(
ackermann (m-1) 1
)
else
(
ackermann (m-1) (ackermann m (n-1))
)
)
Mercury
This is the Ackermann function with some (obvious) elements elided. The ack/3
predicate is implemented in terms of the ack/2
function. The ack/2
function is implemented in terms of the ack/3
predicate. This makes the code both more concise and easier to follow than would otherwise be the case. The integer
type is used instead of int
because the problem statement stipulates the use of bignum integers if possible.
:- func ack(integer, integer) = integer.
ack(M, N) = R :- ack(M, N, R).
:- pred ack(integer::in, integer::in, integer::out) is det.
ack(M, N, R) :-
( ( M < integer(0)
; N < integer(0) ) -> throw(bounds_error)
; M = integer(0) -> R = N + integer(1)
; N = integer(0) -> ack(M - integer(1), integer(1), R)
; ack(M - integer(1), ack(M, N - integer(1)), R) ).
min
(
:n :m
(
((m 0 ==) (n 1 +))
((n 0 ==) (m 1 - 1 ackermann))
((true) (m 1 - m n 1 - ackermann ackermann))
) case
) :ackermann
MiniScript
ackermann = function(m, n)
if m == 0 then return n+1
if n == 0 then return ackermann(m - 1, 1)
return ackermann(m - 1, ackermann(m, n - 1))
end function
for m in range(0, 3)
for n in range(0, 4)
print "(" + m + ", " + n + "): " + ackermann(m, n)
end for
end for
МК-61/52
П1 <-> П0 ПП 06 С/П ИП0 x=0 13 ИП1
1 + В/О ИП1 x=0 24 ИП0 1 П1 -
П0 ПП 06 В/О ИП0 П2 ИП1 1 - П1
ПП 06 П1 ИП2 1 - П0 ПП 06 В/О
ML/I
ML/I loves recursion, but runs out of its default amount of storage with larger numbers than those tested here!
Program
MCSKIP "WITH" NL
"" Ackermann function
"" Will overflow when it reaches implementation-defined signed integer limit
MCSKIP MT,<>
MCINS %.
MCDEF ACK WITHS ( , )
AS <MCSET T1=%A1.
MCSET T2=%A2.
MCGO L1 UNLESS T1 EN 0
%%T2.+1.MCGO L0
%L1.MCGO L2 UNLESS T2 EN 0
ACK(%%T1.-1.,1)MCGO L0
%L2.ACK(%%T1.-1.,ACK(%T1.,%%T2.-1.))>
"" Macro ACK now defined, so try it out
a(0,0) => ACK(0,0)
a(0,1) => ACK(0,1)
a(0,2) => ACK(0,2)
a(0,3) => ACK(0,3)
a(0,4) => ACK(0,4)
a(0,5) => ACK(0,5)
a(1,0) => ACK(1,0)
a(1,1) => ACK(1,1)
a(1,2) => ACK(1,2)
a(1,3) => ACK(1,3)
a(1,4) => ACK(1,4)
a(2,0) => ACK(2,0)
a(2,1) => ACK(2,1)
a(2,2) => ACK(2,2)
a(2,3) => ACK(2,3)
a(3,0) => ACK(3,0)
a(3,1) => ACK(3,1)
a(3,2) => ACK(3,2)
a(4,0) => ACK(4,0)
- Output:
a(0,0) => 1
a(0,1) => 2
a(0,2) => 3
a(0,3) => 4
a(0,4) => 5
a(0,5) => 6
a(1,0) => 2
a(1,1) => 3
a(1,2) => 4
a(1,3) => 5
a(1,4) => 6
a(2,0) => 3
a(2,1) => 5
a(2,2) => 7
a(2,3) => 9
a(3,0) => 5
a(3,1) => 13
a(3,2) => 29
a(4,0) => 13
mLite
fun ackermann( 0, n ) = n + 1
| ( m, 0 ) = ackermann( m - 1, 1 )
| ( m, n ) = ackermann( m - 1, ackermann(m, n - 1) )
Test code providing tuples from (0,0) to (3,8)
fun jota x = map (fn x = x-1) ` iota x
fun test_tuples (x, y) = append_map (fn a = map (fn b = (b, a)) ` jota x) ` jota y
map ackermann (test_tuples(4,9))
Result
[1, 2, 3, 5, 2, 3, 5, 13, 3, 4, 7, 29, 4, 5, 9, 61, 5, 6, 11, 125, 6, 7, 13, 253, 7, 8, 15, 509, 8, 9, 17, 1021, 9, 10, 19, 2045]
Modula-2
MODULE ackerman;
IMPORT ASCII, NumConv, InOut;
VAR m, n : LONGCARD;
string : ARRAY [0..19] OF CHAR;
OK : BOOLEAN;
PROCEDURE Ackerman (x, y : LONGCARD) : LONGCARD;
BEGIN
IF x = 0 THEN RETURN y + 1
ELSIF y = 0 THEN RETURN Ackerman (x - 1 , 1)
ELSE
RETURN Ackerman (x - 1 , Ackerman (x , y - 1))
END
END Ackerman;
BEGIN
FOR m := 0 TO 3 DO
FOR n := 0 TO 6 DO
NumConv.Num2Str (Ackerman (m, n), 10, string, OK);
IF OK THEN
InOut.WriteString (string)
ELSE
InOut.WriteString ("* Error in number * ")
END;
InOut.Write (ASCII.HT)
END;
InOut.WriteLn
END;
InOut.WriteLn
END ackerman.
- Output:
jan@Beryllium:~/modula/rosetta$ ackerman1 2 3 4 5 6 7 2 3 4 5 6 7 8 3 5 7 9 11 13 15
5 13 29 61 125 253 509
Modula-3
The type CARDINAL is defined in Modula-3 as [0..LAST(INTEGER)], in other words, it can hold all positive integers.
MODULE Ack EXPORTS Main;
FROM IO IMPORT Put;
FROM Fmt IMPORT Int;
PROCEDURE Ackermann(m, n: CARDINAL): CARDINAL =
BEGIN
IF m = 0 THEN
RETURN n + 1;
ELSIF n = 0 THEN
RETURN Ackermann(m - 1, 1);
ELSE
RETURN Ackermann(m - 1, Ackermann(m, n - 1));
END;
END Ackermann;
BEGIN
FOR m := 0 TO 3 DO
FOR n := 0 TO 6 DO
Put(Int(Ackermann(m, n)) & " ");
END;
Put("\n");
END;
END Ack.
- Output:
1 2 3 4 5 6 7 2 3 4 5 6 7 8 3 5 7 9 11 13 15 5 13 29 61 125 253 509
MUMPS
Ackermann(m,n) ;
If m=0 Quit n+1
If m>0,n=0 Quit $$Ackermann(m-1,1)
If m>0,n>0 Quit $$Ackermann(m-1,$$Ackermann(m,n-1))
Set $Ecode=",U13-Invalid parameter for Ackermann: m="_m_", n="_n_","
Write $$Ackermann(1,8) ; 10
Write $$Ackermann(2,8) ; 19
Write $$Ackermann(3,5) ; 253
Neko
/**
Ackermann recursion, in Neko
Tectonics:
nekoc ackermann.neko
neko ackermann 4 0
*/
ack = function(x,y) {
if (x == 0) return y+1;
if (y == 0) return ack(x-1,1);
return ack(x-1, ack(x,y-1));
};
var arg1 = $int($loader.args[0]);
var arg2 = $int($loader.args[1]);
/* If not given, or negative, default to Ackermann(3,4) */
if (arg1 == null || arg1 < 0) arg1 = 3;
if (arg2 == null || arg2 < 0) arg2 = 4;
try
$print("Ackermann(", arg1, ",", arg2, "): ", ack(arg1,arg2), "\n")
catch problem
$print("Ackermann(", arg1, ",", arg2, "): ", problem, "\n")
- Output:
prompt$ nekoc ackermann.neko prompt$ neko ackermann.n 3 4 Ackermann(3,4): 125 prompt$ time neko ackermann.n 4 1 Ackermann(4,1): Stack Overflow real 0m31.475s user 0m31.460s sys 0m0.012s prompt$ time neko ackermann 3 10 Ackermann(3,10): 8189 real 0m1.865s user 0m1.862s sys 0m0.004s
Nemerle
In Nemerle, we can state the Ackermann function as a lambda. By using pattern-matching, our definition strongly resembles the mathematical notation.
using System;
using Nemerle.IO;
def ackermann(m, n) {
def A = ackermann;
match(m, n) {
| (0, n) => n + 1
| (m, 0) when m > 0 => A(m - 1, 1)
| (m, n) when m > 0 && n > 0 => A(m - 1, A(m, n - 1))
| _ => throw Exception("invalid inputs");
}
}
for(mutable m = 0; m < 4; m++) {
for(mutable n = 0; n < 5; n++) {
print("ackermann($m, $n) = $(ackermann(m, n))\n");
}
}
A terser version using implicit match
(which doesn't use the alias A
internally):
def ackermann(m, n) {
| (0, n) => n + 1
| (m, 0) when m > 0 => ackermann(m - 1, 1)
| (m, n) when m > 0 && n > 0 => ackermann(m - 1, ackermann(m, n - 1))
| _ => throw Exception("invalid inputs");
}
Or, if we were set on using the A
notation, we could do this:
def ackermann = {
def A(m, n) {
| (0, n) => n + 1
| (m, 0) when m > 0 => A(m - 1, 1)
| (m, n) when m > 0 && n > 0 => A(m - 1, A(m, n - 1))
| _ => throw Exception("invalid inputs");
}
A
}
NetRexx
/* NetRexx */
options replace format comments java crossref symbols binary
numeric digits 66
parse arg j_ k_ .
if j_ = '' | j_ = '.' | \j_.datatype('w') then j_ = 3
if k_ = '' | k_ = '.' | \k_.datatype('w') then k_ = 5
loop m_ = 0 to j_
say
loop n_ = 0 to k_
say 'ackermann('m_','n_') =' ackermann(m_, n_).right(5)
end n_
end m_
return
method ackermann(m, n) public static
select
when m = 0 then rval = n + 1
when n = 0 then rval = ackermann(m - 1, 1)
otherwise rval = ackermann(m - 1, ackermann(m, n - 1))
end
return rval
NewLISP
#! /usr/local/bin/newlisp
(define (ackermann m n)
(cond ((zero? m) (inc n))
((zero? n) (ackermann (dec m) 1))
(true (ackermann (- m 1) (ackermann m (dec n))))))
In case of stack overflow error, you have to start your program with a proper "-s <value>" flag as "newlisp -s 100000 ./ackermann.lsp". See http://www.newlisp.org/newlisp_manual.html#stack_size
Nim
from strutils import parseInt
proc ackermann(m, n: int64): int64 =
if m == 0:
result = n + 1
elif n == 0:
result = ackermann(m - 1, 1)
else:
result = ackermann(m - 1, ackermann(m, n - 1))
proc getNumber(): int =
try:
result = stdin.readLine.parseInt
except ValueError:
echo "An integer, please!"
result = getNumber()
if result < 0:
echo "Please Enter a non-negative Integer: "
result = getNumber()
echo "First non-negative Integer please: "
let first = getNumber()
echo "Second non-negative Integer please: "
let second = getNumber()
echo "Result: ", $ackermann(first, second)
Nit
Source: the official Nit’s repository.
# Task: Ackermann function
#
# A simple straightforward recursive implementation.
module ackermann_function
fun ack(m, n: Int): Int
do
if m == 0 then return n + 1
if n == 0 then return ack(m-1,1)
return ack(m-1, ack(m, n-1))
end
for m in [0..3] do
for n in [0..6] do
print ack(m,n)
end
print ""
end
Output:
1 2 3 4 5 6 7 2 3 4 5 6 7 8 3 5 7 9 11 13 15 5 13 29 61 125 253 509
Oberon-2
MODULE ackerman;
IMPORT Out;
VAR m, n : INTEGER;
PROCEDURE Ackerman (x, y : INTEGER) : INTEGER;
BEGIN
IF x = 0 THEN RETURN y + 1
ELSIF y = 0 THEN RETURN Ackerman (x - 1 , 1)
ELSE
RETURN Ackerman (x - 1 , Ackerman (x , y - 1))
END
END Ackerman;
BEGIN
FOR m := 0 TO 3 DO
FOR n := 0 TO 6 DO
Out.Int (Ackerman (m, n), 10);
Out.Char (9X)
END;
Out.Ln
END;
Out.Ln
END ackerman.
Objeck
class Ackermann {
function : Main(args : String[]) ~ Nil {
for(m := 0; m <= 3; ++m;) {
for(n := 0; n <= 4; ++n;) {
a := Ackermann(m, n);
if(a > 0) {
"Ackermann({$m}, {$n}) = {$a}"->PrintLine();
};
};
};
}
function : Ackermann(m : Int, n : Int) ~ Int {
if(m > 0) {
if (n > 0) {
return Ackermann(m - 1, Ackermann(m, n - 1));
}
else if (n = 0) {
return Ackermann(m - 1, 1);
};
}
else if(m = 0) {
if(n >= 0) {
return n + 1;
};
};
return -1;
}
}
Ackermann(0, 0) = 1 Ackermann(0, 1) = 2 Ackermann(0, 2) = 3 Ackermann(0, 3) = 4 Ackermann(0, 4) = 5 Ackermann(1, 0) = 2 Ackermann(1, 1) = 3 Ackermann(1, 2) = 4 Ackermann(1, 3) = 5 Ackermann(1, 4) = 6 Ackermann(2, 0) = 3 Ackermann(2, 1) = 5 Ackermann(2, 2) = 7 Ackermann(2, 3) = 9 Ackermann(2, 4) = 11 Ackermann(3, 0) = 5 Ackermann(3, 1) = 13 Ackermann(3, 2) = 29 Ackermann(3, 3) = 61 Ackermann(3, 4) = 125
OCaml
let rec a m n =
if m=0 then (n+1) else
if n=0 then (a (m-1) 1) else
(a (m-1) (a m (n-1)))
or:
let rec a = function
| 0, n -> (n+1)
| m, 0 -> a(m-1, 1)
| m, n -> a(m-1, a(m, n-1))
with memoization using an hash-table:
let h = Hashtbl.create 4001
let a m n =
try Hashtbl.find h (m, n)
with Not_found ->
let res = a (m, n) in
Hashtbl.add h (m, n) res;
(res)
taking advantage of the memoization we start calling small values of m and n in order to reduce the recursion call stack:
let a m n =
for _m = 0 to m do
for _n = 0 to n do
ignore(a _m _n);
done;
done;
(a m n)
Arbitrary precision
With arbitrary-precision integers (Big_int module):
open Big_int
let one = unit_big_int
let zero = zero_big_int
let succ = succ_big_int
let pred = pred_big_int
let eq = eq_big_int
let rec a m n =
if eq m zero then (succ n) else
if eq n zero then (a (pred m) one) else
(a (pred m) (a m (pred n)))
compile with:
ocamlopt -o acker nums.cmxa acker.ml
Tail-Recursive
Here is a tail-recursive version:
let rec find_option h v =
try Some(Hashtbl.find h v)
with Not_found -> None
let rec a bounds caller todo m n =
match m, n with
| 0, n ->
let r = (n+1) in
( match todo with
| [] -> r
| (m,n)::todo ->
List.iter (fun k ->
if not(Hashtbl.mem bounds k)
then Hashtbl.add bounds k r) caller;
a bounds [] todo m n )
| m, 0 ->
a bounds caller todo (m-1) 1
| m, n ->
match find_option bounds (m, n-1) with
| Some a_rec ->
let caller = (m,n)::caller in
a bounds caller todo (m-1) a_rec
| None ->
let todo = (m,n)::todo
and caller = [(m, n-1)] in
a bounds caller todo m (n-1)
let a = a (Hashtbl.create 42 (* arbitrary *) ) [] [] ;;
This one uses the arbitrary precision, the tail-recursion, and the optimisation explain on the Wikipedia page about (m,n) = (3,_).
open Big_int
let one = unit_big_int
let zero = zero_big_int
let succ = succ_big_int
let pred = pred_big_int
let add = add_big_int
let sub = sub_big_int
let eq = eq_big_int
let three = succ(succ one)
let power = power_int_positive_big_int
let eq2 (a1,a2) (b1,b2) =
(eq a1 b1) && (eq a2 b2)
module H = Hashtbl.Make
(struct
type t = Big_int.big_int * Big_int.big_int
let equal = eq2
let hash (x,y) = Hashtbl.hash
(Big_int.string_of_big_int x ^ "," ^
Big_int.string_of_big_int y)
(* probably not a very good hash function *)
end)
let rec find_option h v =
try Some (H.find h v)
with Not_found -> None
let rec a bounds caller todo m n =
let may_tail r =
let k = (m,n) in
match todo with
| [] -> r
| (m,n)::todo ->
List.iter (fun k ->
if not (H.mem bounds k)
then H.add bounds k r) (k::caller);
a bounds [] todo m n
in
match m, n with
| m, n when eq m zero ->
let r = (succ n) in
may_tail r
| m, n when eq n zero ->
let caller = (m,n)::caller in
a bounds caller todo (pred m) one
| m, n when eq m three ->
let r = sub (power 2 (add n three)) three in
may_tail r
| m, n ->
match find_option bounds (m, pred n) with
| Some a_rec ->
let caller = (m,n)::caller in
a bounds caller todo (pred m) a_rec
| None ->
let todo = (m,n)::todo in
let caller = [(m, pred n)] in
a bounds caller todo m (pred n)
let a = a (H.create 42 (* arbitrary *)) [] [] ;;
let () =
let m, n =
try
big_int_of_string Sys.argv.(1),
big_int_of_string Sys.argv.(2)
with _ ->
Printf.eprintf "usage: %s <int> <int>\n" Sys.argv.(0);
exit 1
in
let r = a m n in
Printf.printf "(a %s %s) = %s\n"
(string_of_big_int m)
(string_of_big_int n)
(string_of_big_int r);
;;
Octave
function r = ackerman(m, n)
if ( m == 0 )
r = n + 1;
elseif ( n == 0 )
r = ackerman(m-1, 1);
else
r = ackerman(m-1, ackerman(m, n-1));
endif
endfunction
for i = 0:3
disp(ackerman(i, 4));
endfor
Oforth
: A( m n -- p )
m ifZero: [ n 1+ return ]
m 1- n ifZero: [ 1 ] else: [ A( m, n 1- ) ] A
;
Ol
; simple version
(define (A m n)
(cond
((= m 0) (+ n 1))
((= n 0) (A (- m 1) 1))
(else (A (- m 1) (A m (- n 1))))))
(print "simple version (A 3 6): " (A 3 6))
; smart (lazy) version
(define (ints-from n)
(cons* n (delay (ints-from (+ n 1)))))
(define (knuth-up-arrow a n b)
(let loop ((n n) (b b))
(cond ((= b 0) 1)
((= n 1) (expt a b))
(else (loop (- n 1) (loop n (- b 1)))))))
(define (A+ m n)
(define (A-stream)
(cons*
(ints-from 1) ;; m = 0
(ints-from 2) ;; m = 1
;; m = 2
(lmap (lambda (n)
(+ (* 2 (+ n 1)) 1))
(ints-from 0))
;; m = 3
(lmap (lambda (n)
(- (knuth-up-arrow 2 (- m 2) (+ n 3)) 3))
(ints-from 0))
;; m = 4...
(delay (ldrop (A-stream) 3))))
(llref (llref (A-stream) m) n))
(print "extended version (A 3 6): " (A+ 3 6))
- Output:
simple version (A 3 6): 509 extended version (A 3 6): 509
OOC
ack: func (m: Int, n: Int) -> Int {
if (m == 0) {
n + 1
} else if (n == 0) {
ack(m - 1, 1)
} else {
ack(m - 1, ack(m, n - 1))
}
}
main: func {
for (m in 0..4) {
for (n in 0..10) {
"ack(#{m}, #{n}) = #{ack(m, n)}" println()
}
}
}
ooRexx
loop m = 0 to 3
loop n = 0 to 6
say "Ackermann("m", "n") =" ackermann(m, n)
end
end
::routine ackermann
use strict arg m, n
-- give us some precision room
numeric digits 10000
if m = 0 then return n + 1
else if n = 0 then return ackermann(m - 1, 1)
else return ackermann(m - 1, ackermann(m, n - 1))
- Output:
Ackermann(0, 0) = 1 Ackermann(0, 1) = 2 Ackermann(0, 2) = 3 Ackermann(0, 3) = 4 Ackermann(0, 4) = 5 Ackermann(0, 5) = 6 Ackermann(0, 6) = 7 Ackermann(1, 0) = 2 Ackermann(1, 1) = 3 Ackermann(1, 2) = 4 Ackermann(1, 3) = 5 Ackermann(1, 4) = 6 Ackermann(1, 5) = 7 Ackermann(1, 6) = 8 Ackermann(2, 0) = 3 Ackermann(2, 1) = 5 Ackermann(2, 2) = 7 Ackermann(2, 3) = 9 Ackermann(2, 4) = 11 Ackermann(2, 5) = 13 Ackermann(2, 6) = 15 Ackermann(3, 0) = 5 Ackermann(3, 1) = 13 Ackermann(3, 2) = 29 Ackermann(3, 3) = 61 Ackermann(3, 4) = 125 Ackermann(3, 5) = 253 Ackermann(3, 6) = 509
Order
#include <order/interpreter.h>
#define ORDER_PP_DEF_8ack ORDER_PP_FN( \
8fn(8X, 8Y, \
8cond((8is_0(8X), 8inc(8Y)) \
(8is_0(8Y), 8ack(8dec(8X), 1)) \
(8else, 8ack(8dec(8X), 8ack(8X, 8dec(8Y)))))))
ORDER_PP(8to_lit(8ack(3, 4))) // 125
Oz
Oz has arbitrary precision integers.
declare
fun {Ack M N}
if M == 0 then N+1
elseif N == 0 then {Ack M-1 1}
else {Ack M-1 {Ack M N-1}}
end
end
in
{Show {Ack 3 7}}
PARI/GP
Naive implementation.
A(m,n)={
if(m,
if(n,
A(m-1, A(m,n-1))
,
A(m-1,1)
)
,
n+1
)
};
Pascal
Program Ackerman;
function ackermann(m, n: Integer) : Integer;
begin
if m = 0 then
ackermann := n+1
else if n = 0 then
ackermann := ackermann(m-1, 1)
else
ackermann := ackermann(m-1, ackermann(m, n-1));
end;
var
m, n : Integer;
begin
for n := 0 to 6 do
for m := 0 to 3 do
WriteLn('A(', m, ',', n, ') = ', ackermann(m,n));
end.
Pascal
Program Ackerman;
function ackermann(m, n: Integer) : Integer;
begin
if m = 0 then
ackermann := n+1
else if n = 0 then
ackermann := ackermann(m-1, 1)
else
ackermann := ackermann(m-1, ackermann(m, n-1));
end;
var
m, n : Integer;
begin
for n := 0 to 6 do
for m := 0 to 3 do
WriteLn('A(', m, ',', n, ') = ', ackermann(m,n));
end.
PascalABC.NET
function Ackermann(m,n: integer): integer;
begin
if (m < 0) or (n < 0) then
raise new System.ArgumentOutOfRangeException();
if m = 0 then
Result := n + 1
else if n = 0 then
Result := Ackermann(m - 1, 1)
else Result := Ackermann(m - 1, Ackermann(m, n - 1))
end;
begin
for var m := 0 to 3 do
for var n := 0 to 4 do
Println($'Ackermann({m}, {n}) = {Ackermann(m,n)}');
end.
- Output:
Ackermann(0, 0) = 1 Ackermann(0, 1) = 2 Ackermann(0, 2) = 3 Ackermann(0, 3) = 4 Ackermann(0, 4) = 5 Ackermann(1, 0) = 2 Ackermann(1, 1) = 3 Ackermann(1, 2) = 4 Ackermann(1, 3) = 5 Ackermann(1, 4) = 6 Ackermann(2, 0) = 3 Ackermann(2, 1) = 5 Ackermann(2, 2) = 7 Ackermann(2, 3) = 9 Ackermann(2, 4) = 11 Ackermann(3, 0) = 5 Ackermann(3, 1) = 13 Ackermann(3, 2) = 29 Ackermann(3, 3) = 61 Ackermann(3, 4) = 125
Perl
We memoize calls to A to make A(2, n) and A(3, n) feasible for larger values of n.
{
my @memo;
sub A {
my( $m, $n ) = @_;
$memo[ $m ][ $n ] and return $memo[ $m ][ $n ];
$m or return $n + 1;
return $memo[ $m ][ $n ] = (
$n
? A( $m - 1, A( $m, $n - 1 ) )
: A( $m - 1, 1 )
);
}
}
An implementation using the conditional statements 'if', 'elsif' and 'else':
sub A {
my ($m, $n) = @_;
if ($m == 0) { $n + 1 }
elsif ($n == 0) { A($m - 1, 1) }
else { A($m - 1, A($m, $n - 1)) }
}
An implementation using ternary chaining:
sub A {
my ($m, $n) = @_;
$m == 0 ? $n + 1 :
$n == 0 ? A($m - 1, 1) :
A($m - 1, A($m, $n - 1))
}
Adding memoization and extra terms:
use Memoize; memoize('ack2');
use bigint try=>"GMP";
sub ack2 {
my ($m, $n) = @_;
$m == 0 ? $n + 1 :
$m == 1 ? $n + 2 :
$m == 2 ? 2*$n + 3 :
$m == 3 ? 8 * (2**$n - 1) + 5 :
$n == 0 ? ack2($m-1, 1)
: ack2($m-1, ack2($m, $n-1));
}
print "ack2(3,4) is ", ack2(3,4), "\n";
print "ack2(4,1) is ", ack2(4,1), "\n";
print "ack2(4,2) has ", length(ack2(4,2)), " digits\n";
- Output:
ack2(3,4) is 125 ack2(4,1) is 65533 ack2(4,2) has 19729 digits
An optimized version, which uses @_
as a stack,
instead of recursion. Very fast.
use strict;
use warnings;
use Math::BigInt;
use constant two => Math::BigInt->new(2);
sub ack {
my $n = pop;
while( @_ ) {
my $m = pop;
if( $m > 3 ) {
push @_, (--$m) x $n;
push @_, reverse 3 .. --$m;
$n = 13;
} elsif( $m == 3 ) {
if( $n < 29 ) {
$n = ( 1 << ( $n + 3 ) ) - 3;
} else {
$n = two ** ( $n + 3 ) - 3;
}
} elsif( $m == 2 ) {
$n = 2 * $n + 3;
} elsif( $m >= 0 ) {
$n = $n + $m + 1;
} else {
die "negative m!";
}
}
$n;
}
print "ack(3,4) is ", ack(3,4), "\n";
print "ack(4,1) is ", ack(4,1), "\n";
print "ack(4,2) has ", length(ack(4,2)), " digits\n";
Phix
native version
function ack(integer m, integer n) if m=0 then return n+1 elsif m=1 then return n+2 elsif m=2 then return 2*n+3 elsif m=3 then return power(2,n+3)-3 elsif m>0 and n=0 then return ack(m-1,1) else return ack(m-1,ack(m,n-1)) end if end function constant limit = 23, fmtlens = {1,2,2,2,3,3,3,4,4,4,4,5,5,5,6,6,6,7,7,7,7,8,8,8} atom t0 = time() printf(1," 0") for j=1 to limit do string fmt = sprintf(" %%%dd",fmtlens[j+1]) printf(1,fmt,j) end for printf(1,"\n") for i=0 to 5 do printf(1,"%d:",i) for j=0 to iff(i>=4?5-i:limit) do string fmt = sprintf(" %%%dd",fmtlens[j+1]) printf(1,fmt,{ack(i,j)}) end for printf(1,"\n") end for
- Output:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 0: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 1: 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 2: 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 3: 5 13 29 61 125 253 509 1021 2045 4093 8189 16381 32765 65533 131069 262141 524285 1048573 2097149 4194301 8388605 16777213 33554429 67108861 4: 13 65533 5: 65533
ack(4,2) and above fail with power function overflow. ack(3,100) will get you an answer, but only accurate to 16 or so digits.
gmp version
-- demo\rosetta\Ackermann.exw include mpfr.e procedure ack(integer m, mpz n) if m=0 then mpz_add_ui(n, n, 1) -- return n+1 elsif m=1 then mpz_add_ui(n, n, 2) -- return n+2 elsif m=2 then mpz_mul_si(n, n, 2) mpz_add_ui(n, n, 3) -- return 2*n+3 elsif m=3 then if not mpz_fits_integer(n) then -- As per Go: 2^MAXINT would most certainly run out of memory. -- (think about it: a million digits is fine but pretty daft; -- however a billion digits requires > addressable memory.) integer bn = mpz_sizeinbase(n, 2) throw(sprintf("A(m,n) had n of %d bits; too large",bn)) end if integer ni = mpz_get_integer(n) mpz_set_si(n, 8) mpz_mul_2exp(n, n, ni) -- (n:=8*2^ni) mpz_sub_ui(n, n, 3) -- return power(2,n+3)-3 elsif mpz_cmp_si(n,0)=0 then mpz_set_si(n, 1) ack(m-1,n) -- return ack(m-1,1) else mpz_sub_ui(n, n, 1) ack(m,n) ack(m-1,n) -- return ack(m-1,ack(m,n-1)) end if end procedure constant limit = 23, fmtlens = {1,2,2,2,3,3,3,4,4,4,4,5,5,5,6,6,6,7,7,7,7,8,8,8}, extras = {{3,100},{3,1e6},{4,2},{4,3}} procedure ackermann_tests() atom t0 = time() atom n = mpz_init() printf(1," 0") for j=1 to limit do string fmt = sprintf(" %%%dd",fmtlens[j+1]) printf(1,fmt,j) end for printf(1,"\n") for i=0 to 5 do printf(1,"%d:",i) for j=0 to iff(i>=4?5-i:limit) do mpz_set_si(n, j) ack(i,n) string fmt = sprintf(" %%%ds",fmtlens[j+1]) printf(1,fmt,{mpz_get_str(n)}) end for printf(1,"\n") end for printf(1,"\n") for i=1 to length(extras) do integer {em, en} = extras[i] mpz_set_si(n, en) string res try ack(em,n) res = mpz_get_str(n) integer lr = length(res) if lr>50 then res[21..-21] = "..." res &= sprintf(" (%d digits)",lr) end if catch e -- ack(4,3), ack(5,1) and ack(6,0) all fail, -- just as they should do res = "***ERROR***: "&e[E_USER] end try printf(1,"ack(%d,%d) %s\n",{em,en,res}) end for n = mpz_free(n) printf(1,"\n") printf(1,"ackermann_tests completed (%s)\n\n",{elapsed(time()-t0)}) end procedure ackermann_tests()
- Output:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 0: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 1: 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 2: 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 3: 5 13 29 61 125 253 509 1021 2045 4093 8189 16381 32765 65533 131069 262141 524285 1048573 2097149 4194301 8388605 16777213 33554429 67108861 4: 13 65533 5: 65533 ack(3,100) 10141204801825835211973625643005 ack(3,1000000) 79205249834367186005...39107225301976875005 (301031 digits) ack(4,2) 20035299304068464649...45587895905719156733 (19729 digits) ack(4,3) ***ERROR***: A(m,n) had n of 65536 bits; too large ackermann_tests completed (0.2s)
Phixmonti
def ack
var n var m
m 0 == if
n 1 +
else
n 0 == if
m 1 - 1 ack
else
m 1 - m n 1 - ack ack
endif
endif
enddef
3 6 ack print nl
PHP
function ackermann( $m , $n )
{
if ( $m==0 )
{
return $n + 1;
}
elseif ( $n==0 )
{
return ackermann( $m-1 , 1 );
}
return ackermann( $m-1, ackermann( $m , $n-1 ) );
}
echo ackermann( 3, 4 );
// prints 125
Picat
go =>
foreach(M in 0..3)
println([m=M,[a(M,N) : N in 0..16]])
end,
nl,
printf("a2(4,1): %d\n", a2(4,1)),
nl,
time(check_larger(3,10000)),
nl,
time(check_larger(4,2)),
nl.
% Using a2/2 and chop off large output
check_larger(M,N) =>
printf("a2(%d,%d): ", M,N),
A = a2(M,N).to_string,
Len = A.len,
if Len < 50 then
println(A)
else
println(A[1..20] ++ ".." ++ A[Len-20..Len])
end,
println(digits=Len).
% Plain tabled (memoized) version with guards
table
a(0, N) = N+1 => true.
a(M, 0) = a(M-1,1), M > 0 => true.
a(M, N) = a(M-1,a(M, N-1)), M > 0, N > 0 => true.
% Faster and pure function version (no guards).
% (Based on Python example.)
table
a2(0,N) = N + 1.
a2(1,N) = N + 2.
a2(2,N) = 2*N + 3.
a2(3,N) = 8*(2**N - 1) + 5.
a2(M,N) = cond(N == 0,a2(M-1, 1), a2(M-1, a2(M, N-1))).
- Output:
[m = 0,[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]] [m = 1,[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]] [m = 2,[3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35]] [m = 3,[5,13,29,61,125,253,509,1021,2045,4093,8189,16381,32765,65533,131069,262141,524285]] a2(4,1): 65533 a2(3,10000): 15960504935046067079..454194438340773675005 digits = 3012 CPU time 0.02 seconds. a2(4,2): 20035299304068464649..445587895905719156733 digits = 19729 CPU time 0.822 seconds.
PicoLisp
(de ack (X Y)
(cond
((=0 X) (inc Y))
((=0 Y) (ack (dec X) 1))
(T (ack (dec X) (ack X (dec Y)))) ) )
Piet
Rendered as wikitable:
ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww |
ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww |
ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww |
ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww |
ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww |
ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww |
ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww |
ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww |
ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww |
ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww |
ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww |
ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww |
ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww | ww |
This is a naive implementation that does not use any optimization. Find the explanation at [[1]]. Computing the Ackermann function for (4,1) is possible, but takes quite a while because the stack grows very fast to large dimensions.
Example output:
? 3 ? 5 253
Pike
int main(){
write(ackermann(3,4) + "\n");
}
int ackermann(int m, int n){
if(m == 0){
return n + 1;
} else if(n == 0){
return ackermann(m-1, 1);
} else {
return ackermann(m-1, ackermann(m, n-1));
}
}
PL/I
Ackerman: procedure (m, n) returns (fixed (30)) recursive;
declare (m, n) fixed (30);
if m = 0 then return (n+1);
else if m > 0 & n = 0 then return (Ackerman(m-1, 1));
else if m > 0 & n > 0 then return (Ackerman(m-1, Ackerman(m, n-1)));
return (0);
end Ackerman;
PL/SQL
DECLARE
FUNCTION ackermann(pi_m IN NUMBER,
pi_n IN NUMBER) RETURN NUMBER IS
BEGIN
IF pi_m = 0 THEN
RETURN pi_n + 1;
ELSIF pi_n = 0 THEN
RETURN ackermann(pi_m - 1, 1);
ELSE
RETURN ackermann(pi_m - 1, ackermann(pi_m, pi_n - 1));
END IF;
END ackermann;
BEGIN
FOR n IN 0 .. 6 LOOP
FOR m IN 0 .. 3 LOOP
dbms_output.put_line('A(' || m || ',' || n || ') = ' || ackermann(m, n));
END LOOP;
END LOOP;
END;
- Output:
A(0,0) = 1 A(1,0) = 2 A(2,0) = 3 A(3,0) = 5 A(0,1) = 2 A(1,1) = 3 A(2,1) = 5 A(3,1) = 13 A(0,2) = 3 A(1,2) = 4 A(2,2) = 7 A(3,2) = 29 A(0,3) = 4 A(1,3) = 5 A(2,3) = 9 A(3,3) = 61 A(0,4) = 5 A(1,4) = 6 A(2,4) = 11 A(3,4) = 125 A(0,5) = 6 A(1,5) = 7 A(2,5) = 13 A(3,5) = 253 A(0,6) = 7 A(1,6) = 8 A(2,6) = 15 A(3,6) = 509
PostScript
/ackermann{
/n exch def
/m exch def %PostScript takes arguments in the reverse order as specified in the function definition
m 0 eq{
n 1 add
}if
m 0 gt n 0 eq and
{
m 1 sub 1 ackermann
}if
m 0 gt n 0 gt and{
m 1 sub m n 1 sub ackermann ackermann
}if
}def
/A {
[/.m /.n] let
{
{.m 0 eq} {.n succ} is?
{.m 0 gt .n 0 eq and} {.m pred 1 A} is?
{.m 0 gt .n 0 gt and} {.m pred .m .n pred A A} is?
} cond
end}.
Potion
ack = (m, n):
if (m == 0): n + 1
. elsif (n == 0): ack(m - 1, 1)
. else: ack(m - 1, ack(m, n - 1)).
.
4 times(m):
7 times(n):
ack(m, n) print
" " print.
"\n" print.
PowerBASIC
FUNCTION PBMAIN () AS LONG
DIM m AS QUAD, n AS QUAD
m = ABS(VAL(INPUTBOX$("Enter a whole number.")))
n = ABS(VAL(INPUTBOX$("Enter another whole number.")))
MSGBOX STR$(Ackermann(m, n))
END FUNCTION
FUNCTION Ackermann (m AS QUAD, n AS QUAD) AS QUAD
IF 0 = m THEN
FUNCTION = n + 1
ELSEIF 0 = n THEN
FUNCTION = Ackermann(m - 1, 1)
ELSE ' m > 0; n > 0
FUNCTION = Ackermann(m - 1, Ackermann(m, n - 1))
END IF
END FUNCTION
PowerShell
function ackermann ([long] $m, [long] $n) {
if ($m -eq 0) {
return $n + 1
}
if ($n -eq 0) {
return (ackermann ($m - 1) 1)
}
return (ackermann ($m - 1) (ackermann $m ($n - 1)))
}
Building an example table (takes a while to compute, though, especially for the last three numbers; also it fails with the last line in Powershell v1 since the maximum recursion depth is only 100 there):
foreach ($m in 0..3) {
foreach ($n in 0..6) {
Write-Host -NoNewline ("{0,5}" -f (ackermann $m $n))
}
Write-Host
}
- Output:
1 2 3 4 5 6 7 2 3 4 5 6 7 8 3 5 7 9 11 13 15 5 13 29 61 125 253 509
A More "PowerShelly" Way
function Get-Ackermann ([int64]$m, [int64]$n)
{
if ($m -eq 0)
{
return $n + 1
}
if ($n -eq 0)
{
return Get-Ackermann ($m - 1) 1
}
return (Get-Ackermann ($m - 1) (Get-Ackermann $m ($n - 1)))
}
Save the result to an array (for possible future use?), then display it using the Format-Wide
cmdlet:
$ackermann = 0..3 | ForEach-Object {$m = $_; 0..6 | ForEach-Object {Get-Ackermann $m $_}}
$ackermann | Format-Wide {"{0,3}" -f $_} -Column 7 -Force
- Output:
1 2 3 4 5 6 7 2 3 4 5 6 7 8 3 5 7 9 11 13 15 5 13 29 61 125 253 509
Processing
int ackermann(int m, int n) {
if (m == 0)
return n + 1;
else if (m > 0 && n == 0)
return ackermann(m - 1, 1);
else
return ackermann( m - 1, ackermann(m, n - 1) );
}
// Call function to produce output:
// the first 4x7 Ackermann numbers
void setup() {
for (int m=0; m<4; m++) {
for (int n=0; n<7; n++) {
print(ackermann(m, n), " ");
}
println();
}
}
- Output:
1 2 3 4 5 6 7 2 3 4 5 6 7 8 3 5 7 9 11 13 15 5 13 29 61 125 253 509
Processing Python mode
Python is not very adequate for deep recursion, so even setting sys.setrecursionlimit(1000000000) if m = 5 it throws 'maximum recursion depth exceeded'
from __future__ import print_function
def setup():
for m in range(4):
for n in range(7):
print("{} ".format(ackermann(m, n)), end = "")
print()
# print('finished')
def ackermann(m, n):
if m == 0:
return n + 1
elif m > 0 and n == 0:
return ackermann(m - 1, 1)
else:
return ackermann(m - 1, ackermann(m, n - 1))
Processing.R
Processing.R may exceed its stack depth at ~n==6 and returns null.
setup <- function() {
for (m in 0:3) {
for (n in 0:4) {
stdout$print(paste(ackermann(m, n), " "))
}
stdout$println("")
}
}
ackermann <- function(m, n) {
if ( m == 0 ) {
return(n+1)
} else if ( n == 0 ) {
ackermann(m-1, 1)
} else {
ackermann(m-1, ackermann(m, n-1))
}
}
- Output:
1 2 3 4 5 2 3 4 5 6 3 5 7 9 11 5 13 29 61 125
Prolog
:- table ack/3. % memoization reduces the execution time of ack(4,1,X) from several
% minutes to about one second on a typical desktop computer.
ack(0, N, Ans) :- Ans is N+1.
ack(M, 0, Ans) :- M>0, X is M-1, ack(X, 1, Ans).
ack(M, N, Ans) :- M>0, N>0, X is M-1, Y is N-1, ack(M, Y, Ans2), ack(X, Ans2, Ans).
"Pure" Prolog Version (Uses Peano arithmetic instead of is/2):
ack(0,N,s(N)).
ack(s(M),0,P):- ack(M,s(0),P).
ack(s(M),s(N),P):- ack(s(M),N,S), ack(M,S,P).
% Peano's first axiom in Prolog is that s(0) AND s(s(N)):- s(N)
% Thanks to this we don't need explicit N > 0 checks.
% Nor explicit arithmetic operations like X is M-1.
% Recursion and unification naturally decrement s(N) to N.
% But: Prolog clauses are relations and cannot be replaced by their result, like functions.
% Because of this we do need an extra argument to hold the output of the function.
% And we also need an additional call to the function in the last clause.
% Example input/output:
% ?- ack(s(0),s(s(0)),P).
% P = s(s(s(s(0)))) ;
% false.
Pure
A 0 n = n+1;
A m 0 = A (m-1) 1 if m > 0;
A m n = A (m-1) (A m (n-1)) if m > 0 && n > 0;
Pure Data
#N canvas 741 265 450 436 10;
#X obj 83 111 t b l;
#X obj 115 163 route 0;
#X obj 115 185 + 1;
#X obj 83 380 f;
#X obj 161 186 swap;
#X obj 161 228 route 0;
#X obj 161 250 - 1;
#X obj 161 208 pack;
#X obj 115 314 t f f;
#X msg 161 272 \$1 1;
#X obj 115 142 t l;
#X obj 207 250 swap;
#X obj 273 271 - 1;
#X obj 207 272 t f f;
#X obj 207 298 - 1;
#X obj 207 360 pack;
#X obj 239 299 pack;
#X obj 83 77 inlet;
#X obj 83 402 outlet;
#X connect 0 0 3 0;
#X connect 0 1 10 0;
#X connect 1 0 2 0;
#X connect 1 1 4 0;
#X connect 2 0 8 0;
#X connect 3 0 18 0;
#X connect 4 0 7 0;
#X connect 4 1 7 1;
#X connect 5 0 6 0;
#X connect 5 1 11 0;
#X connect 6 0 9 0;
#X connect 7 0 5 0;
#X connect 8 0 3 1;
#X connect 8 1 15 1;
#X connect 9 0 10 0;
#X connect 10 0 1 0;
#X connect 11 0 13 0;
#X connect 11 1 12 0;
#X connect 12 0 16 1;
#X connect 13 0 14 0;
#X connect 13 1 16 0;
#X connect 14 0 15 0;
#X connect 15 0 10 0;
#X connect 16 0 10 0;
#X connect 17 0 0 0;
PureBasic
Procedure.q Ackermann(m, n)
If m = 0
ProcedureReturn n + 1
ElseIf n = 0
ProcedureReturn Ackermann(m - 1, 1)
Else
ProcedureReturn Ackermann(m - 1, Ackermann(m, n - 1))
EndIf
EndProcedure
Debug Ackermann(3,4)
Purity
data Iter = f => FoldNat <const $f One, $f>
data Ackermann = FoldNat <const Succ, Iter>
Python
Python: Explicitly recursive
def ack1(M, N):
return (N + 1) if M == 0 else (
ack1(M-1, 1) if N == 0 else ack1(M-1, ack1(M, N-1)))
Another version:
from functools import lru_cache
@lru_cache(None)
def ack2(M, N):
if M == 0:
return N + 1
elif N == 0:
return ack2(M - 1, 1)
else:
return ack2(M - 1, ack2(M, N - 1))
- Example of use:
>>> import sys
>>> sys.setrecursionlimit(3000)
>>> ack1(0,0)
1
>>> ack1(3,4)
125
>>> ack2(0,0)
1
>>> ack2(3,4)
125
From the Mathematica ack3 example:
def ack2(M, N):
return (N + 1) if M == 0 else (
(N + 2) if M == 1 else (
(2*N + 3) if M == 2 else (
(8*(2**N - 1) + 5) if M == 3 else (
ack2(M-1, 1) if N == 0 else ack2(M-1, ack2(M, N-1))))))
Results confirm those of Mathematica for ack(4,1) and ack(4,2)
Python: Without recursive function calls
The heading is more correct than saying the following is iterative as an explicit stack is used to replace explicit recursive function calls. I don't think this is what Comp. Sci. professors mean by iterative.
from collections import deque
def ack_ix(m, n):
"Paddy3118's iterative with optimisations on m"
stack = deque([])
stack.extend([m, n])
while len(stack) > 1:
n, m = stack.pop(), stack.pop()
if m == 0:
stack.append(n + 1)
elif m == 1:
stack.append(n + 2)
elif m == 2:
stack.append(2*n + 3)
elif m == 3:
stack.append(2**(n + 3) - 3)
elif n == 0:
stack.extend([m-1, 1])
else:
stack.extend([m-1, m, n-1])
return stack[0]
- Output:
(From an ipython shell)
In [26]: %time a_4_2 = ack_ix(4, 2) Wall time: 0 ns In [27]: # How big is the answer? In [28]: float(a_4_2) Traceback (most recent call last): File "<ipython-input-28-af4ad951eff8>", line 1, in <module> float(a_4_2) OverflowError: int too large to convert to float In [29]: # How many decimal digits in the answer? In [30]: len(str(a_4_2)) Out[30]: 19729
Quackery
forward is ackermann ( m n --> r )
[ over 0 = iff
[ nip 1 + ] done
dup 0 = iff
[ drop 1 - 1
ackermann ] done
over 1 - unrot 1 -
ackermann ackermann ] resolves ackermann ( m n --> r )
3 10 ackermann echo
Output:
8189
R
ackermann <- function(m, n) {
if ( m == 0 ) {
n+1
} else if ( n == 0 ) {
ackermann(m-1, 1)
} else {
ackermann(m-1, ackermann(m, n-1))
}
}
for ( i in 0:3 ) {
print(ackermann(i, 4))
}
Racket
#lang racket
(define (ackermann m n)
(cond [(zero? m) (add1 n)]
[(zero? n) (ackermann (sub1 m) 1)]
[else (ackermann (sub1 m) (ackermann m (sub1 n)))]))
Raku
(formerly Perl 6)
sub A(Int $m, Int $n) {
if $m == 0 { $n + 1 }
elsif $n == 0 { A($m - 1, 1) }
else { A($m - 1, A($m, $n - 1)) }
}
An implementation using multiple dispatch:
multi sub A(0, Int $n) { $n + 1 }
multi sub A(Int $m, 0 ) { A($m - 1, 1) }
multi sub A(Int $m, Int $n) { A($m - 1, A($m, $n - 1)) }
Note that in either case, Int is defined to be arbitrary precision in Raku.
Here's a caching version of that, written in the sigilless style, with liberal use of Unicode, and the extra optimizing terms to make A(4,2) possible:
proto A(Int \𝑚, Int \𝑛) { (state @)[𝑚][𝑛] //= {*} }
multi A(0, Int \𝑛) { 𝑛 + 1 }
multi A(1, Int \𝑛) { 𝑛 + 2 }
multi A(2, Int \𝑛) { 3 + 2 * 𝑛 }
multi A(3, Int \𝑛) { 5 + 8 * (2 ** 𝑛 - 1) }
multi A(Int \𝑚, 0 ) { A(𝑚 - 1, 1) }
multi A(Int \𝑚, Int \𝑛) { A(𝑚 - 1, A(𝑚, 𝑛 - 1)) }
# Testing:
say A(4,1);
say .chars, " digits starting with ", .substr(0,50), "..." given A(4,2);
- Output:
65533 19729 digits starting with 20035299304068464649790723515602557504478254755697...
REBOL
ackermann: func [m n] [ case [ m = 0 [n + 1] n = 0 [ackermann m - 1 1] true [ackermann m - 1 ackermann m n - 1] ] ]
Refal
$ENTRY Go {
= <Prout 'A(3,9) = ' <A 3 9>>;
};
A {
0 s.N = <+ s.N 1>;
s.M 0 = <A <- s.M 1> 1>;
s.M s.N = <A <- s.M 1> <A s.M <- s.N 1>>>;
};
- Output:
A(3,9) = 4093
ReScript
let _m = Sys.argv[2]
let _n = Sys.argv[3]
let m = int_of_string(_m)
let n = int_of_string(_n)
let rec a = (m, n) =>
switch (m, n) {
| (0, n) => (n+1)
| (m, 0) => a(m-1, 1)
| (m, n) => a(m-1, a(m, n-1))
}
Js.log("ackermann(" ++ _m ++ ", " ++ _n ++ ") = "
++ string_of_int(a(m, n)))
- Output:
$ bsc acker.res > acker.bs.js $ node acker.bs.js 2 3 ackermann(2, 3) = 9 $ node acker.bs.js 3 4 ackermann(3, 4) = 125
REXX
no optimization
/*REXX program calculates and displays some values for the Ackermann function. */
/*╔════════════════════════════════════════════════════════════════════════╗
║ Note: the Ackermann function (as implemented here) utilizes deep ║
║ recursive and is limited by the largest number that can have ║
║ "1" (unity) added to a number (successfully and accurately). ║
╚════════════════════════════════════════════════════════════════════════╝*/
high=24
do j=0 to 3; say
do k=0 to high % (max(1, j))
call tell_Ack j, k
end /*k*/
end /*j*/
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
tell_Ack: parse arg mm,nn; calls=0 /*display an echo message to terminal. */
#=right(nn,length(high))
say 'Ackermann('mm", "#')='right(ackermann(mm, nn), high),
left('', 12) 'calls='right(calls, high)
return
/*──────────────────────────────────────────────────────────────────────────────────────*/
ackermann: procedure expose calls /*compute value of Ackermann function. */
parse arg m,n; calls=calls+1
if m==0 then return n+1
if n==0 then return ackermann(m-1, 1)
return ackermann(m-1, ackermann(m, n-1) )
- output when using the internal default input:
Ackermann(0, 0)= 1 calls= 1 Ackermann(0, 1)= 2 calls= 1 Ackermann(0, 2)= 3 calls= 1 Ackermann(0, 3)= 4 calls= 1 Ackermann(0, 4)= 5 calls= 1 Ackermann(0, 5)= 6 calls= 1 Ackermann(0, 6)= 7 calls= 1 Ackermann(0, 7)= 8 calls= 1 Ackermann(0, 8)= 9 calls= 1 Ackermann(0, 9)= 10 calls= 1 Ackermann(0,10)= 11 calls= 1 Ackermann(0,11)= 12 calls= 1 Ackermann(0,12)= 13 calls= 1 Ackermann(0,13)= 14 calls= 1 Ackermann(0,14)= 15 calls= 1 Ackermann(0,15)= 16 calls= 1 Ackermann(0,16)= 17 calls= 1 Ackermann(0,17)= 18 calls= 1 Ackermann(0,18)= 19 calls= 1 Ackermann(0,19)= 20 calls= 1 Ackermann(0,20)= 21 calls= 1 Ackermann(0,21)= 22 calls= 1 Ackermann(0,22)= 23 calls= 1 Ackermann(0,23)= 24 calls= 1 Ackermann(0,24)= 25 calls= 1 Ackermann(1, 0)= 2 calls= 2 Ackermann(1, 1)= 3 calls= 4 Ackermann(1, 2)= 4 calls= 6 Ackermann(1, 3)= 5 calls= 8 Ackermann(1, 4)= 6 calls= 10 Ackermann(1, 5)= 7 calls= 12 Ackermann(1, 6)= 8 calls= 14 Ackermann(1, 7)= 9 calls= 16 Ackermann(1, 8)= 10 calls= 18 Ackermann(1, 9)= 11 calls= 20 Ackermann(1,10)= 12 calls= 22 Ackermann(1,11)= 13 calls= 24 Ackermann(1,12)= 14 calls= 26 Ackermann(1,13)= 15 calls= 28 Ackermann(1,14)= 16 calls= 30 Ackermann(1,15)= 17 calls= 32 Ackermann(1,16)= 18 calls= 34 Ackermann(1,17)= 19 calls= 36 Ackermann(1,18)= 20 calls= 38 Ackermann(1,19)= 21 calls= 40 Ackermann(1,20)= 22 calls= 42 Ackermann(1,21)= 23 calls= 44 Ackermann(1,22)= 24 calls= 46 Ackermann(1,23)= 25 calls= 48 Ackermann(1,24)= 26 calls= 50 Ackermann(2, 0)= 3 calls= 5 Ackermann(2, 1)= 5 calls= 14 Ackermann(2, 2)= 7 calls= 27 Ackermann(2, 3)= 9 calls= 44 Ackermann(2, 4)= 11 calls= 65 Ackermann(2, 5)= 13 calls= 90 Ackermann(2, 6)= 15 calls= 119 Ackermann(2, 7)= 17 calls= 152 Ackermann(2, 8)= 19 calls= 189 Ackermann(2, 9)= 21 calls= 230 Ackermann(2,10)= 23 calls= 275 Ackermann(2,11)= 25 calls= 324 Ackermann(2,12)= 27 calls= 377 Ackermann(3, 0)= 5 calls= 15 Ackermann(3, 1)= 13 calls= 106 Ackermann(3, 2)= 29 calls= 541 Ackermann(3, 3)= 61 calls= 2432 Ackermann(3, 4)= 125 calls= 10307 Ackermann(3, 5)= 253 calls= 42438 Ackermann(3, 6)= 509 calls= 172233 Ackermann(3, 7)= 1021 calls= 693964 Ackermann(3, 8)= 2045 calls= 2785999
This output is from Regina and takes about 4 seconds. Running under ooRexx, the last line displayed is 'Ackermann(3, 6)...' and then the program just stops. Looks like deep recursion is more limited in ooRexx.
optimized for m ≤ 2
/*REXX program calculates and displays some values for the Ackermann function. */
high=24
do j=0 to 3; say
do k=0 to high % (max(1, j))
call tell_Ack j, k
end /*k*/
end /*j*/
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
tell_Ack: parse arg mm,nn; calls=0 /*display an echo message to terminal. */
#=right(nn,length(high))
say 'Ackermann('mm", "#')='right(ackermann(mm, nn), high),
left('', 12) 'calls='right(calls, high)
return
/*──────────────────────────────────────────────────────────────────────────────────────*/
ackermann: procedure expose calls /*compute value of Ackermann function. */
parse arg m,n; calls=calls+1
if m==0 then return n + 1
if n==0 then return ackermann(m-1, 1)
if m==2 then return n + 3 + n
return ackermann(m-1, ackermann(m, n-1) )
- output when using the internal default input:
Ackermann(0, 0)= 1 calls= 1 Ackermann(0, 1)= 2 calls= 1 Ackermann(0, 2)= 3 calls= 1 Ackermann(0, 3)= 4 calls= 1 Ackermann(0, 4)= 5 calls= 1 Ackermann(0, 5)= 6 calls= 1 Ackermann(0, 6)= 7 calls= 1 Ackermann(0, 7)= 8 calls= 1 Ackermann(0, 8)= 9 calls= 1 Ackermann(0, 9)= 10 calls= 1 Ackermann(0,10)= 11 calls= 1 Ackermann(0,11)= 12 calls= 1 Ackermann(0,12)= 13 calls= 1 Ackermann(0,13)= 14 calls= 1 Ackermann(0,14)= 15 calls= 1 Ackermann(0,15)= 16 calls= 1 Ackermann(0,16)= 17 calls= 1 Ackermann(0,17)= 18 calls= 1 Ackermann(0,18)= 19 calls= 1 Ackermann(0,19)= 20 calls= 1 Ackermann(0,20)= 21 calls= 1 Ackermann(0,21)= 22 calls= 1 Ackermann(0,22)= 23 calls= 1 Ackermann(0,23)= 24 calls= 1 Ackermann(0,24)= 25 calls= 1 Ackermann(1, 0)= 2 calls= 2 Ackermann(1, 1)= 3 calls= 4 Ackermann(1, 2)= 4 calls= 6 Ackermann(1, 3)= 5 calls= 8 Ackermann(1, 4)= 6 calls= 10 Ackermann(1, 5)= 7 calls= 12 Ackermann(1, 6)= 8 calls= 14 Ackermann(1, 7)= 9 calls= 16 Ackermann(1, 8)= 10 calls= 18 Ackermann(1, 9)= 11 calls= 20 Ackermann(1,10)= 12 calls= 22 Ackermann(1,11)= 13 calls= 24 Ackermann(1,12)= 14 calls= 26 Ackermann(1,13)= 15 calls= 28 Ackermann(1,14)= 16 calls= 30 Ackermann(1,15)= 17 calls= 32 Ackermann(1,16)= 18 calls= 34 Ackermann(1,17)= 19 calls= 36 Ackermann(1,18)= 20 calls= 38 Ackermann(1,19)= 21 calls= 40 Ackermann(1,20)= 22 calls= 42 Ackermann(1,21)= 23 calls= 44 Ackermann(1,22)= 24 calls= 46 Ackermann(1,23)= 25 calls= 48 Ackermann(1,24)= 26 calls= 50 Ackermann(2, 0)= 3 calls= 5 Ackermann(2, 1)= 5 calls= 1 Ackermann(2, 2)= 7 calls= 1 Ackermann(2, 3)= 9 calls= 1 Ackermann(2, 4)= 11 calls= 1 Ackermann(2, 5)= 13 calls= 1 Ackermann(2, 6)= 15 calls= 1 Ackermann(2, 7)= 17 calls= 1 Ackermann(2, 8)= 19 calls= 1 Ackermann(2, 9)= 21 calls= 1 Ackermann(2,10)= 23 calls= 1 Ackermann(2,11)= 25 calls= 1 Ackermann(2,12)= 27 calls= 1 Ackermann(3, 0)= 5 calls= 2 Ackermann(3, 1)= 13 calls= 4 Ackermann(3, 2)= 29 calls= 6 Ackermann(3, 3)= 61 calls= 8 Ackermann(3, 4)= 125 calls= 10 Ackermann(3, 5)= 253 calls= 12 Ackermann(3, 6)= 509 calls= 14 Ackermann(3, 7)= 1021 calls= 16 Ackermann(3, 8)= 2045 calls= 18
optimized for m ≤ 4
This REXX version takes advantage that some of the lower numbers for the Ackermann function have direct formulas.
If the numeric digits 100 were to be increased to 20000, then the value of Ackermann(4,2)
(the last line of output) would be presented with the full 19,729 decimal digits.
/*REXX program calculates and displays some values for the Ackermann function. */
numeric digits 100 /*use up to 100 decimal digit integers.*/
/*╔═════════════════════════════════════════════════════════════╗
║ When REXX raises a number to an integer power (via the ** ║
║ operator, the power can be positive, zero, or negative). ║
║ Ackermann(5,1) is a bit impractical to calculate. ║
╚═════════════════════════════════════════════════════════════╝*/
high=24
do j=0 to 4; say
do k=0 to high % (max(1, j))
call tell_Ack j, k
if j==4 & k==2 then leave /*there's no sense in going overboard. */
end /*k*/
end /*j*/
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
tell_Ack: parse arg mm,nn; calls=0 /*display an echo message to terminal. */
#=right(nn,length(high))
say 'Ackermann('mm", "#')='right(ackermann(mm, nn), high),
left('', 12) 'calls='right(calls, high)
return
/*──────────────────────────────────────────────────────────────────────────────────────*/
ackermann: procedure expose calls /*compute value of Ackermann function. */
parse arg m,n; calls=calls+1
if m==0 then return n + 1
if m==1 then return n + 2
if m==2 then return n + 3 + n
if m==3 then return 2**(n+3) - 3
if m==4 then do; #=2 /* [↓] Ugh! ··· and still more ughs.*/
do (n+3)-1 /*This is where the heavy lifting is. */
#=2**#
end
return #-3
end
if n==0 then return ackermann(m-1, 1)
return ackermann(m-1, ackermann(m, n-1) )
Output note: none of the numbers shown below use recursion to compute.
- output when using the internal default input:
Ackermann(0, 0)= 1 calls= 1 Ackermann(0, 1)= 2 calls= 1 Ackermann(0, 2)= 3 calls= 1 Ackermann(0, 3)= 4 calls= 1 Ackermann(0, 4)= 5 calls= 1 Ackermann(0, 5)= 6 calls= 1 Ackermann(0, 6)= 7 calls= 1 Ackermann(0, 7)= 8 calls= 1 Ackermann(0, 8)= 9 calls= 1 Ackermann(0, 9)= 10 calls= 1 Ackermann(0,10)= 11 calls= 1 Ackermann(0,11)= 12 calls= 1 Ackermann(0,12)= 13 calls= 1 Ackermann(0,13)= 14 calls= 1 Ackermann(0,14)= 15 calls= 1 Ackermann(0,15)= 16 calls= 1 Ackermann(0,16)= 17 calls= 1 Ackermann(0,17)= 18 calls= 1 Ackermann(0,18)= 19 calls= 1 Ackermann(0,19)= 20 calls= 1 Ackermann(0,20)= 21 calls= 1 Ackermann(0,21)= 22 calls= 1 Ackermann(0,22)= 23 calls= 1 Ackermann(0,23)= 24 calls= 1 Ackermann(0,24)= 25 calls= 1 Ackermann(1, 0)= 2 calls= 1 Ackermann(1, 1)= 3 calls= 1 Ackermann(1, 2)= 4 calls= 1 Ackermann(1, 3)= 5 calls= 1 Ackermann(1, 4)= 6 calls= 1 Ackermann(1, 5)= 7 calls= 1 Ackermann(1, 6)= 8 calls= 1 Ackermann(1, 7)= 9 calls= 1 Ackermann(1, 8)= 10 calls= 1 Ackermann(1, 9)= 11 calls= 1 Ackermann(1,10)= 12 calls= 1 Ackermann(1,11)= 13 calls= 1 Ackermann(1,12)= 14 calls= 1 Ackermann(1,13)= 15 calls= 1 Ackermann(1,14)= 16 calls= 1 Ackermann(1,15)= 17 calls= 1 Ackermann(1,16)= 18 calls= 1 Ackermann(1,17)= 19 calls= 1 Ackermann(1,18)= 20 calls= 1 Ackermann(1,19)= 21 calls= 1 Ackermann(1,20)= 22 calls= 1 Ackermann(1,21)= 23 calls= 1 Ackermann(1,22)= 24 calls= 1 Ackermann(1,23)= 25 calls= 1 Ackermann(1,24)= 26 calls= 1 Ackermann(2, 0)= 3 calls= 1 Ackermann(2, 1)= 5 calls= 1 Ackermann(2, 2)= 7 calls= 1 Ackermann(2, 3)= 9 calls= 1 Ackermann(2, 4)= 11 calls= 1 Ackermann(2, 5)= 13 calls= 1 Ackermann(2, 6)= 15 calls= 1 Ackermann(2, 7)= 17 calls= 1 Ackermann(2, 8)= 19 calls= 1 Ackermann(2, 9)= 21 calls= 1 Ackermann(2,10)= 23 calls= 1 Ackermann(2,11)= 25 calls= 1 Ackermann(2,12)= 27 calls= 1 Ackermann(3, 0)= 5 calls= 1 Ackermann(3, 1)= 13 calls= 1 Ackermann(3, 2)= 29 calls= 1 Ackermann(3, 3)= 61 calls= 1 Ackermann(3, 4)= 125 calls= 1 Ackermann(3, 5)= 253 calls= 1 Ackermann(3, 6)= 509 calls= 1 Ackermann(3, 7)= 1021 calls= 1 Ackermann(3, 8)= 2045 calls= 1 Ackermann(4, 0)= 13 calls= 1 Ackermann(4, 1)= 65533 calls= 1 Ackermann(4, 2)=89506130880933368E+19728 calls= 1
The last value is correct in magnitude, but not in value (only last digits plus exponent). Some other entries and Wikipedia give 2.0035...E+19728.
But leaving out the formatting and running with 20000 digits, the last value is correct shown in its full 19728 digits.
By the way, this version does not illustrate recursion anymore, because all workable values are captured as special values. Ackermann(4,2) = 2^65536-3 (19768 digits) and Ackerman(4,3) = 2^(2^65536)-3, far beyond REXX' (and other languages) capabilities in expressing numbers.
Ring
for m = 0 to 3
for n = 0 to 4
see "Ackermann(" + m + ", " + n + ") = " + Ackermann(m, n) + nl
next
next
func Ackermann m, n
if m > 0
if n > 0
return Ackermann(m - 1, Ackermann(m, n - 1))
but n = 0
return Ackermann(m - 1, 1)
ok
but m = 0
if n >= 0
return n + 1
ok
ok
Raise("Incorrect Numerical input !!!")
- Output:
Ackermann(0, 0) = 1 Ackermann(0, 1) = 2 Ackermann(0, 2) = 3 Ackermann(0, 3) = 4 Ackermann(0, 4) = 5 Ackermann(1, 0) = 2 Ackermann(1, 1) = 3 Ackermann(1, 2) = 4 Ackermann(1, 3) = 5 Ackermann(1, 4) = 6 Ackermann(2, 0) = 3 Ackermann(2, 1) = 5 Ackermann(2, 2) = 7 Ackermann(2, 3) = 9 Ackermann(2, 4) = 11 Ackermann(3, 0) = 5 Ackermann(3, 1) = 13 Ackermann(3, 2) = 29 Ackermann(3, 3) = 61 Ackermann(3, 4) = 125
RISC-V Assembly
the basic recursive function, because memorization and other improvements would blow the clarity.
ackermann: #x: a1, y: a2, return: a0
beqz a1, npe #case m = 0
beqz a2, mme #case m > 0 & n = 0
addi sp, sp, -8 #case m > 0 & n > 0
sw ra, 4(sp)
sw a1, 0(sp)
addi a2, a2, -1
jal ackermann
lw a1, 0(sp)
addi a1, a1, -1
mv a2, a0
jal ackermann
lw t0, 4(sp)
addi sp, sp, 8
jr t0, 0
npe:
addi a0, a2, 1
jr ra, 0
mme:
addi sp, sp, -4
sw ra, 0(sp)
addi a1, a1, -1
li a2, 1
jal ackermann
lw t0, 0(sp)
addi sp, sp, 4
jr t0, 0
RPL
« CASE OVER NOT THEN NIP 1 + END DUP NOT THEN DROP 1 - 1 ACKER END OVER 1 - ROT ROT 1 - ACKER ACKER END » 'ACKER' STO
3 4 ACKER
- Output:
1: 125
Runs in 7 min 13 secs on a HP-50g. Speed could be increased by replacing every 1
by 1.
, which would force calculations to be made with floating-point numbers, but we would then lose the arbitrary precision.
Ruby
def ack(m, n)
if m == 0
n + 1
elsif n == 0
ack(m-1, 1)
else
ack(m-1, ack(m, n-1))
end
end
Example:
(0..3).each do |m|
puts (0..6).map { |n| ack(m, n) }.join(' ')
end
- Output:
1 2 3 4 5 6 7 2 3 4 5 6 7 8 3 5 7 9 11 13 15 5 13 29 61 125 253 509
Run BASIC
print ackermann(1, 2)
function ackermann(m, n)
if (m = 0) then ackermann = (n + 1)
if (m > 0) and (n = 0) then ackermann = ackermann((m - 1), 1)
if (m > 0) and (n > 0) then ackermann = ackermann((m - 1), ackermann(m, (n - 1)))
end function
Rust
fn ack(m: isize, n: isize) -> isize {
if m == 0 {
n + 1
} else if n == 0 {
ack(m - 1, 1)
} else {
ack(m - 1, ack(m, n - 1))
}
}
fn main() {
let a = ack(3, 4);
println!("{}", a); // 125
}
Or:
fn ack(m: u64, n: u64) -> u64 {
match (m, n) {
(0, n) => n + 1,
(m, 0) => ack(m - 1, 1),
(m, n) => ack(m - 1, ack(m, n - 1)),
}
}
Sather
class MAIN is
ackermann(m, n:INT):INT
pre m >= 0 and n >= 0
is
if m = 0 then return n + 1; end;
if n = 0 then return ackermann(m-1, 1); end;
return ackermann(m-1, ackermann(m, n-1));
end;
main is
n, m :INT;
loop n := 0.upto!(6);
loop m := 0.upto!(3);
#OUT + "A(" + m + ", " + n + ") = " + ackermann(m, n) + "\n";
end;
end;
end;
end;
Instead of INT
, the class INTI
could be used, even though we need to use a workaround since in the GNU Sather v1.2.3 compiler the INTI literals are not implemented yet.
class MAIN is
ackermann(m, n:INTI):INTI is
zero ::= 0.inti; -- to avoid type conversion each time
one ::= 1.inti;
if m = zero then return n + one; end;
if n = zero then return ackermann(m-one, one); end;
return ackermann(m-one, ackermann(m, n-one));
end;
main is
n, m :INT;
loop n := 0.upto!(6);
loop m := 0.upto!(3);
#OUT + "A(" + m + ", " + n + ") = " + ackermann(m.inti, n.inti) + "\n";
end;
end;
end;
end;
Scala
def ack(m: BigInt, n: BigInt): BigInt = {
if (m==0) n+1
else if (n==0) ack(m-1, 1)
else ack(m-1, ack(m, n-1))
}
- Example:
scala> for ( m <- 0 to 3; n <- 0 to 6 ) yield ack(m,n) res0: Seq.Projection[BigInt] = RangeG(1, 2, 3, 4, 5, 6, 7, 2, 3, 4, 5, 6, 7, 8, 3, 5, 7, 9, 11, 13, 15, 5, 13, 29, 61, 125, 253, 509)
Memoized version using a mutable hash map:
val ackMap = new mutable.HashMap[(BigInt,BigInt),BigInt]
def ackMemo(m: BigInt, n: BigInt): BigInt = {
ackMap.getOrElseUpdate((m,n), ack(m,n))
}
Scheme
(define (A m n)
(cond
((= m 0) (+ n 1))
((= n 0) (A (- m 1) 1))
(else (A (- m 1) (A m (- n 1))))))
An improved solution that uses a lazy data structure, streams, and defines Knuth up-arrows to calculate iterative exponentiation:
(define (A m n)
(letrec ((A-stream
(cons-stream
(ints-from 1) ;; m = 0
(cons-stream
(ints-from 2) ;; m = 1
(cons-stream
;; m = 2
(stream-map (lambda (n)
(1+ (* 2 (1+ n))))
(ints-from 0))
(cons-stream
;; m = 3
(stream-map (lambda (n)
(- (knuth-up-arrow 2 (- m 2) (+ n 3)) 3))
(ints-from 0))
;; m = 4...
(stream-tail A-stream 3)))))))
(stream-ref (stream-ref A-stream m) n)))
(define (ints-from n)
(letrec ((ints-rec (cons-stream n (stream-map 1+ ints-rec))))
ints-rec))
(define (knuth-up-arrow a n b)
(let loop ((n n) (b b))
(cond ((= b 0) 1)
((= n 1) (expt a b))
(else (loop (-1+ n) (loop n (-1+ b)))))))
Scilab
clear
function acker=ackermann(m,n)
global calls
calls=calls+1
if m==0 then acker=n+1
else
if n==0 then acker=ackermann(m-1,1)
else acker=ackermann(m-1,ackermann(m,n-1))
end
end
endfunction
function printacker(m,n)
global calls
calls=0
printf('ackermann(%d,%d)=',m,n)
printf('%d calls=%d\n',ackermann(m,n),calls)
endfunction
maxi=3; maxj=6
for i=0:maxi
for j=0:maxj
printacker(i,j)
end
end
- Output:
ackermann(0,0)=1 calls=1 ackermann(0,1)=2 calls=1 ackermann(0,2)=3 calls=1 ackermann(0,3)=4 calls=1 ackermann(0,4)=5 calls=1 ackermann(0,5)=6 calls=1 ackermann(0,6)=7 calls=1 ackermann(1,0)=2 calls=2 ackermann(1,1)=3 calls=4 ackermann(1,2)=4 calls=6 ackermann(1,3)=5 calls=8 ackermann(1,4)=6 calls=10 ackermann(1,5)=7 calls=12 ackermann(1,6)=8 calls=14 ackermann(2,0)=3 calls=5 ackermann(2,1)=5 calls=14 ackermann(2,2)=7 calls=27 ackermann(2,3)=9 calls=44 ackermann(2,4)=11 calls=65 ackermann(2,5)=13 calls=90 ackermann(2,6)=15 calls=119 ackermann(3,0)=5 calls=15 ackermann(3,1)=13 calls=106 ackermann(3,2)=29 calls=541 ackermann(3,3)=61 calls=2432 ackermann(3,4)=125 calls=10307 ackermann(3,5)=253 calls=42438 ackermann(3,6)=509 calls=172233
Seed7
Basic version
const func integer: ackermann (in integer: m, in integer: n) is func
result
var integer: result is 0;
begin
if m = 0 then
result := succ(n);
elsif n = 0 then
result := ackermann(pred(m), 1);
else
result := ackermann(pred(m), ackermann(m, pred(n)));
end if;
end func;
Original source: [2]
Improved version
$ include "seed7_05.s7i";
include "bigint.s7i";
const func bigInteger: ackermann (in bigInteger: m, in bigInteger: n) is func
result
var bigInteger: ackermann is 0_;
begin
case m of
when {0_}: ackermann := succ(n);
when {1_}: ackermann := n + 2_;
when {2_}: ackermann := 3_ + 2_ * n;
when {3_}: ackermann := 5_ + 8_ * pred(2_ ** ord(n));
otherwise:
if n = 0_ then
ackermann := ackermann(pred(m), 1_);
else
ackermann := ackermann(pred(m), ackermann(m, pred(n)));
end if;
end case;
end func;
const proc: main is func
local
var bigInteger: m is 0_;
var bigInteger: n is 0_;
var string: stri is "";
begin
for m range 0_ to 3_ do
for n range 0_ to 9_ do
writeln("A(" <& m <& ", " <& n <& ") = " <& ackermann(m, n));
end for;
end for;
writeln("A(4, 0) = " <& ackermann(4_, 0_));
writeln("A(4, 1) = " <& ackermann(4_, 1_));
stri := str(ackermann(4_, 2_));
writeln("A(4, 2) = (" <& length(stri) <& " digits)");
writeln(stri[1 len 80]);
writeln("...");
writeln(stri[length(stri) - 79 ..]);
end func;
Original source: [3]
- Output:
A(0, 0) = 1 A(0, 1) = 2 A(0, 2) = 3 A(0, 3) = 4 A(0, 4) = 5 A(0, 5) = 6 A(0, 6) = 7 A(0, 7) = 8 A(0, 8) = 9 A(0, 9) = 10 A(1, 0) = 2 A(1, 1) = 3 A(1, 2) = 4 A(1, 3) = 5 A(1, 4) = 6 A(1, 5) = 7 A(1, 6) = 8 A(1, 7) = 9 A(1, 8) = 10 A(1, 9) = 11 A(2, 0) = 3 A(2, 1) = 5 A(2, 2) = 7 A(2, 3) = 9 A(2, 4) = 11 A(2, 5) = 13 A(2, 6) = 15 A(2, 7) = 17 A(2, 8) = 19 A(2, 9) = 21 A(3, 0) = 5 A(3, 1) = 13 A(3, 2) = 29 A(3, 3) = 61 A(3, 4) = 125 A(3, 5) = 253 A(3, 6) = 509 A(3, 7) = 1021 A(3, 8) = 2045 A(3, 9) = 4093 A(4, 0) = 13 A(4, 1) = 65533 A(4, 2) = (19729 digits) 20035299304068464649790723515602557504478254755697514192650169737108940595563114 ... 84717124577965048175856395072895337539755822087777506072339445587895905719156733
SETL
program ackermann;
(for m in [0..3])
print(+/ [rpad('' + ack(m, n), 4): n in [0..6]]);
end;
proc ack(m, n);
return {[0,n+1]}(m) ? ack(m-1, {[0,1]}(n) ? ack(m, n-1));
end proc;
end program;
Shen
(define ack
0 N -> (+ N 1)
M 0 -> (ack (- M 1) 1)
M N -> (ack (- M 1)
(ack M (- N 1))))
Sidef
func A(m, n) {
m == 0 ? (n + 1)
: (n == 0 ? (A(m - 1, 1))
: (A(m - 1, A(m, n - 1))));
}
Alternatively, using multiple dispatch:
func A((0), n) { n + 1 }
func A(m, (0)) { A(m - 1, 1) }
func A(m, n) { A(m-1, A(m, n-1)) }
Calling the function:
say A(3, 2); # prints: 29
Simula
as modified by R. Péter and R. Robinson:
BEGIN
INTEGER procedure
Ackermann(g, p); SHORT INTEGER g, p;
Ackermann:= IF g = 0 THEN p+1
ELSE Ackermann(g-1, IF p = 0 THEN 1
ELSE Ackermann(g, p-1));
INTEGER g, p;
FOR p := 0 STEP 3 UNTIL 13 DO BEGIN
g := 4 - p/3;
outtext("Ackermann("); outint(g, 0);
outchar(','); outint(p, 2); outtext(") = ");
outint(Ackermann(g, p), 0); outimage
END
END
- Output:
Ackermann(4, 0) = 13 Ackermann(3, 3) = 61 Ackermann(2, 6) = 15 Ackermann(1, 9) = 11 Ackermann(0,12) = 13
Slate
m@(Integer traits) ackermann: n@(Integer traits)
[
m isZero
ifTrue: [n + 1]
ifFalse:
[n isZero
ifTrue: [m - 1 ackermann: n]
ifFalse: [m - 1 ackermann: (m ackermann: n - 1)]]
].
Smalltalk
|ackermann|
ackermann := [ :n :m |
(n = 0) ifTrue: [ (m + 1) ]
ifFalse: [
(m = 0) ifTrue: [ ackermann value: (n-1) value: 1 ]
ifFalse: [
ackermann value: (n-1)
value: ( ackermann value: n
value: (m-1) )
]
]
].
(ackermann value: 0 value: 0) displayNl.
(ackermann value: 3 value: 4) displayNl.
SmileBASIC
DEF ACK(M,N)
IF M==0 THEN
RETURN N+1
ELSEIF M>0 AND N==0 THEN
RETURN ACK(M-1,1)
ELSE
RETURN ACK(M-1,ACK(M,N-1))
ENDIF
END
SNOBOL4
Both Snobol4+ and CSnobol stack overflow, at ack(3,3) and ack(3,4), respectively.
define('ack(m,n)') :(ack_end)
ack ack = eq(m,0) n + 1 :s(return)
ack = eq(n,0) ack(m - 1,1) :s(return)
ack = ack(m - 1,ack(m,n - 1)) :(return)
ack_end
* # Test and display ack(0,0) .. ack(3,6)
L1 str = str ack(m,n) ' '
n = lt(n,6) n + 1 :s(L1)
output = str; str = ''
n = 0; m = lt(m,3) m + 1 :s(L1)
end
- Output:
1 2 3 4 5 6 7 2 3 4 5 6 7 8 3 5 7 9 11 13 15 5 13 29 61 125 253 509
SNUSP
/==!/==atoi=@@@-@-----#
| | Ackermann function
| | /=========\!==\!====\ recursion:
$,@/>,@/==ack=!\?\<+# | | | A(0,j) -> j+1
j i \<?\+>-@/# | | A(i,0) -> A(i-1,1)
\@\>@\->@/@\<-@/# A(i,j) -> A(i-1,A(i,j-1))
| | |
# # | | | /+<<<-\
/-<<+>>\!=/ \=====|==!/========?\>>>=?/<<#
? ? | \<<<+>+>>-/
\>>+<<-/!==========/
# #
One could employ tail recursion elimination by replacing "@/#" with "/" in two places above.
SPAD
NNI ==> NonNegativeInteger
A:(NNI,NNI) -> NNI
A(m,n) ==
m=0 => n+1
m>0 and n=0 => A(m-1,1)
m>0 and n>0 => A(m-1,A(m,n-1))
-- Example
matrix [[A(i,j) for i in 0..3] for j in 0..3]
- Output:
+1 2 3 5 + | | |2 3 5 13| (1) | | |3 4 7 29| | | +4 5 9 61+ Type: Matrix(NonNegativeInteger)
SQL PL
version 9.7 or higher.
With SQL PL:
--#SET TERMINATOR @
SET SERVEROUTPUT ON@
CREATE OR REPLACE FUNCTION ACKERMANN(
IN M SMALLINT,
IN N BIGINT
) RETURNS BIGINT
BEGIN
DECLARE RET BIGINT;
DECLARE STMT STATEMENT;
IF (M = 0) THEN
SET RET = N + 1;
ELSEIF (N = 0) THEN
PREPARE STMT FROM 'SET ? = ACKERMANN(? - 1, 1)';
EXECUTE STMT INTO RET USING M;
ELSE
PREPARE STMT FROM 'SET ? = ACKERMANN(? - 1, ACKERMANN(?, ? - 1))';
EXECUTE STMT INTO RET USING M, M, N;
END IF;
RETURN RET;
END @
BEGIN
DECLARE M SMALLINT DEFAULT 0;
DECLARE N SMALLINT DEFAULT 0;
DECLARE MAX_LEVELS CONDITION FOR SQLSTATE '54038';
DECLARE CONTINUE HANDLER FOR MAX_LEVELS BEGIN END;
WHILE (N <= 6) DO
WHILE (M <= 3) DO
CALL DBMS_OUTPUT.PUT_LINE('ACKERMANN(' || M || ', ' || N || ') = ' || ACKERMANN(M, N));
SET M = M + 1;
END WHILE;
SET M = 0;
SET N = N + 1;
END WHILE;
END @
Output:
db2 -td@ db2 => CREATE OR REPLACE FUNCTION ACKERMANN( ... db2 (cont.) => END @ DB20000I The SQL command completed successfully. db2 => BEGIN db2 (cont.) => END ... DB20000I The SQL command completed successfully. ACKERMANN(0, 0) = 1 ACKERMANN(1, 0) = 2 ACKERMANN(2, 0) = 3 ACKERMANN(3, 0) = 5 ACKERMANN(0, 1) = 2 ACKERMANN(1, 1) = 3 ACKERMANN(2, 1) = 5 ACKERMANN(3, 1) = 13 ACKERMANN(0, 2) = 3 ACKERMANN(1, 2) = 4 ACKERMANN(2, 2) = 7 ACKERMANN(3, 2) = 29 ACKERMANN(0, 3) = 4 ACKERMANN(1, 3) = 5 ACKERMANN(2, 3) = 9 ACKERMANN(3, 3) = 61 ACKERMANN(0, 4) = 5 ACKERMANN(1, 4) = 6 ACKERMANN(2, 4) = 11 ACKERMANN(0, 5) = 6 ACKERMANN(1, 5) = 7 ACKERMANN(2, 5) = 13 ACKERMANN(0, 6) = 7 ACKERMANN(1, 6) = 8 ACKERMANN(2, 6) = 15
The maximum levels of cascade calls in Db2 are 16, and in some cases when executing the Ackermann function, it arrives to this limit (SQL0724N). Thus, the code catches the exception and continues with the next try.
Standard ML
fun a (0, n) = n+1
| a (m, 0) = a (m-1, 1)
| a (m, n) = a (m-1, a (m, n-1))
Stata
mata
function ackermann(m,n) {
if (m==0) {
return(n+1)
} else if (n==0) {
return(ackermann(m-1,1))
} else {
return(ackermann(m-1,ackermann(m,n-1)))
}
}
for (i=0; i<=3; i++) printf("%f\n",ackermann(i,4))
5
6
11
125
end
Swift
func ackerman(m:Int, n:Int) -> Int {
if m == 0 {
return n+1
} else if n == 0 {
return ackerman(m-1, 1)
} else {
return ackerman(m-1, ackerman(m, n-1))
}
}
Tcl
Simple
proc ack {m n} {
if {$m == 0} {
expr {$n + 1}
} elseif {$n == 0} {
ack [expr {$m - 1}] 1
} else {
ack [expr {$m - 1}] [ack $m [expr {$n - 1}]]
}
}
With Tail Recursion
With Tcl 8.6, this version is preferred (though the language supports tailcall optimization, it does not apply it automatically in order to preserve stack frame semantics):
proc ack {m n} {
if {$m == 0} {
expr {$n + 1}
} elseif {$n == 0} {
tailcall ack [expr {$m - 1}] 1
} else {
tailcall ack [expr {$m - 1}] [ack $m [expr {$n - 1}]]
}
}
To Infinity… and Beyond!
If we want to explore the higher reaches of the world of Ackermann's function, we need techniques to really cut the amount of computation being done.
package require Tcl 8.6
# A memoization engine, from http://wiki.tcl.tk/18152
oo::class create cache {
filter Memoize
variable ValueCache
method Memoize args {
# Do not filter the core method implementations
if {[lindex [self target] 0] eq "::oo::object"} {
return [next {*}$args]
}
# Check if the value is already in the cache
set key [self target],$args
if {[info exist ValueCache($key)]} {
return $ValueCache($key)
}
# Compute value, insert into cache, and return it
return [set ValueCache($key) [next {*}$args]]
}
method flushCache {} {
unset ValueCache
# Skip the cacheing
return -level 2 ""
}
}
# Make an object, attach the cache engine to it, and define ack as a method
oo::object create cached
oo::objdefine cached {
mixin cache
method ack {m n} {
if {$m==0} {
expr {$n+1}
} elseif {$m==1} {
# From the Mathematica version
expr {$m+2}
} elseif {$m==2} {
# From the Mathematica version
expr {2*$n+3}
} elseif {$m==3} {
# From the Mathematica version
expr {8*(2**$n-1)+5}
} elseif {$n==0} {
tailcall my ack [expr {$m-1}] 1
} else {
tailcall my ack [expr {$m-1}] [my ack $m [expr {$n-1}]]
}
}
}
# Some small tweaks...
interp recursionlimit {} 100000
interp alias {} ack {} cacheable ack
But even with all this, you still run into problems calculating as that's kind-of large…
TI-83 BASIC
This program assumes the variables N and M are the arguments of the function, and that the list L1 is empty. It stores the result in the system variable ANS. (Program names can be no longer than 8 characters, so I had to truncate the function's name.)
PROGRAM:ACKERMAN
:If not(M
:Then
:N+1→N
:Return
:Else
:If not(N
:Then
:1→N
:M-1→M
:prgmACKERMAN
:Else
:N-1→N
:M→L1(1+dim(L1
:prgmACKERMAN
:Ans→N
:L1(dim(L1))-1→M
:dim(L1)-1→dim(L1
:prgmACKERMAN
:End
:End
Here is a handler function that makes the previous function easier to use. (You can name it whatever you want.)
PROGRAM:AHANDLER
:0→dim(L1
:Prompt M
:Prompt N
:prgmACKERMAN
:Disp Ans
TI-89 BASIC
Define A(m,n) = when(m=0, n+1, when(n=0, A(m-1,1), A(m-1, A(m, n-1))))
TorqueScript
function ackermann(%m,%n)
{
if(%m==0)
return %n+1;
if(%m>0&&%n==0)
return ackermann(%m-1,1);
if(%m>0&&%n>0)
return ackermann(%m-1,ackermann(%m,%n-1));
}
Transd
#lang transd
MainModule: {
Ack: Lambda<Int Int Int>(λ m Int() n Int()
(if (not m) (ret (+ n 1)))
(if (not n) (ret (exec Ack (- m 1) 1)))
(ret (exec Ack (- m 1) (exec Ack m (- n 1))))
),
_start: (λ (textout (exec Ack 3 1) "\n"
(exec Ack 3 2) "\n"
(exec Ack 3 3)))
}
- Output:
13 29 61
TSE SAL
// library: math: get: ackermann: recursive <description></description> <version>1.0.0.0.5</version> <version control></version control> (filenamemacro=getmaare.s) [kn, ri, tu, 27-12-2011 14:46:59]
INTEGER PROC FNMathGetAckermannRecursiveI( INTEGER mI, INTEGER nI )
IF ( mI == 0 )
RETURN( nI + 1 )
ENDIF
IF ( nI == 0 )
RETURN( FNMathGetAckermannRecursiveI( mI - 1, 1 ) )
ENDIF
RETURN( FNMathGetAckermannRecursiveI( mI - 1, FNMathGetAckermannRecursiveI( mI, nI - 1 ) ) )
END
PROC Main()
STRING s1[255] = "2"
STRING s2[255] = "3"
IF ( NOT ( Ask( "math: get: ackermann: recursive: m = ", s1, _EDIT_HISTORY_ ) ) AND ( Length( s1 ) > 0 ) ) RETURN() ENDIF
IF ( NOT ( Ask( "math: get: ackermann: recursive: n = ", s2, _EDIT_HISTORY_ ) ) AND ( Length( s2 ) > 0 ) ) RETURN() ENDIF
Message( FNMathGetAckermannRecursiveI( Val( s1 ), Val( s2 ) ) ) // gives e.g. 9
END
TXR
with memoization.
(defmacro defmemofun (name (. args) . body)
(let ((hash (gensym "hash-"))
(argl (gensym "args-"))
(hent (gensym "hent-"))
(uniq (copy-str "uniq")))
^(let ((,hash (hash :equal-based)))
(defun ,name (,*args)
(let* ((,argl (list ,*args))
(,hent (inhash ,hash ,argl ,uniq)))
(if (eq (cdr ,hent) ,uniq)
(set (cdr ,hent) (block ,name (progn ,*body)))
(cdr ,hent)))))))
(defmemofun ack (m n)
(cond
((= m 0) (+ n 1))
((= n 0) (ack (- m 1) 1))
(t (ack (- m 1) (ack m (- n 1))))))
(each ((i (range 0 3)))
(each ((j (range 0 4)))
(format t "ack(~a, ~a) = ~a\n" i j (ack i j))))
- Output:
ack(0, 0) = 1 ack(0, 1) = 2 ack(0, 2) = 3 ack(0, 3) = 4 ack(0, 4) = 5 ack(1, 0) = 2 ack(1, 1) = 3 ack(1, 2) = 4 ack(1, 3) = 5 ack(1, 4) = 6 ack(2, 0) = 3 ack(2, 1) = 5 ack(2, 2) = 7 ack(2, 3) = 9 ack(2, 4) = 11 ack(3, 0) = 5 ack(3, 1) = 13 ack(3, 2) = 29 ack(3, 3) = 61 ack(3, 4) = 125
UNIX Shell
ack() {
local m=$1
local n=$2
if [ $m -eq 0 ]; then
echo -n $((n+1))
elif [ $n -eq 0 ]; then
ack $((m-1)) 1
else
ack $((m-1)) $(ack $m $((n-1)))
fi
}
Example:
for ((m=0;m<=3;m++)); do
for ((n=0;n<=6;n++)); do
ack $m $n
echo -n " "
done
echo
done
- Output:
1 2 3 4 5 6 7 2 3 4 5 6 7 8 3 5 7 9 11 13 15 5 13 29 61 125 253 509
Ursalang
let A = fn(m, n) {
if m == 0 {n + 1}
else if m > 0 and n == 0 {A(m - 1, 1)}
else {A(m - 1, A(m, n - 1))}
}
print(A(0, 0))
print(A(3, 4))
print(A(3, 1))
Ursala
Anonymous recursion is the usual way of doing things like this.
#import std
#import nat
ackermann =
~&al^?\successor@ar ~&ar?(
^R/~&f ^/predecessor@al ^|R/~& ^|/~& predecessor,
^|R/~& ~&\1+ predecessor@l)
test program for the first 4 by 7 numbers:
#cast %nLL
test = block7 ackermann*K0 iota~~/4 7
- Output:
< <1,2,3,4,5,6,7>, <2,3,4,5,6,7,8>, <3,5,7,9,11,13,15>, <5,13,29,61,125,253,509>>
V
[ack
[ [pop zero?] [popd succ]
[zero?] [pop pred 1 ack]
[true] [[dup pred swap] dip pred ack ack ]
] when].
using destructuring view
[ack
[ [pop zero?] [ [m n : [n succ]] view i]
[zero?] [ [m n : [m pred 1 ack]] view i]
[true] [ [m n : [m pred m n pred ack ack]] view i]
] when].
Vala
uint64 ackermann(uint64 m, uint64 n) {
if (m == 0) return n + 1;
if (n == 0) return ackermann(m - 1, 1);
return ackermann(m - 1, ackermann(m, n - 1));
}
void main () {
for (uint64 m = 0; m < 4; ++m) {
for (uint64 n = 0; n < 10; ++n) {
print(@"A($m,$n) = $(ackermann(m,n))\n");
}
}
}
- Output:
A(0,0) = 1 A(0,1) = 2 A(0,2) = 3 A(0,3) = 4 A(0,4) = 5 A(0,5) = 6 A(0,6) = 7 A(0,7) = 8 A(0,8) = 9 A(0,9) = 10 A(1,0) = 2 A(1,1) = 3 A(1,2) = 4 A(1,3) = 5 A(1,4) = 6 A(1,5) = 7 A(1,6) = 8 A(1,7) = 9 A(1,8) = 10 A(1,9) = 11 A(2,0) = 3 A(2,1) = 5 A(2,2) = 7 A(2,3) = 9 A(2,4) = 11 A(2,5) = 13 A(2,6) = 15 A(2,7) = 17 A(2,8) = 19 A(2,9) = 21 A(3,0) = 5 A(3,1) = 13 A(3,2) = 29 A(3,3) = 61 A(3,4) = 125 A(3,5) = 253 A(3,6) = 509 A(3,7) = 1021 A(3,8) = 2045 A(3,9) = 4093
VBA
Private Function Ackermann_function(m As Variant, n As Variant) As Variant
Dim result As Variant
Debug.Assert m >= 0
Debug.Assert n >= 0
If m = 0 Then
result = CDec(n + 1)
Else
If n = 0 Then
result = Ackermann_function(m - 1, 1)
Else
result = Ackermann_function(m - 1, Ackermann_function(m, n - 1))
End If
End If
Ackermann_function = CDec(result)
End Function
Public Sub main()
Debug.Print " n=",
For j = 0 To 7
Debug.Print j,
Next j
Debug.Print
For i = 0 To 3
Debug.Print "m=" & i,
For j = 0 To 7
Debug.Print Ackermann_function(i, j),
Next j
Debug.Print
Next i
End Sub
- Output:
n= 0 1 2 3 4 5 6 7 m=0 1 2 3 4 5 6 7 8 m=1 2 3 4 5 6 7 8 9 m=2 3 5 7 9 11 13 15 17 m=3 5 13 29 61 125 253 509 1021
VBScript
Based on BASIC version. Uncomment all the lines referring to depth
and see just how deep the recursion goes.
- Implementation
option explicit
'~ dim depth
function ack(m, n)
'~ wscript.stdout.write depth & " "
if m = 0 then
'~ depth = depth + 1
ack = n + 1
'~ depth = depth - 1
elseif m > 0 and n = 0 then
'~ depth = depth + 1
ack = ack(m - 1, 1)
'~ depth = depth - 1
'~ elseif m > 0 and n > 0 then
else
'~ depth = depth + 1
ack = ack(m - 1, ack(m, n - 1))
'~ depth = depth - 1
end if
end function
- Invocation
wscript.echo ack( 1, 10 )
'~ depth = 0
wscript.echo ack( 2, 1 )
'~ depth = 0
wscript.echo ack( 4, 4 )
- Output:
12 5 C:\foo\ackermann.vbs(16, 3) Microsoft VBScript runtime error: Out of stack space: 'ack'
Visual Basic
Option Explicit
Dim calls As Long
Sub main()
Const maxi = 4
Const maxj = 9
Dim i As Long, j As Long
For i = 0 To maxi
For j = 0 To maxj
Call print_acker(i, j)
Next j
Next i
End Sub 'main
Sub print_acker(m As Long, n As Long)
calls = 0
Debug.Print "ackermann("; m; ","; n; ")=";
Debug.Print ackermann(m, n), "calls="; calls
End Sub 'print_acker
Function ackermann(m As Long, n As Long) As Long
calls = calls + 1
If m = 0 Then
ackermann = n + 1
Else
If n = 0 Then
ackermann = ackermann(m - 1, 1)
Else
ackermann = ackermann(m - 1, ackermann(m, n - 1))
End If
End If
End Function 'ackermann
- Output:
ackermann( 0 , 0 )= 1 calls= 1 ackermann( 0 , 1 )= 2 calls= 1 ackermann( 0 , 2 )= 3 calls= 1 ackermann( 0 , 3 )= 4 calls= 1 ackermann( 0 , 4 )= 5 calls= 1 ackermann( 0 , 5 )= 6 calls= 1 ackermann( 0 , 6 )= 7 calls= 1 ackermann( 0 , 7 )= 8 calls= 1 ackermann( 0 , 8 )= 9 calls= 1 ackermann( 0 , 9 )= 10 calls= 1 ackermann( 1 , 0 )= 2 calls= 2 ackermann( 1 , 1 )= 3 calls= 4 ackermann( 1 , 2 )= 4 calls= 6 ackermann( 1 , 3 )= 5 calls= 8 ackermann( 1 , 4 )= 6 calls= 10 ackermann( 1 , 5 )= 7 calls= 12 ackermann( 1 , 6 )= 8 calls= 14 ackermann( 1 , 7 )= 9 calls= 16 ackermann( 1 , 8 )= 10 calls= 18 ackermann( 1 , 9 )= 11 calls= 20 ackermann( 2 , 0 )= 3 calls= 5 ackermann( 2 , 1 )= 5 calls= 14 ackermann( 2 , 2 )= 7 calls= 27 ackermann( 2 , 3 )= 9 calls= 44 ackermann( 2 , 4 )= 11 calls= 65 ackermann( 2 , 5 )= 13 calls= 90 ackermann( 2 , 6 )= 15 calls= 119 ackermann( 2 , 7 )= 17 calls= 152 ackermann( 2 , 8 )= 19 calls= 189 ackermann( 2 , 9 )= 21 calls= 230 ackermann( 3 , 0 )= 5 calls= 15 ackermann( 3 , 1 )= 13 calls= 106 ackermann( 3 , 2 )= 29 calls= 541 ackermann( 3 , 3 )= 61 calls= 2432 ackermann( 3 , 4 )= 125 calls= 10307 ackermann( 3 , 5 )= 253 calls= 42438 ackermann( 3 , 6 )= 509 calls= 172233 ackermann( 3 , 7 )= 1021 calls= 693964 ackermann( 3 , 8 )= 2045 calls= 2785999 ackermann( 3 , 9 )= 4093 calls= 11164370 ackermann( 4 , 0 )= 13 calls= 107 ackermann( 4 , 1 )= out of stack space
V (Vlang)
fn ackermann(m int, n int ) int {
if m == 0 {
return n + 1
}
else if n == 0 {
return ackermann(m - 1, 1)
}
return ackermann(m - 1, ackermann(m, n - 1) )
}
fn main() {
for m := 0; m <= 4; m++ {
for n := 0; n < ( 6 - m ); n++ {
println('Ackermann($m, $n) = ${ackermann(m, n)}')
}
}
}
- Output:
Ackermann(0, 0) = 1 Ackermann(0, 1) = 2 Ackermann(0, 2) = 3 Ackermann(0, 3) = 4 Ackermann(0, 4) = 5 Ackermann(0, 5) = 6 Ackermann(1, 0) = 2 Ackermann(1, 1) = 3 Ackermann(1, 2) = 4 Ackermann(1, 3) = 5 Ackermann(1, 4) = 6 Ackermann(2, 0) = 3 Ackermann(2, 1) = 5 Ackermann(2, 2) = 7 Ackermann(2, 3) = 9 Ackermann(3, 0) = 5 Ackermann(3, 1) = 13 Ackermann(3, 2) = 29 Ackermann(4, 0) = 13 Ackermann(4, 1) = 65533
Wart
def (ackermann m n)
(if m=0
n+1
n=0
(ackermann m-1 1)
:else
(ackermann m-1 (ackermann m n-1)))
WDTE
let memo a m n => true {
== m 0 => + n 1;
== n 0 => a (- m 1) 1;
true => a (- m 1) (a m (- n 1));
};
Wren
// To use recursion definition and declaration must be on separate lines
var Ackermann
Ackermann = Fn.new {|m, n|
if (m == 0) return n + 1
if (n == 0) return Ackermann.call(m - 1, 1)
return Ackermann.call(m - 1, Ackermann.call(m, n - 1))
}
var pairs = [ [1, 3], [2, 3], [3, 3], [1, 5], [2, 5], [3, 5] ]
for (pair in pairs) {
var p1 = pair[0]
var p2 = pair[1]
System.print("A[%(p1), %(p2)] = %(Ackermann.call(p1, p2))")
}
- Output:
A[1, 3] = 5 A[2, 3] = 9 A[3, 3] = 61 A[1, 5] = 7 A[2, 5] = 13 A[3, 5] = 253
X86 Assembly
section .text
global _main
_main:
mov eax, 3 ;m
mov ebx, 4 ;n
call ack ;returns number in ebx
ret
ack:
cmp eax, 0
je M0 ;if M == 0
cmp ebx, 0
je N0 ;if N == 0
dec ebx ;else N-1
push eax ;save M
call ack1 ;ack(m,n) -> returned in ebx so no further instructions needed
pop eax ;restore M
dec eax ;M - 1
call ack1 ;return ack(m-1,ack(m,n-1))
ret
M0:
inc ebx ;return n + 1
ret
N0:
dec eax
inc ebx ;ebx always 0: inc -> ebx = 1
call ack1 ;return ack(M-1,1)
ret
XLISP
(defun ackermann (m n)
(cond
((= m 0) (+ n 1))
((= n 0) (ackermann (- m 1) 1))
(t (ackermann (- m 1) (ackermann m (- n 1))))))
Test it:
(print (ackermann 3 9))
Output (after a very perceptible pause):
4093
That worked well. Test it again:
(print (ackermann 4 1))
Output (after another pause):
Abort: control stack overflow happened in: #<Code ACKERMANN>
XPL0
include c:\cxpl\codes;
func Ackermann(M, N);
int M, N;
[if M=0 then return N+1;
if N=0 then return Ackermann(M-1, 1);
return Ackermann(M-1, Ackermann(M, N-1));
]; \Ackermann
int M, N;
[for M:= 0 to 3 do
[for N:= 0 to 7 do
[IntOut(0, Ackermann(M, N)); ChOut(0,9\tab\)];
CrLf(0);
];
]
Recursion overflows the stack if either M or N is extended by a single count.
- Output:
1 2 3 4 5 6 7 8 2 3 4 5 6 7 8 9 3 5 7 9 11 13 15 17 5 13 29 61 125 253 509 1021
XSLT
The following named template calculates the Ackermann function:
<xsl:template name="ackermann">
<xsl:param name="m"/>
<xsl:param name="n"/>
<xsl:choose>
<xsl:when test="$m = 0">
<xsl:value-of select="$n+1"/>
</xsl:when>
<xsl:when test="$n = 0">
<xsl:call-template name="ackermann">
<xsl:with-param name="m" select="$m - 1"/>
<xsl:with-param name="n" select="'1'"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="p">
<xsl:call-template name="ackermann">
<xsl:with-param name="m" select="$m"/>
<xsl:with-param name="n" select="$n - 1"/>
</xsl:call-template>
</xsl:variable>
<xsl:call-template name="ackermann">
<xsl:with-param name="m" select="$m - 1"/>
<xsl:with-param name="n" select="$p"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Here it is as part of a template
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="arguments">
<xsl:for-each select="args">
<div>
<xsl:value-of select="m"/>, <xsl:value-of select="n"/>:
<xsl:call-template name="ackermann">
<xsl:with-param name="m" select="m"/>
<xsl:with-param name="n" select="n"/>
</xsl:call-template>
</div>
</xsl:for-each>
</xsl:template>
<xsl:template name="ackermann">
<xsl:param name="m"/>
<xsl:param name="n"/>
<xsl:choose>
<xsl:when test="$m = 0">
<xsl:value-of select="$n+1"/>
</xsl:when>
<xsl:when test="$n = 0">
<xsl:call-template name="ackermann">
<xsl:with-param name="m" select="$m - 1"/>
<xsl:with-param name="n" select="'1'"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="p">
<xsl:call-template name="ackermann">
<xsl:with-param name="m" select="$m"/>
<xsl:with-param name="n" select="$n - 1"/>
</xsl:call-template>
</xsl:variable>
<xsl:call-template name="ackermann">
<xsl:with-param name="m" select="$m - 1"/>
<xsl:with-param name="n" select="$p"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Which will transform this input
<?xml version="1.0" ?>
<?xml-stylesheet type="text/xsl" href="ackermann.xslt"?>
<arguments>
<args>
<m>0</m>
<n>0</n>
</args>
<args>
<m>0</m>
<n>1</n>
</args>
<args>
<m>0</m>
<n>2</n>
</args>
<args>
<m>0</m>
<n>3</n>
</args>
<args>
<m>0</m>
<n>4</n>
</args>
<args>
<m>0</m>
<n>5</n>
</args>
<args>
<m>0</m>
<n>6</n>
</args>
<args>
<m>0</m>
<n>7</n>
</args>
<args>
<m>0</m>
<n>8</n>
</args>
<args>
<m>1</m>
<n>0</n>
</args>
<args>
<m>1</m>
<n>1</n>
</args>
<args>
<m>1</m>
<n>2</n>
</args>
<args>
<m>1</m>
<n>3</n>
</args>
<args>
<m>1</m>
<n>4</n>
</args>
<args>
<m>1</m>
<n>5</n>
</args>
<args>
<m>1</m>
<n>6</n>
</args>
<args>
<m>1</m>
<n>7</n>
</args>
<args>
<m>1</m>
<n>8</n>
</args>
<args>
<m>2</m>
<n>0</n>
</args>
<args>
<m>2</m>
<n>1</n>
</args>
<args>
<m>2</m>
<n>2</n>
</args>
<args>
<m>2</m>
<n>3</n>
</args>
<args>
<m>2</m>
<n>4</n>
</args>
<args>
<m>2</m>
<n>5</n>
</args>
<args>
<m>2</m>
<n>6</n>
</args>
<args>
<m>2</m>
<n>7</n>
</args>
<args>
<m>2</m>
<n>8</n>
</args>
<args>
<m>3</m>
<n>0</n>
</args>
<args>
<m>3</m>
<n>1</n>
</args>
<args>
<m>3</m>
<n>2</n>
</args>
<args>
<m>3</m>
<n>3</n>
</args>
<args>
<m>3</m>
<n>4</n>
</args>
<args>
<m>3</m>
<n>5</n>
</args>
<args>
<m>3</m>
<n>6</n>
</args>
<args>
<m>3</m>
<n>7</n>
</args>
<args>
<m>3</m>
<n>8</n>
</args>
</arguments>
into this output
0, 0: 1 0, 1: 2 0, 2: 3 0, 3: 4 0, 4: 5 0, 5: 6 0, 6: 7 0, 7: 8 0, 8: 9 1, 0: 2 1, 1: 3 1, 2: 4 1, 3: 5 1, 4: 6 1, 5: 7 1, 6: 8 1, 7: 9 1, 8: 10 2, 0: 3 2, 1: 5 2, 2: 7 2, 3: 9 2, 4: 11 2, 5: 13 2, 6: 15 2, 7: 17 2, 8: 19 3, 0: 5 3, 1: 13 3, 2: 29 3, 3: 61 3, 4: 125 3, 5: 253 3, 6: 509 3, 7: 1021 3, 8: 2045
Yabasic
sub ack(M,N)
if M = 0 return N + 1
if N = 0 return ack(M-1,1)
return ack(M-1,ack(M, N-1))
end sub
print ack(3, 4)
What smart code can get. Fast as lightning!
sub ack(m, n)
if m=0 then
return n+1
elsif m=1 then
return n+2
elsif m=2 then
return 2*n+3
elsif m=3 then
return 2^(n+3)-3
elsif m>0 and n=0 then
return ack(m-1,1)
else
return ack(m-1,ack(m,n-1))
end if
end sub
sub Ackermann()
local i, j
for i=0 to 3
for j=0 to 10
print ack(i,j) using "#####";
next
print
next
print "ack(4,1) ";: print ack(4,1) using "#####"
end sub
Ackermann()
Yorick
func ack(m, n) {
if(m == 0)
return n + 1;
else if(n == 0)
return ack(m - 1, 1);
else
return ack(m - 1, ack(m, n - 1));
}
Example invocation:
for(m = 0; m <= 3; m++) {
for(n = 0; n <= 6; n++)
write, format="%d ", ack(m, n);
write, "";
}
- Output:
1 2 3 4 5 6 7 2 3 4 5 6 7 8 3 5 7 9 11 13 15 5 13 29 61 125 253 509
Z80 Assembly
This function does 16-bit math. Sjasmplus syntax, CP/M executable.
OPT --syntax=abf : OUTPUT "ackerman.com"
ORG $100
jr demo_start
;--------------------------------------------------------------------------------------------------------------------
; entry: ackermann_fn
; input: bc = m, hl = n
; output: hl = A(m,n) (16bit only)
ackermann_fn.inc_n:
inc hl
ackermann_fn:
inc hl
ld a,c
or b
ret z ; m == 0 -> return n+1
; m > 0 case ; bc = m, hl = n+1
dec bc
dec hl ; m-1, n restored
ld a,l
or h
jr z,.inc_n ; n == 0 -> return A(m-1, 1)
; m > 0, n > 0 ; bc = m-1, hl = n
push bc
inc bc
dec hl
call ackermann_fn ; n = A(m, n-1)
pop bc
jp ackermann_fn ; return A(m-1,A(m, n-1))
;--------------------------------------------------------------------------------------------------------------------
; helper functions for demo printing 4x9 table
print_str:
push bc
push hl
ld c,9
.call_cpm:
call 5
pop hl
pop bc
ret
print_hl:
ld b,' '
ld e,b
call print_char
ld de,-10000
call extract_digit
ld de,-1000
call extract_digit
ld de,-100
call extract_digit
ld de,-10
call extract_digit
ld a,l
print_digit:
ld b,'0'
add a,b
ld e,a
print_char:
push bc
push hl
ld c,2
jr print_str.call_cpm
extract_digit:
ld a,-1
.digit_loop:
inc a
add hl,de
jr c,.digit_loop
sbc hl,de
or a
jr nz,print_digit
ld e,b
jr print_char
;--------------------------------------------------------------------------------------------------------------------
demo_start: ; do m: [0,4) cross n: [0,9) table
ld bc,0
.loop_m:
ld hl,0 ; bc = m, hl = n = 0
ld de,txt_m_is
call print_str
ld a,c
or '0'
ld e,a
call print_char
ld e,':'
call print_char
.loop_n:
push bc
push hl
call ackermann_fn
call print_hl
pop hl
pop bc
inc hl
ld a,l
cp 9
jr c,.loop_n
ld de,crlf
call print_str
inc bc
ld a,c
cp 4
jr c,.loop_m
rst 0 ; return to CP/M
txt_m_is: db "m=$"
crlf: db 10,13,'$'
- Output:
m=0: 1 2 3 4 5 6 7 8 9 m=1: 2 3 4 5 6 7 8 9 10 m=2: 3 5 7 9 11 13 15 17 19 m=3: 5 13 29 61 125 253 509 1021 2045
ZED
Source -> http://ideone.com/53FzPA Compiled -> http://ideone.com/OlS7zL
(A) m n
comment:
(=) m 0
(add1) n
(A) m n
comment:
(=) n 0
(A) (sub1) m 1
(A) m n
comment:
#true
(A) (sub1) m (A) m (sub1) n
(add1) n
comment:
#true
(003) "+" n 1
(sub1) n
comment:
#true
(003) "-" n 1
(=) n1 n2
comment:
#true
(003) "=" n1 n2
Zig
pub fn ack(m: u64, n: u64) u64 {
if (m == 0) return n + 1;
if (n == 0) return ack(m - 1, 1);
return ack(m - 1, ack(m, n - 1));
}
pub fn main() !void {
const stdout = @import("std").io.getStdOut().writer();
var m: u8 = 0;
while (m <= 3) : (m += 1) {
var n: u8 = 0;
while (n <= 8) : (n += 1)
try stdout.print("{d:>8}", .{ack(m, n)});
try stdout.print("\n", .{});
}
}
- Output:
1 2 3 4 5 6 7 8 9 2 3 4 5 6 7 8 9 10 3 5 7 9 11 13 15 17 19 5 13 29 61 125 253 509 1021 2045
ZX Spectrum Basic
10 DIM s(2000,3)
20 LET s(1,1)=3: REM M
30 LET s(1,2)=7: REM N
40 LET lev=1
50 GO SUB 100
60 PRINT "A(";s(1,1);",";s(1,2);") = ";s(1,3)
70 STOP
100 IF s(lev,1)=0 THEN LET s(lev,3)=s(lev,2)+1: RETURN
110 IF s(lev,2)=0 THEN LET lev=lev+1: LET s(lev,1)=s(lev-1,1)-1: LET s(lev,2)=1: GO SUB 100: LET s(lev-1,3)=s(lev,3): LET lev=lev-1: RETURN
120 LET lev=lev+1
130 LET s(lev,1)=s(lev-1,1)
140 LET s(lev,2)=s(lev-1,2)-1
150 GO SUB 100
160 LET s(lev,1)=s(lev-1,1)-1
170 LET s(lev,2)=s(lev,3)
180 GO SUB 100
190 LET s(lev-1,3)=s(lev,3)
200 LET lev=lev-1
210 RETURN
- Output:
A(3,7) = 1021
- Programming Tasks
- Recursion
- Memoization
- Classic CS problems and programs
- 11l
- 360 Assembly
- 68000 Assembly
- 8080 Assembly
- 8086 Assembly
- 8th
- AArch64 Assembly
- ABAP
- ABC
- Acornsoft Lisp
- Action!
- ActionScript
- Ada
- Agda
- Agda-stdlib v1.7
- ALGOL 60
- ALGOL 68
- ALGOL W
- APL
- AppleScript
- Argile
- ARM Assembly
- Arturo
- ATS
- AutoHotkey
- AutoIt
- AWK
- Babel
- BASIC
- Applesoft BASIC
- BASIC256
- BBC BASIC
- Chipmunk Basic
- True BASIC
- QuickBasic
- Batch File
- Bc
- BCPL
- Beeswax
- Befunge
- Binary Lambda Calculus
- BQN
- Bracmat
- Brat
- Bruijn
- C
- C sharp
- C++
- Chapel
- Clay
- CLIPS
- Clojure
- CLU
- COBOL
- CoffeeScript
- Comal
- Common Lisp
- Component Pascal
- Coq
- Crystal
- D
- Dart
- Dc
- Delphi
- Draco
- DWScript
- Dylan
- E
- EasyLang
- Egel
- Eiffel
- Ela
- Elena
- Elixir
- Emacs Lisp
- EMal
- Erlang
- ERRE
- Euler Math Toolbox
- Euphoria
- Ezhil
- F Sharp
- Factor
- Falcon
- FALSE
- Fantom
- FBSL
- Fermat
- Forth
- Fortran
- Free Pascal
- FreeBASIC
- FunL
- Futhark
- FutureBasic
- Fōrmulæ
- Gambas
- GAP
- Genyris
- GML
- Gnuplot
- Go
- Golfscript
- Groovy
- Hare
- Haskell
- Haxe
- Hoon
- Icon
- Unicon
- Icon Programming Library
- Idris
- Ioke
- J
- Java
- Arbitrary precision
- JavaScript
- Joy
- Jq
- Jsish
- Julia
- K
- Kdf9 Usercode
- Klingphix
- Klong
- Kotlin
- Lambdatalk
- Lasso
- LFE
- Liberty BASIC
- LiveCode
- Logo
- Logtalk
- LOLCODE
- Lua
- Lucid
- Luck
- M2000 Interpreter
- M4
- MACRO-11
- MAD
- Maple
- Mathcad
- Mathematica
- Wolfram Language
- MATLAB
- Maxima
- MAXScript
- Mercury
- Min
- MiniScript
- МК-61/52
- ML/I
- MLite
- Modula-2
- Modula-3
- MUMPS
- Neko
- Nemerle
- NetRexx
- NewLISP
- Nim
- Nit
- Oberon-2
- Objeck
- OCaml
- Octave
- Oforth
- Ol
- OOC
- OoRexx
- Order
- Oz
- PARI/GP
- Pascal
- PascalABC.NET
- Perl
- Phix
- Phix/mpfr
- Phixmonti
- PHP
- Picat
- PicoLisp
- Piet
- Pike
- PL/I
- PL/SQL
- PostScript
- Initlib
- Potion
- PowerBASIC
- PowerShell
- Processing
- Processing Python mode
- Processing.R
- Prolog
- Pure
- Pure Data
- PureBasic
- Purity
- Python
- Quackery
- R
- Racket
- Raku
- REBOL
- Refal
- ReScript
- REXX
- Ring
- RISC-V Assembly
- RPL
- Ruby
- Run BASIC
- Rust
- Sather
- Scala
- Scheme
- Scilab
- Seed7
- SETL
- Shen
- Sidef
- Simula
- Slate
- Smalltalk
- SmileBASIC
- SNOBOL4
- SNUSP
- SPAD
- SQL PL
- Standard ML
- Stata
- Swift
- Tcl
- TI-83 BASIC
- TI-89 BASIC
- TorqueScript
- Transd
- TSE SAL
- TXR
- UNIX Shell
- Ursalang
- Ursala
- V
- Vala
- VBA
- VBScript
- Visual Basic
- V (Vlang)
- Wart
- WDTE
- Wren
- X86 Assembly
- XLISP
- XPL0
- XSLT
- Yabasic
- Yorick
- Z80 Assembly
- ZED
- Zig
- ZX Spectrum Basic
- LaTeX/Omit
- Make/Omit
- PlainTeX/Omit
- Pages with too many expensive parser function calls