Fungsi Ackermann terkenal karena menjadi salah satu contoh paling sederhana dari total, fungsi yang dapat dihitung yang bukan rekursif primitif.
Kami akan menggunakan definisi A(m,n)
mengambil dua bilangan bulat tidak negatif di mana
A(0,n) = n+1
A(m,0) = A(m-1,1)
A(m,n) = A(m-1,A(m,n-1))
Anda dapat menerapkan
- fungsi bernama atau anonim mengambil dua bilangan bulat sebagai input, mengembalikan bilangan bulat, atau
- sebuah program mengambil dua bilangan bulat yang dipisahkan spasi atau baris baru pada STDIN, mencetak hasilnya ke STDOUT.
Anda tidak boleh menggunakan fungsi Ackermann atau fungsi hyperexponentiation dari perpustakaan, jika ada, tetapi Anda dapat menggunakan fungsi lain dari perpustakaan lain. Eksponen reguler diperbolehkan.
Fungsi Anda harus dapat menemukan nilai A(m,n)
untuk m ≤ 3 dan n ≤ 10 dalam waktu kurang dari satu menit. Setidaknya harus diakhiri secara teoritis pada input lain: diberi ruang stack tak terbatas, tipe Bigint asli, dan periode waktu yang lama secara sewenang-wenang, itu akan mengembalikan jawabannya. Sunting: Jika bahasa Anda memiliki kedalaman rekursi default yang terlalu ketat, Anda dapat mengonfigurasi ulang tanpa biaya karakter.
Pengajuan dengan jumlah karakter terpendek akan menang.
Berikut ini beberapa nilai, untuk memeriksa jawaban Anda:
A | n=0 1 2 3 4 5 6 7 8 9 10
-----+-----------------------------------------------------------------
m=0 | 1 2 3 4 5 6 7 8 9 10 11
1 | 2 3 4 5 6 7 8 9 10 11 12
2 | 3 5 7 9 11 13 15 17 19 21 23
3 | 5 13 29 61 125 253 509 1021 2045 4093 8189
4 | 13 65533 big really big...
A(3,8)
dan di atas sama naifnya dengan yang lain? Apakah saya harus datang dengan solusi non-rekursi, atau bisakah saya juga "mengasumsikan ruang stack tak terbatas" dalam kasus ini? Saya cukup yakin, itu akan berakhir dalam satu menit.Jawaban:
Pyth , 19
Menentukan
a
, yang berfungsi sebagai fungsi Ackermann. Perhatikan bahwa ini membutuhkan kedalaman rekursi yang lebih tinggi daripada compiler pyth resmi yang diizinkan hingga hari ini untuk menghitunga 3 10
, jadi saya meningkatkan kedalaman rekursi. Ini bukan perubahan bahasa, hanya ke kompiler.Uji:
Penjelasan:
Pada dasarnya, ini pertama-tama mengkondisikan pada nilai kebenaran
G
apakah akan muncul kembali atau mengembalikan H + 1. Jika berulang, argumen pertama selalu G-1, dan itu mengkondisikan pada nilai kebenaranH
apakah akan digunakana(G,H-1)
sebagai argumen kedua, atau untuk digunakan1
sebagai argumen kedua.sumber
DaGHR
keM
dana
keg
. (Apakah urutan argumen untuk?
perubahan?)M
sebagai gantinya, dan ya,?
urutan argumen berubah. Sekarang kondisinya, benar, salah. Itu benar, kondisi, salah.M
!Haskell, 35
ini menentukan fungsi operator
%
.ini bekerja dengan memperhatikan bahwa
m%n
(di manaa
adalah fungsi Ackerman) untuk nolm
yang(m-1)%
diterapkann+1
kali untuk1
. misalnya,3%2
didefinisikan apa2%(3%1)
adanya2%(2%(3%0))
, dan ini2%(2%(2%1))
sumber
0%n
bukann+1
karena diutamakanGolfScript (30)
Demo online
Tanpa
1>
(kasus-kasus khususA(1, n)
) yang dibutuhkan 9 menit untuk menghitungA(3, 10)
di komputer saya sudah mengujinya. Dengan case khusus itu cukup cepat sehingga demo online membutuhkan waktu kurang dari 10 detik.Perhatikan bahwa ini bukan terjemahan definisi yang naif. Kedalaman rekursi dibatasi oleh
m
.Pembedahan
sumber
1>
. Setelah dihapus (dan diubahif
ke?
), komputasi3 10 A
membutuhkan 110 detik dengan juru bahasa online dan enam detik dengan juru bahasa Java.Kalkulus biner biner , 54 bit = 6,75 byte
Hexdump:
Biner:
Ini adalah λ m . m (λ g . λ n . g ( n g 1)) (λ n . λ f . λ x . f ( n f x )), di mana semua angka direpresentasikan sebagai angka Gereja .
sumber
JavaScript, ES6,
4134 byteJalankan ini di Konsol Firefox terbaru dan itu akan membuat fungsi yang disebut
f
yang dapat Anda panggil dengan nilaim
dann
suka yang berbedaATAU
coba kode di bawah ini dalam Firefox terbaru
sumber
Python 2.7.8 -
80, 54, 48, 4645(Kredit ke xnor!)
Lebih mudah dibaca, tetapi dengan 1 karakter lebih:
Bukan berarti saya harus mengatur
sys.setrecursionlimit(10000)
untuk mendapatkan hasilA(3,10)
. Golf lebih lanjut menggunakan pengindeksan logis tidak bekerja karena kedalaman rekursi tumbuh secara dramatis.sumber
1else
. Huruf awale
menyebabkan masalah bagi parser karena angka dapat ditulis seperti1e3
.and/or
:A=lambda m,n:m and A(m-1,n<1or A(m,n-1))or-~n
1else
, sebagian besar versi lain tidak.1else
; itu memungkinkan saya memeras char di sini dan mungkin di tempat lain. Tapi sialan itu khusus versi! Python 2.7.4 tidak mengizinkannya. Apakah Anda menggunakan versi online dengan 2.7.8 atau haruskah saya mengunduhnya?1else
juga.J - 26 char
Ada definisi Ackermann alternatif yang lebih fungsional:
Kebetulan
Iter
sangat mudah untuk menulis dalam J, karena J memiliki cara untuk meneruskanm-1
keAck
dan juga untuk menentukan nilai awalIter
menjadi 1. Dijelaskan oleh ledakan:Ini bergantung pada apa yang disebut J sebagai bentuk gerund - pada
^:
dasarnya cara untuk memiliki kontrol lebih besar atas semua batasan dengan cara diam-diam (point-free).Di REPL:
Kita perlu mendefinisikan
ack
dengan nama untuk bisa meletakkannya di meja, karena itu$:
adalah binatang yang mengerikan, jelek dan menyerang siapa pun yang mencoba memahaminya. Ini adalah referensi-diri, di mana diri didefinisikan sebagai frase kata kerja terbesar yang mengandungnya.table
adalah kata keterangan dan sangat ingin menjadi bagian dari frasa kata kerja jika Anda memberinya kesempatan, jadi Anda harus menjebak$:
dalam definisi yang disebutkan untuk menggunakannya.Sunting: 24 karakter?
Bertahun-tahun kemudian, saya menemukan solusi yang dua karakter lebih pendek.
Ini jauh lebih lambat:
3 ack 8
membutuhkan waktu lebih dari satu menit pada mesin saya. Ini karena (1) Saya menggunakan lipatan/
alih-alih iterasi, jadi J mungkin harus mengingat lebih banyak hal daripada biasanya, dan (2) saat0&<~
melakukan perhitungan yang sama dengan(0<[)
, itu sebenarnya dieksekusin+1
kali sebelum mengambil langkah rekursif ketika memohonm ack n
-0&<
terjadi menjadi idempoten, sehingga tidak merusak perhitungan, tetapin
menjadi besar cepat danack
sangat rekursif.Saya ragu bahwa mesin yang lebih kuat dapat mendorong kode baru di bawah satu menit, karena ini adalah komputer di mana kode lama dapat ditemukan
3 ack 10
dalam waktu kurang dari 15 detik.sumber
C - 41 byte
Tidak ada artinya - batas kecil berarti bahwa semua nilai yang diperlukan dapat dihitung dalam waktu kurang dari 1 detik dengan secara naif mengikuti definisi fungsi.
sumber
Javascript ES6 (34)
Pelaksanaan:
sumber
JavaScript (ES6) - 34
Dan ujian:
sumber
Coq, 40
Ini adalah fungsi tipe
nat -> nat -> nat
. Karena Coq hanya memungkinkan konstruksi fungsi total, Coq juga berfungsi sebagai bukti resmi bahwa perulangan Ackermann beralasan.Demo:
Catatan: Coq 8.5, dirilis setelah tantangan ini, diganti namanya
nat_iter
menjadiNat.iter
.sumber
Raket 67
sumber
Mathematica, 46 byte
Memakan waktu yang cukup tepat
a[3,10]
. Perhatikan bahwa batas rekursi default Mathematica terlalu kecil untuka[3,8]
dan di luar (setidaknya di komputer saya), tetapi itu dapat diperbaiki dengan mengkonfigurasisumber
If
menjadi fungsi bahkan lebih lambat.m_~a~n_:=m~a~n=
...Javascript dengan lambdas, 34
Jawaban tipical, tidak dapat membuat sesuatu lebih pendek.
sumber
Haskell,
4844 karakter (36 untuk daftar)Meskipun tidak sependek solusi Haskell lainnya, solusi ini terkenal karena mengekspresikan fungsi Ackermann sebagai daftar tanpa batas, yang menurut saya agak rapi. Hasilnya adalah daftar tak terbatas (dari daftar tak terbatas) sehingga pada posisi [m, n] ia memegang nilai A (m, n) .
Daftar yang tak terbatas itu sendiri:
Sebagai fungsi (untuk memenuhi spesifikasi):
Formulasi diturunkan dengan mengamati bahwa kasus umum / umum untuk fungsi Ackermann adalah menggunakan nilai di sebelah kiri sebagai indeks pada baris di atas. Kasing dasar untuk rekursi ini (yaitu kolom paling kiri dari suatu baris, yaitu A (m, 0) ) adalah menggunakan nilai paling kiri kedua pada baris di atas. Kasus dasar untuk yang rekursi adalah A (0, n) = n + 1 kasus, yaitu baris pertama adalah
[1..]
.Jadi, kita dapatkan
Kemudian kita cukup menambahkan tingkat iterasi lain berdasarkan pola itu, dan melakukan beberapa juggling sia-sia .
sumber
iterate
ke satu nama huruf yaitui=iterate;ack=i ...
Tiny Lisp , 70 (keluar dari kompetisi)
Ini kehabisan kompetisi, karena bahasanya lebih baru dari pertanyaan, dan itu juga tidak berhasil menjalankan
(A 3 10)
seperti yang dipersyaratkan dalam pertanyaan, karena stack overflow.(d A(q((m n)(i m(i n(A(s m 1)(A m(s n 1)))(A(s m 1)1))(s n(s 0 1))))))
Ini mendefinisikan fungsi
A
yang menghitung fungsi Ackermann. Diformat:Kami menggunakan semua makro builtin (
d
(define) danq
(quote) dani
(if)) dan satu fungsi builtin (s
- kurangi) di sini.i
mengeksekusi bagian yang sebenarnya ketika kondisinya adalah angka> 0 (dan sebaliknya bagian yang salah), jadi kita tidak perlu melakukan perbandingan eksplisit di sini.s
adalah satu-satunya operasi aritmatika yang tersedia, kami menggunakannya untukn-1
/m-1
, dan juga(s n (s 0 1))
untukn+1
.Lump kecil menggunakan optimasi rekursi ekor, tetapi ini hanya membantu untuk bagian luar
A
panggilan dalam hasil, bukan untukA(m, n-1)
panggilan yang digunakan untuk parameter.Dengan implementasi cisp kecil saya di Ceylon pada JVM, ia bekerja hingga
(A 3 5) = 253
, tetapi tampaknya rusak ketika mencoba menghitung(A 2 125)
secara langsung (yang seharusnya memberikan hasil yang sama). Jika menghitung setelah itu(A 3 4) = 125
, JVM tampaknya harus mengoptimalkan fungsi cukup untuk inline beberapa panggilan fungsi menengah di interpreter saya, memungkinkan kedalaman rekursi lebih. Aneh.The implementasi referensi bangun untuk
(A 3 5) = 253
dan juga(A 2 163) = 329
, tapi tidak berhasil(A 2 164)
, dan karena itu bahkan kurang(A 3 6) = (A 2 253)
.sumber
Pergi,
260243240122 byteSaya tidak melihat bahwa pertanyaan itu memungkinkan beberapa fungsi.
jauh dari kompetitif tetapi saya sedang belajar bahasa ini dan saya ingin mengujinya.
gunakan seperti
go run ack.go
lalu berikan dua angka,m
dann
. jika m> 4 atau n> 30, waktu eksekusi mungkin lebih dari setengah menit.untuk
m=3 n=11
:edit : menyimpan total 17 byte dengan beralih ke
switch
overif/else
dan dot-importsumber
switch 0 {case m:r=n+1 case n:r=a(m-1,1) default:r=a(m-1,a(m,n-1))}
Goswitch
sangat indah dan fleksibel!Haskell:
8169 bytea 3 10
membutuhkan sekitar 45 detik.sumber
(non-bersaing) Pyth, 15 byte
Cobalah online!(Contoh penggunaan fungsi
g3T
ditambahkan, yang berartig(3,10)
)sumber
(tidak bersaing) UGL ,
3130 byteInput dipisahkan oleh baris baru.
Cobalah online!
(Ini telah diterapkan sebagai contoh standar dalam penerjemah.)
sumber
Julia,
343128 byteIni adalah fungsi anonim bernama. Ini adalah implementasi langsung dari definisi rekursif, menyalahgunakan kemampuan Julia untuk mendefinisikan kembali operator .
Cobalah online!
sumber
R -
5452Saya menggunakan ini sebagai alasan untuk mencoba dan mendapatkan kepalaku sekitar R, jadi ini mungkin benar-benar dilakukan dengan buruk :)
Contoh dijalankan
Saya mendapatkan stack overflow untuk apa pun selain itu
T-SQL-222
Saya pikir saya akan mencoba untuk mendapatkan T-SQL untuk melakukannya juga. Menggunakan metode yang berbeda karena rekursi tidak begitu baik di SQL. Lebih dari 4,2 bom itu.
sumber
{}
meskipun tidak ada yang membantu batas stack overflow, karena R tidak memiliki TCO ...brainfuck , 90 byte
Cobalah online!
Mengasumsikan implementasi dengan ukuran sel yang berubah-ubah, dengan IO sebagai angka. -6 byte jika Anda tidak keberatan menggunakan sel negatif.
Selesai dalam waktu sekitar 30 detik selama 3,8 dalam penerjemah tertaut, asalkan Anda mencentang pengaturan yang benar. Ketik nomor diinput didahului dengan
\
s, misalnya3,9
adalah\3\9
.sumber
Tcl , 67 byte
Cobalah online!
Tcl , 77 byte
Cobalah online!
Dalam kompiler online, ia gagal dijalankan karena time-out, tetapi dalam interpreter Tcl lokal ia berjalan dengan baik. Saya membuat profil setiap panggilan root ke
A
berfungsi, untuk melihat berapa banyak waktu perhitungan yang diperlukan untuk setiap{m,n}
subjek pasangan yang akan diuji:Gagal untuk pasangan terakhir
{m,n}={3,10}
, karena dibutuhkan sedikit lebih dari satu menit.Untuk nilai yang lebih tinggi
m
, akan diperlukan untuk meningkatkanrecursionlimit
nilainya.Saya dapat membuatnya lebih pendek hingga 65 byte, tetapi tidak akan memenuhi persyaratan pertanyaan "Fungsi Anda harus dapat menemukan nilai A (m, n) untuk m ≤ 3 dan n ≤ 10 dalam waktu kurang dari satu menit.". Tanpa
{}
itu akan habis pada TIO dan tidak melakukan demo dari dua entri terakhir.Tcl , 65 byte
Cobalah online!
sumber
J: 50
Kembali dalam sepersekian detik untuk 0 ... 3 vs 0 ... 10:
PS: the "0 berfungsi untuk membuat A bekerja pada setiap elemen tunggal, alih-alih melahap array kiri dan kanan, dan menghasilkan kesalahan panjang. Tapi itu tidak diperlukan untuk misalnya. 9 = 2 A 3.
sumber
APL, 31
Cukup mudah. Menggunakan karakter ⍨ satu kali untuk menyimpan satu byte dengan membalik argumen. Membawa m sebagai argumen kiri dan n sebagai argumen kanan.
TryAPL.org
sumber
Ruby, 65
Penjelasan
Ini adalah terjemahan yang cukup mudah dari algoritma yang diberikan dalam deskripsi masalah.
Integer
s diharapkan.Hash
h
. The||=
operator yang digunakan untuk menghitung nilai yang sebelumnya tidak dihitung.a[3,10]
dihitung dalam ~ 0,1 detik di mesin saya.Berikut ini adalah versi yang tidak dipisahkan
sumber
a[3,10]
melempar SystemStackError pada mesin saya ...m<1?(n+1):(n<1?a[m-1,1]:a[m-1,a[m,n-1]])
menjadim<1?n+1:a[m-1,n<1?1:a[m,n-1]]
Mouse-2002 ,
9983 bytesumber
Java, 274 byte
Ini menghitung
A(3,10)
dalam beberapa detik, dan diberi ruang memori dan stack yang tak terbatas, ia dapat menghitung kombinasi apa punb
danB
selama hasilnya di bawah 2 2147483647 -1.sumber
import java.math.*;BigInteger A(BigInteger b,BigInteger B){return b.equals(B.ZERO)?B.add(B.ONE):B.equals(B.ZERO)?A(b.subtract(B.ONE),B.ONE):A(b.subtract(B.ONE),A(b,B.subtract(B.ONE)));}
Ceylon,
888785Ini adalah implementasi yang mudah. Diformat:
Alias menyimpan hanya satu byte, tanpa itu (dengan tulisan
Integer
alih-alihI
) kita akan mendapatkan 86 byte. Dua byte dapat disimpan dengan mengganti== 0
dengan< 1
dua kali.Dengan pengaturan default
ceylon run
, ini akan berfungsi hinggaA(3,12) = 32765
(danA(4,0) = 13
), tetapiA(3,13)
(dan karenanya jugaA(4,1)
) akan melempar kesalahan stack overflow. (A(3,12)
membutuhkan sekitar 5 detik,A(3,11)
sekitar 3 pada komputer saya.)Menggunakan
ceylon run-js
(yaitu menjalankan hasil kompilasi ke JavaScript pada node.js) jauh lebih lambat (perlu 1 menit 19 detik untukA(3,10)
), dan sudah terputus untukA(3, 11)
dengan »Ukuran tumpukan panggilan maksimum melebihi« (menggunakan pengaturan default) setelah berjalan selama 1 min 30 dtk.Ceylon tanpa rekursi, 228
Sebagai bonus, ini adalah versi non-rekursif (lebih lama, tentu saja, tetapi kebal terhadap stack overflow - mungkin mendapatkan kesalahan kehabisan memori di beberapa titik).
Diformat:
Ini lebih lambat di komputer saya daripada versi rekursif:
A(3,11)
membutuhkan 9,5 detik,A(3,12)
membutuhkan 34 detik,A(3,13)
membutuhkan waktu 2:08 menit,A(3,14)
membutuhkan waktu 8:25 menit. (Saya awalnya memiliki versi menggunakan iterables malas, bukan tuple yang saya miliki sekarang, yang bahkan lebih lambat, dengan ukuran yang sama).Sedikit lebih cepat (21 detik untuk
A(3,12)
) (tetapi juga satu byte lebih lama) adalah versi yang menggunakans.push
alih-alihs.addAll
, tetapi itu perlu dipanggil beberapa kali untuk menambahkan beberapa angka, karena masing-masing hanya membutuhkan satu bilangan bulat. Menggunakan LinkedList daripada ArrayList jauh lebih lambat.sumber