理论上输出格雷厄姆数


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
是否允许随机性?如果我只是输出随机值,那么最终必须产生格雷厄姆数。
2016年

15
@miles为什么地球上已经不是标准漏洞?澄清。
Leaky Nun

18
警告:u(3,3,2)= u(3,2,3)= 7625597484987,因此您还需要测试其他值,例如u(3,5,1)= 243,以确保获得参数顺序权。
Anders Kaseorg 2016年

Answers:


48

二进制Lambda演算,114位= 14.25字节

十六进制转储:

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(λ ÿX ÿ(λ (λ 。λ ñÑ 1)(λ Ñ。λ ˚FXÑ ˚F))XÝ)(λ ˚F。λ ž˚FX ˚F ž)))3,其中所有数值被表示为Church数。Church数是自然数的标准演算表示,并且它们非常适合于这个问题的原因是教会数由函数迭代定义:Ñ Ñ次迭代的函数的

例如,如果是函数λ Ñ。λ ˚F。3(Ñ ˚F),其通过一个教会数字乘以3,则λ Ñn g 1是将教会数的幂乘以3的函数。重复此操作m次,得到

(λ 。λ ñÑ 1)(λ Ñ。λ ˚F 3(Ñ ˚F))ñ = ù(3,Ñ)。

(我们使用乘法u(–,–,0)而不是幂u(–,–,1)作为基数,因为从教堂数字中减去1是不愉快的。)

替代n = 3:

(λ 。λ ññ (λ1)ñ。λ ˚F 3(Ñ ˚F))3 = ù(3,3,)。

m = 4 开始迭代该操作64次,得到

64(λ (λ 。λ ñÑ 1)(λ Ñ。λ ˚F 3(Ñ ˚F))3)4 = g ^

要优化此表达式,请代入64 = 4 ^ 3 = 3 4:

3 4(λ (λ 。λ ñÑ 1)(λ Ñ。λ ˚F 3(Ñ ˚F))3)4 = g ^

记得4 = SUCC 3 =λ ˚F。λ žf(3 f z)作为lambda参数:

(λ ÿ 3 ÿ(λ (λ 。λ ñÑ 1)(λ Ñ。λ ˚F 3(Ñ ˚F))3)Ý)(λ ˚F。λ ž˚F(3 ˚F ž))= g ^

最后,请记住3 =λ ˚F。λ žfff z))作为lambda参数:

(λ X(λ ÿX ÿ(λ (λ 。λ ñÑ 1)(λ Ñ。λ ˚FXÑ ˚F))XÝ)(λ ˚F。λ ž˚FX ˚F ž)))3 = G ^


在哪里可以找到这种语言的翻译?
丹尼斯


1
太棒了。这应该得到可观的赏金

1
14.25 bytes似乎弄乱了排行榜。它被解析为25 bytes,因此您排名第二。
2013年

1
@Dan,我认为我固定了排行榜片段。
Anders Kaseorg

40

Haskell,41个字节

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

说明:

(`i`1)f n= i f 1 n计算从开始n的函数的迭代。特别是= 3 ^ n,并将此构造迭代m次,得出= u(3,nm)。我们可以将其重写为= u(3,nm),并将此构造迭代k次以获得= g _ kf1(`i`1)(*3)ni(`i`1)(*3)m n(($n).i(`i`1)(*3))mi(($3).i(`i`1)(*3))4 k


16

Haskell,43个字节

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

有更好的g内联翻转方式。

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吗?
Leaky Nun

我数了44个字节,4和64发生了什么?
Leaky Nun

糟糕,我在较小参数测试中进行了复制。我认为我无法更改运算符的优先级,因为我正在定义一个新函数,并且这些函数具有默认优先级。我无法覆盖现有功能。
xnor

我的意思是,我算44个字节你将其改回64后
漏嫩

我想你的意思(`g`3)不是(3`g`)
Anders Kaseorg 2016年

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,然后计算r1ug3tG1 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
安德斯Kaseorg

您可以使用未偏移的u参数(^3*3tGG)和一个带有.UgbtH*G]3↦ 的字节来保存一个字节e.ugNtHG1
Anders Kaseorg '16

保存第二个字节的另一种方法是*G]3ShG
Anders Kaseorg '16

8

Sesos,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表示法:

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

测试中

为了计算ù(3,Ñù(3,Ñ,... ù(3,Ñ)...))与ķ嵌套调用ü,取代前三个add指令add 4add 64add 3add madd kadd 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 '16

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 Ugh,在这种情况下,我不妨还原该更改。
尼尔

