Теоретично виведіть число Грема


44

Число Грема Gвизначається таким чином:

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

THEN

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

Вам дано u(3,3,2)=7625597484987перевірити свій код.

Ваше завдання - написати програму / функцію, яка буде виводити значення Gдетерміновано з урахуванням достатнього цілого розміру та достатнього часу.

Список літератури

Таблиця лідерів



7
Чи дозволена випадковість? Якщо я просто вивожу випадкові значення, врешті-решт треба отримати число Грема.
миль

15
@miles Чому на землі це вже не стандартна лазівка? Уточнено.
Leaky Nun

18
Попередження: u (3, 3, 2) = u (3, 2, 3) = 7625597484987, тому ви також хочете перевірити інші значення, такі як u (3, 5, 1) = 243, щоб переконатися, що ви отримали аргумент в порядку право.
Андерс Касеорг

Відповіді:


48

Двійкове обчислення лямбда , 114 біт = 14,25 байт

Hexdump:

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

Двійковий:

010001000101011101000010101100000010110110001000000111111001110101110100000011100101111011010000001110011100111010

Пояснення

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

Це (λ x . (Λ y . X ym . Mg . Λ n . N g 1) (λ n . Λ f . X ( n f )) x ) y ) (λ f . Λ z . f ( x f z ))) 3, де всі числа представлені у вигляді церковних цифр. Церковні цифри - це стандартне представлення натуральних чисел лямбда-числення, і вони добре підходять до цієї проблеми, оскільки церковне число визначається за допомогою ітерації функції: n g - n -ітерація функції g .

Наприклад, якщо g - функція λ n . λ f . 3 ( n f ), що помножує 3 на церковну цифру, тоді λ n . n g 1 - це функція, яка приймає 3 під силу церковного числа. Ітерація цієї операції m разів дає

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

(Ми використовуємо множення u (-, -, 0), а не експоненціацію u (-, -, 1) як базовий випадок, тому що відняти 1 від церковного числа неприємно .)

Заміна n = 3:

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

Ітерація цієї операції 64 рази, починаючи з m = 4, дає

64 (λ м . Мг . Λ п . П р 1) (λ п . Λ е . 3 ( п е )) 3) 4 = Про .

Щоб оптимізувати цей вираз, замініть 64 = 4 ^ 3 = 3 4:

3 4 (λ м . Мг λ. П . П р 1) (λ п . Λ е . 3 ( п е )) 3) 4 = Про .

Запам’ятайте 4 = succ 3 = λ f . λ z . f (3 f z ) як лямбда-аргумент:

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

Нарешті, пригадайте 3 = λ f . λ z . f ( f ( f z )) як лямбда-аргумент:

x . (λ y . x ym . mg . λ n . n g 1) (λ n . λ f . x ( n f )) x ) y ) (λ f . λ z . е ( х е г ))) 3 = Про .


Де можна було знайти перекладача цієї мови?
Денніс

4
@Dennis tromp.github.io/cl/cl.html має декілька з них.
Anders Kaseorg

1
Це приголомшливо . це заслуговує значної щедрості
кішка

1
14.25 bytesначебто псує таблицю лідерів. Він розбирається як 25 bytes, і тому ви ставитесь як другі.
Ден

1
@ Думаю, я виправив фрагмент дошки лідерів, я думаю.
Андерс Касеорг

40

Haskell, 41 байт

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

Пояснення:

(`i`1)f n= i f 1 nобчислює nітерат функції, fпочинаючи з 1. Зокрема, (`i`1)(*3)n= 3 ^ n , і повторення цієї побудови m разів дає i(`i`1)(*3)m n= u (3, n , m ). Ми можемо переписати це як (($n).i(`i`1)(*3))m= u (3, n , m ) і повторити цю конструкцію k разів, щоб отримати i(($3).i(`i`1)(*3))4 k= g _ k .


16

Haskell, 43 байти

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

Існує кращий спосіб перевернути gInline.

46 байт:

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

48 байт:

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

Просто записуємо визначення.

Базові корпуси трохи чистіші з резервними копіями до 0, хоча це не економить байтів. Можливо, це полегшить написання альтернативного визначення.

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

