理論的にグラハムの数を出力します


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一体なぜ標準の抜け穴ではないのですか?明確にした。
リーキー修道女

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(λ YX Y(λ MM(λ G。λ NN G 1)(λ N。λ FXN F))XY)(λ F。λ ZFX F zのすべての数は以下のように表されている)))3、教会数字。教会の数字は自然数の標準ラムダ計算の表現であり、教会の数は関数の繰り返しによって定義されているため、それらは同様にこの問題に適している:N GがであるN個の関数の反復番目G

たとえば、gが関数λnである場合。λ F。3(N F)は教会符号によって乗算3は、λ Nn g 1は、教会の数字の3のべき乗を取る関数です。この操作をm回繰り返すと、

M(λ G。λ NN G 1)(λ N。λ F。3(N F))N = U(3、NM)。

(我々は、乗算使用U - 、 - 、0)よりもむしろべき乗(U教会数字から1を減算することであるため、基本ケースとして、1)の( - - 、 不快)。

置換n = 3:

M(λ G。λ NN G 1)(λ N。λ F。3(N F))3 = U(3、3、M)。

m = 4 から始まる操作を64回繰り返すと、

64(λ MM(λ G。λ NN G 1)(λ N。λ F。3(N F))3)4 = G

この式を最適化するには、64 = 4 ^ 3 = 3 4を代入します。

3 4(λ MM(λ G。λ NN G 1)(λ N。λ F。3(N F))3)4 = G

4 = SUCC 3 =λを覚えておいてくださいFを。λ Z。ラムダ引数としてのf(3 f z):

(λ Y 3 、Y(λ MM(λ G。λ NN G 1)(λ N。λ F。3(N F))3)Y)(λ F。λ ZF(3 F Z))= Gは

最後に、3 =λ覚えFを。λ Zfff z))ラムダ引数として:

(λ X(λ YX Y(λ MM(λ G。λ NN G 1)(λ N。λ FXN F))XY)(λ F。λ ZFX 、F Z)))3 = G


この言語の通訳はどこで見つけられますか?
デニス

4
@Dennis tromp.github.io/cl/cl.htmlにはそれらがいくつかあります。
アンデルスカセオルグ

1
これはすごいです。これは相当な賞金に値する

1
14.25 bytesリーダーボードを台無しにしているようです。として解析される25 bytesため、2番目に配置されます。
ダン

1
@Danリーダーボードのスニペットを修正したと思います。
アンデルスカセオルグ

40

Haskell、41バイト

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

説明:

(`i`1)f n= は、から始まる関数の反復をi f 1 n計算します。特に、= 3 ^ nであり、この構成をm回繰り返すと= u(3、nm)が得られます。これをas = u(3、nm)に書き換え、この構成をk回繰り返してget = g _ kにすることができます。nf1(`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か?
リーキー修道女

44バイトをカウントしますが、4と64はどうなりましたか?
リーキー修道女

おっと、小さいパラメータのテストでコピーしました。新しい関数を定義しており、それらにデフォルトの優先順位があるため、演算子の優先順位を変更できるとは思わない。既存の関数を上書きできません。
xnor

私はあなたが戻って64にそれを変更した後、私は44のバイトを数え、平均値
漏れ修道女

あなたが意味するの(`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

2番目の部分ug3tG64 4は64 から始まり、64回r0 = 4計算してrn = u(3,3,r(n-1)) = g(3,r(n-1))、最終値を出力します(混乱を避けるために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
アンダースKaseorg

あなたは(unoffsetted uの引数を使ってバイトを保存することができ^3*3tGG)、および持つ別のバイト.UgbtH*G]3e.ugNtHG1
アンデルスカセオルグ

その第二のバイトを保存する別の方法がある*G]3ShG
アンデルスカセオルグ

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表記で:

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

テスト中

計算するためにUを(3、nはU(3、N、... U(3、nはMで)...))Kにネストされた呼び出しU、最初の三つの交換addの指示をadd 4add 64add 3add madd kadd nそれぞれ、。Sesosは線形時間よりも速く数値を構築できないため、実際にはu(3、2、2 )= 27、u(3、5、1 )= 243、u(3、1)のような小さな値に制限されます、u3、1、… u3、1m)…))= 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 Ugh、その場合、その変更を元に戻すこともできます。
ニール

これによりスタックオーバーフローが発生し、再帰パターンを再確認する必要がある場合があります。
NodeNodeNode