这会导致堆栈溢出,可能需要重新检查递归模式。
NodeNodeNode

这不是简单的ES7。这是不受限制的ES7(ES7的一种虚构变体,但具有bignum,可以无限运算,并且使用带/#xE ^的十进制表示速记)。
user75200

5

Brachylog,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用的价值m64使用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)

这是lambda演算表达式64语法糖(λ (λ ˚F。λ ñÑ ˚F 1)(λ Ñ。λ ˚F 3(Ñ ˚F))3)4,其中的所有数值被表示为教会数字


(n f->3 (n f))它不应该读n-1吗?
Leaky Nun

@LeakyNun No. (n f->3 (n f))是用于将教堂数字乘以3的函数。
Anders Kaseorg

2
在lambda演算中,这一挑战似乎过于简单。为什么?

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));}

编辑:通过删除制表符和换行符节省了11个字节。编辑: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))
Anders Kaseorg

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

@algmyr哇!您应该发布自己的答案XD。
thepiercingarrow '16

2

Mathematica,59个字节

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

使用未定义的infix运算符±,在ISO 8859-1中进行编码时仅需要1个字节。有关更多信息,请参见@Martin的帖子。Mathematica函数支持对其参数进行模式匹配,从而可以分别定义两个基本情况。


1
从什么时候开始Mathematica使用ISO 8859-1?
Leaky Nun

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

2

C,114个 109字节

根据@thepiercingarrow(链接)的答案,我对答案进行了很多研究。大多数节省是由于在执行K&R样式函数时滥用了默认的参数类型,以及用三元运算符替换了if语句。在功能之间添加了可选的换行符,以提高可读性。

由于@LeakyNun而提高到109。

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 '16

1

Python,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参数的默认值设置g63,可以通过调用g()(不带参数)获得所需的输出,从而满足我们对不需要输入的函数提交的要求。

在线验证v(2,1) = u(3,3,2)v(4,0) = u(3,5,1)测试用例:Python 2Python 3


1
有点难以验证,但是您的功能g似乎关闭了。不v(2,n-1)应该g(n-1)还是类似的东西?
丹尼斯

@丹尼斯好抓住。我会解决的。
Mego

实际上,u和之间的偏移量v应为g(n-1)-1
Anders Kaseorg '16

@AndersKaseorg我不应该在困倦时进行编程。我必须每隔几天重新学习一次。
Mego

@AndersKaseorg将来,即使要修正您建议的改进/错误修正中的错误,也请不要编辑其他人的提交。
Mego

1

Dyalog 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ý'7


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#,111108字节

编辑

这是使用下面的函数计算格雷厄姆的电话号码

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 2016年

@AndersKaseorg对此进行了编辑。谢谢。我以前的评论似乎已经消失了。
asibahi

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)

我使用Wikipedia定义了此递归函数,因为出于某种奇怪的原因,建议的那个函数不起作用...或者我只是在R打高尔夫球。

UPD:由于Leaky Nun的提示,减少了12 + 14 = 26个字节。先前版本使用的是笨重且效率较低的

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:由于巧妙地用“ if(x)”而不是“ if(x == 0)”替换,因此减少了2 + 6 + 2个字节(再次对Leaky Nun表示敬意),因为从未将x <0馈入功能...对吗?


@LeakyNun谢谢您,并用确认更新了答案。
安德烈KOSTYRKA

只需几秒钟...今天是我打高尔夫的第一天,有很多东西要学习!
安德烈KOSTYRKA

邀请您加入我们的聊天室
Leaky Nun

更多高尔夫运动,请看改进。
安德烈KOSTYRKA

Ta-dam完成了,u在与您相同的键中更改了功能,g并节省了6个字节-太棒了!
安德烈KOSTYRKA

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);

可以将第二种情况整合到第一种情况中:for n=13^nequals 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的三元组合左键需要括号...或特定的测试顺序。
这在括号表达式中保存了两个字节。


可能有一种迭代的方法,可能允许进一步打高尔夫球...
但是我现在不能花时间。


希望我认识Sesos或有时间立即学习和翻译
Titus

@Leaky Nun:我将其分解为仅循环和加法。Sesos中是否可以将一个单元格的值添加到另一个单元格中?
泰特斯(Titus)

@AndersKaseorg:您可能是对的...通过查看该算法,我的眼睛发了水泡。很快会再次查看。
泰特斯(Titus)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.