Чи можете ви використовувати іншу функцію, яка має пріоритет нижче, ніж +для видалення дужок між ними m-1?
Лина монашка

Я рахую 44 байти, а що сталося з 4 та 64?
Лина монашка

На жаль, я скопіював тест менших параметрів. Я не думаю, що я можу змінити пріоритет оператора, оскільки я визначаю нову функцію, а ті мають пріоритет за замовчуванням. Я не можу перезаписати існуючу функцію.
xnor

Я маю в виду, я вважаю 44 байта після того, як ви зміните його назад 64.
дірявої черниці

Я думаю, ти маєш на увазі (`g`3), ні (3`g`).
Андерс Касеорг

10

Pyth, 25 байт

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

Перша частина M?H.UgbtH*G]3^3Gвизначає метод g(G,H) = u(3,G,H+1).

Для того, щоб перевірити першу частину, переконайтеся , що 7625597484987=u(3,3,2)=g(3,1): g3 1.

Друга частина ug3tG64 4починається з, r0 = 4а потім обчислюється rn = u(3,3,r(n-1)) = g(3,r(n-1))64 рази, виводячи остаточне значення ( rвибирається замість того, gщоб уникнути плутанини).

Щоб перевірити цю частину, почніть з , r0=2а потім обчислити r1: ug3tG1 2.


Якщо g (G, H) = u (3, G, H + 1), ви повинні мати r (n) = u (3, 3, r (n - 1)) = g (3, r (n - 1 ) - 1), а не g (3, r (n - 1)). Я думаю, що ваш код правильний, але у вашому поясненні відсутнє - 1.
Anders Kaseorg

Ви можете зберегти байт, використовуючи невстановлені аргументи u ( ^3*3, tGG) та інший байт з .UgbtH*G]3e.ugNtHG1.
Андерс Касеорг

Альтернативний спосіб зберегти цей другий байт - *G]3ShG.
Андерс Касеорг

8

Сесос , 30 байт

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

Розібраний

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

Або в позначенні Brainfuck:

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

Тестування

Для обчислення U (3, п , U (3, п ... у (3, п , м ) ...)) з K вкладених викликів функції і замінити перші три addінструкцій add 4, add 64, add 3з add m, add k, add nвідповідно. Оскільки Sesos не може побудувати числа швидше, ніж у лінійний час, ви практично обмежені малими значеннями, такими як u (3, 2, 2) = 27, u (3, 5, 1) = 243 і u (3, 1 , u (3, 1,… u (3, 1, m )…)) = 3.


Ви можете замінити [-]з , ,так як EOF є 0.
mbomb007

6

JavaScript (ES7), 63 байти

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

@AndersKaseorg Фу, у такому випадку я міг би відновити ці зміни.
Ніл

Це спричиняє переповнення стека, можливо, потрібно повторно перевірити схему рекурсії.
NodeNodeNode

Це не просто ES7. Це необмежений ES7 (уявний варіант ES7, але з bignum, здатний нескінченно проробляти оракул і використовує десяткові знаки з / # xE ^ як скорочення).
користувач75200

5

Брахілог , 57 байт

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

Очікує, що немає вводу чи виводу та записує результат у STDOUT. Це призведе до переповнення стека в одній точці.

Щоб перевірити, чи працює це для малих значень (наприклад u(3,3,2)), ви можете замінити 4значення на mі 64на 1.

Пояснення

Це в основному просто реалізація поясненого способу обчислення числа.

  • Основний предикат:

    4:64:1i                    Call Predicate 1 64 times with 4 as initial input (the second
                               call takes the output of the first as input, etc. 64 times).
           w                   Write the final output to STDOUT
    
  • Предикат 1:

    :3{...}.                   Call predicate 2 with input [Input, 3]. Its output is the 
                               output of predicate 1.
    
  • Предикат 2:

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

5

Карамель , 38 байт

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

Це синтаксичний цукор для вираження обчислення лямбда 64 (λ m . Mf . Λ n . N f 1) (λ n . Λ f . 3 ( n f )) 3) 4, де всі числа представлені як Церква числівники .


(n f->3 (n f))чи не слід це читати n-1?
Лина монашка

@LeakyNun No. (n f->3 (n f))- це функція для множення на три в церковних числівниках .
Андерс Касеорг