これは単純なES7ではありません。これは無制限のES7です(ES7の架空のバリアントですが、bignumを使用し、無限にオラクルでき、省略形として/#xE ^を使用した10進数を使用しています)。
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)

これは、ラムダ計算式64のための糖衣構文である(λ MM(λ F。λ NN fは 1)(λ N。λ F。3(N F))3)すべての数値は次のように表現される4、教会数字


(n f->3 (n f))読むべきじゃないn-1
リーキー修道女

@LeakyNun No. (n f->3 (n f))は、教会の数字で 3を掛ける関数です。
アンデルスカセオルグ

2
この課題は、ラムダ計算では非常に単純に思えます。どうして?

3

プロローグ(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).

Grahamの番号を出力するには、クエリを実行します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コードのどこにも番号を付けずにどうやってそれをやったのですか?
リーキー修道女

@LeakyNun明確にするために編集しました。より良い?
SQB

それから、コードとバイトカウントに追加します。
リーキー修道女

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))
アンデルスカセオルグ

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

2

Mathematica、59バイト

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

±ISO 8859-1でエンコードされたときに1バイトのみを必要とする未定義の挿入演算子を使用します。詳細については、@ Martinの投稿を参照してください。Mathematica関数は引数のパターンマッチングをサポートしており、2つのベースケースを別々に定義できます。


1
Mathematicaはいつ頃ISO 8859-1を使用しましたか?
リーキー修道女

n_ ±m_:=Nest[#±(m-1)&,3,n]
リーキー修道女

2

C、114 109バイト

@thepiercingarrow(link)の回答に基づいて、私はかなり答えを下げました。ほとんどの節約は、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));}
リーキー修道女

@LeakyNunそれは本当に良いものです。ありがとう。
アルグミー

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パラメーターのデフォルト値をに設定するg63g()(パラメーターなしで)を呼び出すことで必要な出力を取得できるため、入力を受け取らない関数サブミッションの要件を満たします。

オンラインで検証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)または類似した何か?
デニス

@デニス良いキャッチ。それを修正します。
メゴ

uとの間の実際のオフセットは、vあるべきであることを意味しますg(n-1)-1
アンデルスカセオルグ

@AndersKaseorg眠い間はプログラミングをすべきではありません。これを数日ごとに再学習する必要があります。
メゴ

@AndersKaseorg将来、あなたが提案した改善/バグ修正の間違いを修正することであっても、他の人の提出物を編集しないでください。
メゴ

1

Dyalog APL、41バイト

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

テストケース:

      3u 2
7625597484987

1=⍺:3⋄1=⍵:3*⍺ちょうど1=⍵:3*⍺3=3*1)に変換できるはずです
ザカリー

1

ルビー、64バイト

Grahamの数値を計算するための理論的アルゴリズムからの借用。

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$:])/[#<:@]@.*@](テストされていない)のようなもの
リーキー修道女

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

aの値として3を想定した場合、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はそれを編集しました。ありがとう。以前のコメントは消えたようです。
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)

何らかの奇妙な理由で提案されたものが機能しなかったので、この再帰関数のウィキペディア定義を使用しました...

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:x <0が入力されないため、「if(x == 0)」ではなく「if(x)」で巧妙に置き換えられたため、さらに2 + 6 + 2バイト削り取られました(これもLeaky Nunへの称賛です)機能...右?


@LeakyNunありがとう、謝辞で答えを更新しました。
アンドレイKostyrka

ちょっと待って...今日はコードゴルフの最初の日です。学ぶべきことがたくさんあります。
アンドレイKostyrka


より多くのゴ​​ルフ、改善をご覧ください。
アンドレイ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);

2番目のケースを最初のケースに統合することができます:for n=13^nequals 3
これにより、既存のすべての回答で、数バイトを節約できます。私に2バイトを保存しました

前のバージョン、62 + 43 + 11 = 116バイト

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

PHPの3項の左結合性には、括弧...または特定のテスト順序が必要です。
これにより、括弧で囲まれた式に2バイトが保存されました。


おそらく反復的なアプローチがあり、さらにゴルフできるかもしれません...
しかし、今は時間をかけることができません。


私がセソスを知っていたか、それを今すぐ学び、翻訳する時間があれば
タイタス

@Leaky Nun:ループと追加のみに分解しました。Sesosに、あるセルの値を別のセルに追加する方法はありますか?
タイタス

@AndersKaseorg:あなたはおそらく正しい...私はそのアルゴリズムを見ると眼球に水ぶくれができました。すぐにまた見ます。
タイタス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.