2
Цей виклик здається надмірно простим в обчисленні лямбда. Чому?
кіт

3

Prolog (SWIPL), 129/137 байт

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

Щоб вивести номер Грема, запитуйте g(64,G).(якщо підрахувати 8 байт цього запиту, довжина становить 137 байт):

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

Але, як можна очікувати, цього не вистачає.

Тест

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

Зворотний трек призводить до того, що у нього закінчується стек:

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

Безумовно

Версія, що не використовується, додає загальне позначення стрілки вгору, а не лише для 3-х, і використовує скорочення та перевірки, щоб уникнути зворотного відстеження та невизначених ситуацій.

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

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

Як вам вдалося це зробити, не маючи 64ніде свого коду?
Leaky Nun

@LeakyNun я відредагував, щоб уточнити; краще?
SQB

Ну, а потім додайте його у свій код, а також свій байт.
Leaky Nun

3

C, 161 байт

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

EDIT: збережено 11 байт, видаливши вкладки та нові рядки. EDIT: thx auhmann врятував ще один байт і виправив мою програму


1
Ви можете зняти, g(int a){if(a==1)return u(3,4);return g(a-1);}оскільки він взагалі не використовується ... Або ви щось забули?
auhmaan

@auhmaan На жаль, я використав це число для тестування і забув змінити його. Дякую!!
thepiercingarrow

Ваше return g(a-1)має бути return u(3,g(a-1)).
Андерс Касеорг

1
Я не знаю, чи повинен я відповісти належним чином або просто прокоментувати це, але ви можете легко вирішити це рішення до 114 байт, зрозумівши: Нові рядки між функціями можна опустити. Пропускаючи типи для всіх аргументів за замовчуванням їх до int (думаємо, K&R). Якщо такі заяви можна записати за допомогою вкладених потрійних опцій. Код:u(a,b){return a<2?3:b<2?pow(3,a):u(u(a-1,b),b-1);}g(a){return a<2?u(3,4):u(3,g(a-1));}main(){printf("%d",g(64));}
альгмір

@algmyr дивовижно! вам слід відправити свою власну відповідь XD.
thepiercingarrow

2

Математика, 59 байт

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

Використовується невизначений оператор інфіксації, ±котрий вимагає лише 1 байт при кодуванні в ISO 8859-1. Додаткову інформацію див. У публікації @ Martin . Функції Mathematica підтримують узгодження шаблону для своїх аргументів, таким чином, що два базових випадки можна визначити окремо.


1
З якого часу Mathematica використовував ISO 8859-1?
Лина монашка

n_ ±m_:=Nest[#±(m-1)&,3,n]
Лина монашка

2

C, 114 109 байт

Виходячи з відповіді @thepiercingarrow ( посилання ), я відповів зовсім небагато. Більшість заощаджень пояснюються зловживанням типовими аргументами за замовчуванням під час виконання функцій стилю K&R та заміною операторів if, якщо вони поступають з потрійними операторами. Додані необов'язкові нові рядки між функціями для читабельності.

Покращено до 109 завдяки @LeakyNun.

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

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

@LeakyNun Це дійсно добре. Дякую.
algmyr

1

Пітон, 85 байт

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

vФункція визначає ту ж функцію, знайдені в відповіді Дениса : v(n,m) = u(3,n+1,m+1). gФункція нульового проіндексована версія традиційної ітерації: g(0) = v(2,3), g(n) = v(2,g(n-1)). Таким чином, g(63)це число Грема. Встановивши значення за замовчуванням для nпараметра gфункції 63, потрібний вихід можна отримати, зателефонувавши g()(без параметрів), таким чином задовольнивши наші вимоги щодо подання функції, яка не приймає ніяких даних.

Перевірте v(2,1) = u(3,3,2)і v(4,0) = u(3,5,1)випробуйте випадки в Інтернеті: Python 2 , Python 3


1
Це важко перевірити, але ваша функція gздається вимкненою. Не повинно v(2,n-1)бути g(n-1)чи щось подібне?
Денніс

@Dennis Хороший улов. Я це виправлю.
Mego

Насправді зміщення між uі vозначає, що воно повинно бути g(n-1)-1.
Андерс Касеорг

@AndersKaseorg Я не повинен займатися програмуванням, коли сплячий. Мені доводиться повторно вчитися цьому кожні кілька днів.
Mego

@AndersKaseorg Надалі не редагуйте подання інших людей, навіть якщо це виправить помилку в запропонованому вами поліпшенні / помилку.
Mego

1

Діалог APL, 41 байт

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

Тестовий випадок:

      3u 2
7625597484987

Ви повинні мати можливість перейти 1=⍺:3⋄1=⍵:3*⍺на just 1=⍵:3*⍺( 3=3*1)
Zacharý

1

Рубін, 64 байти

Запозичення з теоретичного алгоритму для обчислення числа Грема .

def f(a,b=3)b<2?3:a<1?3*b:f(a-1,f(a,b-1))end;a=4;64.times{a=f a};p a

Простіше кажучи, f a = u(3,3,a)і застосовується це 64 рази.


Гарне пояснення того, чому і як працює цей код, було б непогано.
Маніш Кунду

Це пряме застосування визначення числа Грема.
Просто красиве мистецтво

0

J, 107 байт

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

Я працюю над перетворенням uпорядку денного, але поки це буде.


Щось на кшталт u=:3^[`[:(3$:])/[#<:@]@.*@](не перевірено)
Leaky Nun

0

F #, 111 108 байт

Редагувати

Це використовується за допомогою наведеної нижче функції для обчислення числа Грема

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

Ось моя попередня відповідь, яка, ну, не:

Досить прямо. Просто визначення uфункції.

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

Використання:

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

Якщо я вважав, що 3 є значенням для a, я міг би скоротити його до 60:

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

Використання:

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

Завдання полягає в тому, щоб написати номер Грема, а не u. Звичайно, ви можете включати будь-які проміжні функції, які вам потрібні, наприклад, uз першим аргументом або без нього, зафіксованим на 3.
Anders Kaseorg

@AndersKaseorg відредагував це. Дякую. Мій попередній коментар, здається, зник.
асібахі

0

R, 154 142 128 126 118 байт

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

Я використовував у Вікіпедії визначення цієї рекурсивної функції, оскільки з якоїсь дивної причини запропонований варіант не працював ... або я просто смоктав на R гольф.

UPD: поголений 12 + 14 = 26 байт завдяки наконечнику від Leaky Nun . Попередня версія використовувала об'ємні та менш ефективні

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

UPD: поголив 2 + 6 + 2 більше байта (знову ж таки, кудо до Leaky Nun ) завдяки геніальній заміні на "if (x)" замість "if (x == 0)", оскільки x <0 ніколи не подається функція ... правда?


@LeakyNun Дякую, оновлення відповіді оновлено.
Андрей Костирка

Всього на секунду ... Сьогодні мій перший день гольф-коду, є чому навчитися!
Андрей Костирка

Вас запрошують приєднатися до нашого чату .
Leaky Nun

Більше гольфу, дивіться поліпшення.
Андрей Костирка

Ta-dam, зроблено, змінив функцію uв тій же клавіші, що і ваш, gі врятував ще 6 байт - приголомшливо!
Андрей Костирка

0

PHP, 114 байт

ігноруйте розриви рядків; вони призначені лише для читабельності.

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

Можна інтегрувати другий випадок у перший: для n=1, 3^nдорівнює 3.
Це дозволить заощадити кілька байтів на - наскільки я бачу - всі існуючі відповіді; зберегли два байти на моєму

попередня версія, 62 + 43 + 11 = 116 байт

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

Ліва асоціативність PHP потрійного вимагає дужок ... або певного порядку тестів.
Це зберегло два байти на викладеному в дужці виразі.


Мабуть, є ітеративний підхід, який може дозволити подальший гольф ...
але я зараз не можу витратити час на це.


хотілося б, щоб я знав Сесоса або встиг його навчитися і перекладати зараз
Тит

@Leaky Nun: Я розбив це лише на петлі та доповнення. Чи є спосіб у Sesos додати значення однієї комірки до іншої?
Тит

@AndersKaseorg: Напевно ти маєш рацію ... У мене з’явилися пухирі на очних яблуках від перегляду цього алгоритму. Поглянемо на це незабаром знову.
Тит
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.