n番目のハイパーオペレーションを評価する


12

私はこれが少し数学的なものであることを理解していますが、ここに行きます。

数学では、ハイパーオペレーションシーケンスは、後継者の単項演算で始まり、加算、乗算、べき乗のバイナリ演算で続行する算術演算(ハイパー演算と呼ばれる)の無限シーケンスであり、その後、シーケンスはさらにバイナリ演算を超えて進みます右結合を使用した累乗。

あなたの目標は、入力として3つの整数x、y、およびnを取り、xおよびyに対するn番目のハイパーオペレーションの結果を出力するプログラムを作成することです。

例えば

1 1 1 出力2

2 4 4 出力65536

3 3 4 出力7625597484987

  • プログラムは、コードの最短ビットで作成する必要があります。
  • STDINファイルからまたはファイルから入力を取得できます。
  • ライブラリ関数は許可されていません。
  • 入力制約:nは1以上です。

http://en.wikipedia.org/wiki/Tetrationには、これで頭を包めない場合の良い説明があります。


なにn=1x+yまたはの場合x+11 1 1返される必要があります2
ジョンドヴォルザーク

私はどこかで間違いを犯したことを知っていました:)修正、thx。
ソハムチョードリー

1
擬似コードを書いた後、実際に有効なRubyコードであることに気付きました(ほぼ:
ジョンドヴォルザーク

1
いいえ、n> = 1のみ。
ソハムチョードリー

回答:


4

ルビー、遅い、 86 84 83文字

def f x,y,n
n>1?(c=x;2.upto(y){c=f(x,c,n-1)};c):x+y
end
p f *gets.split.map(&:to_i)

ルビー、速い、 96 94 93文字

def f x,y,n
n>1?(n>2?(c=x;2.upto(y){c=f(x,c,n-1)};c):x*y):x+y
end
p f *gets.split.map(&:to_i)

最初のバージョンである方法 Iはなく加算のベースケースとしてバージョンその用途乗算を添加して、最後のテストケースでは遅すぎます。最初のバージョンは計算に時間がかかります3 3 4。2番目のものは即時型です(ネイティブIRBコンソールでは、Webバージョンは少し遅くなります)。

Rubyのいくつかの美しさがここに現れます:

ほとんどすべてのステートメントはルビーの表現です。したがって、十分な括弧が横たわっていれば、三項演算子の中にセミコロンを詰めることができます。Coffeescriptはそれを借りました。また、Rubyの「no parens required」呼び出し構文も借用しました。

暗黙の戻り値:これはクールな機能であり、前の機能に続きます。実際、関数の最後の行をで開始することは、returnゴルフをしていなくても、ラメと見なされます。

数字はルビーのオブジェクトです(オブジェクトであってもnull)。ルビーでは、整数にはメソッドtimesがあり、渡されたブロックを数回実行します。これは、Rubyの多くの反復メソッドの1つにすぎません。ここで、このuptoメソッドを使用すると、2つ以上の文字を保存timesできます。

*ここでは単項演算子がスプラット演算子です。配列を引数リストに変換します。JavascriptのFunction#applyに似ていますが、短くて優れています。

単項&は、プロシージャをブロックに変換します。一方で:to_i、シンボルである、それはかなりよくプロシージャに変換します。つまり、to_i引数を呼び出して結果を返すプロシージャになります。スタックオーバーフローの詳細。

n=3ベースケースとして使用することで、さらに高速に取得することは可能ですが、必要ないのではないかと思います。ただし、ルビーのもう1つの美しさである指数演算子のおかげで、11文字しかかかりません**。Pythonにはこの演算子がありますが、最初の演算子ではありません(@ aka.niceが指摘したように-ありがとう-Fortranには既にこの演算子がありました)。

ここで利用可能なオンラインルビーインタープリター:http : //repl.it/Ikj/1


いいですが、私はまだ3 3 4:)からの出力を待っています。それは非常に遅いです。
ソハムチョードリー

@SohamChowdhuryベースケースは追加です。乗算の基本ケースでは、非常に遅くなります(そして長くなります)。代わりにべき乗でテストすることをお勧めします;
ジョンドヴォルザーク

それは可能性が使用するメモ化までの時間を節約、それはいくつかのバイト(かなりの数を)かかるだろう
ジョンドヴォルザーク

別のバージョンを追加してください:)
Soham Chowdhury

1
演算子**は50年代にFORTRANにすでに存在し、ALGOLは上向き矢印で1文字少なくなります
-aka.nice

6

APL、62

{1=3⌷⍵:2⌷+\⍵⋄0=2⌷⍵:(⍵[3]⌊3)⌷⍵[1],0,1⋄∇⍵[1],(∇⍵-0 1 0),3⌷⍵-1}⎕

{...}⎕:評価された入力(スペースで区切られた数値は数値配列に評価されます)を受け取り、それに関数を適用します。

1=3⌷⍵::nが1に等しい場合...
2⌷+\⍵:最初の2要素の合計(x + y)を返す
⋄0=2⌷⍵:...
(⍵[3]⌊3)⌷⍵[1],0,1:yが0に等しい場合... :数値配列[x、0,1]を作成し、インデックスを返すmin(n,3)...
⋄∇⍵[1],(∇⍵-0 1 0),3⌷⍵-1:それ以外の場合は、∇(x、∇(x、y-1、n)、n-1)を返します。(∇は自己参照です)


関数を受け取り、次のハイパーオペレーションを返す「ハイパーレイザー」演算子を持っています

{⍺⍺/⊃⍴/⌽⍵}

たとえば+{⍺⍺/⊃⍴/⌽⍵}、乗算関数であり、+{⍺⍺/⊃⍴/⌽⍵}5 315です。

しかし、再帰させることはできません。たぶん他の誰かがそれを行うことができます。


ああ、APL。シンプルさのためにいつでもPythonを打ち負かす。</ sarcasm>これを実行するにはどうすればよいですか?
ソハムチョードリー

2

Python、83

flornquakeの回答に基づく)

def h(x,y,n):r=n>2;exec"r=h(x,r,n-1);"*y*(n>1);return(x+y,r)[n>1]
print h(*input())

大きな結果の場合は非常に遅くなります。

2, 4, 4出力についてはです65536


「非常に遅い」が、私の86文字のソリューションが悪いと見なされた理由です。
ジョンドボラック

1
@JanDvorak:なぜそれが悪いと考えられたと思いますか?Soham Chowdhuryは、それが遅いため、ソリューションを置き換えるのではなく、別のバージョンを追加する必要があると述べました。(しかし、私はそれを誤解したかもしれません。)
モニカを復活させる

あなたが正しい; ショートバージョンを復元しました。今、私はあなたよりも長いチャーです。
ジョンドボラック

@WolframH正確に。常にバージョンがあると便利です。
ソハムチョードリー

2

Python、96 92

def h(x,y,n):r=1;exec(n>2)*y*"r=h(x,r,n-1);";return(r,(x+y,x*y)[n>1])[n<3]
print h(*input())

入力:3, 3, 4
出力:7625597484987

@WolframHのアイデアをいくつか使用して短縮しました。


2

Golfscript、遅い、39文字

 ~{\(.{3${[4$\2$4$.~}4$(*}{;;+}if])\;}.~

(ライブリンク)

これは、n = 1(追加)(つまり遅い)の基本ケースを持つ標準的な再帰アルゴリズムです。Rubyソリューションで使用したものと同じ

これが私の注釈付きのバージョンです(主にスタック保持)。後で追加した最適化は含まれていません。

~{            #read the input and do (x y n f)
 \(.{         #(x y f n-1); if(n-1)
  3${         #(x y f n-1 c)
   4$\2$4$.~  #(x y f n-1 x c n-1 f); call
  }3$(*       #y-1 times
  {\;}4*
 }{           #else
  ;;+         #return (x+y)
 }if
}.~           #once

~eval演算子です。文字列の場合、文字列をGolfScriptプログラムとして扱います。幸いなことに、スペースで区切られた整数のリストは、それらの整数をスタックにプッシュする有効なGolfScriptプログラムです。これと比較して、入力ルーチンの以前のバージョン(" "/{~}/、スペースで分割し、それぞれを評価する)はかなり不自由です。関数の場合、関数を呼び出します。.(クローン)が前に付いている場合、それ自体を最初の引数として関数を呼び出します。

Golfscriptは、再帰的なアルゴリズムを作成するのに適しているとは思えません。末尾呼び出しを最適化できない再帰アルゴリズムが必要な場合は、スタックフレームを作成および破棄して変数を保存する必要があります。ほとんどの言語では、これは自動的に行われます。golfscriptでは、実際に変数(実際には、スタックエントリ)を複製し、不要になったスタックエントリを破棄する必要があります。Golfscriptにはスタックフレームの概念はありません。GolfScriptはスタックベースの言語だと言ったことがありますか?

最初の要件は理解できます。なんらかの方法で引数を指定する必要があります。彼らが元の位置を保持している場合にのみ素晴らしいです。2番目の要件は、特に戻り値がスタックの一番上にあり、golfscriptにはスタック要素だけを削除する機能がないため、残念です。スタックを回転させて新しい最上部の要素を破棄することもできますが、それはすぐに蓄積されます。\;結構です。\;\;\;\;\;そうではありません。\;ループで実行できます({\;}9*;コスト:最大9個の要素を破棄するには6文字、最大99個の要素を破棄するには7文字)。

Golfscriptには一流の配列があります。配列リテラル構文もあります[1 2 3 4]。予期しないことはそれ[]あり、実際には構文の一部ではありません。これらは単なる2つの演算子です。[スタック上の現在の位置をマークし、]配列の開始マークを見つけるかスタックを使い果たすまですべての要素を収集し、マークを破棄します。これら2つを引き裂いて、何が起こるかを見ることができます。まあ、非常に興味深いこと:

golfscriptにはスタックフレームの概念がないと言いましたか?私は嘘をついた。これはスタックフレームです[。一度にすべて破棄できます];。しかし、戻り値を保持したい場合はどうでしょうか?関数エントリでスタックフレームを閉じることができます(その後、配列によるパスのわずかにマングルされたバージョンがあります-興味深い概念ではありません)、またはスタックフレームを閉じて、完全に破棄する代わりに最後の要素を取ることができます:]-1=またはunconsは最後の要素の代わりに、とすることができ、その後のフレームを破棄します:])\;。それらは同じ長さですが、後者はわずかに涼しいので、私はそれを使用しています。

したがって、クリーンアップを行うための6または7キャラクターの代わりに、5で行うことができます。


再帰のための面白いアイデア- 「最初の引数としての地位を持つ関数を呼び出す」
SEは悪であるため、aditsuはやめ

1

Smalltalk Squeak 4.xフレーバーの多くのバイト!

71文字の整数で再帰形式の1つを実装できました

f:y n:n n=1or:[^(2to:y)inject:self into:[:x :i|self f:x n:n-1]].^self+y

次に、ファイルまたはFileStreamの標準入力から読み取ると、コストがかかります... Squeakは明らかにスクリプト言語として設計されていません。そのため、問題に関係のない独自の汎用ユーティリティを作成するために多くのバイトを費やします。

この21文字のメソッドをStreamに実装します(シーパレーターをスキップするため)

s self skipSeparators

Behaviorでこの20文字のメソッドを実装します(Streamからインスタンスを読み取るため)

<s^self readFrom:s s

次に、文字列に28文字(ファイルハンドルを作成するため)

f^FileDirectory default/self

次に、FileDirectoryに59文字(readStreamを作成するため)

r^FileStream concreteStream readOnlyFileNamed:self fullName

次に、BlockClosureで33文字(n回評価するため)

*n^(1to:n)collect:[:i|self value]

次に、63文字の配列(引数をレシーバーで評価し、引数を配列から取得)

`s^self first perform:s asSymbol withArguments:self allButFirst

次に、この31文字スニペットを評価してxという名前のファイルから読み取ることで問題を解決します

|s|s:='x'f r.[0class<s]*3`#f:n:

ユーティリティを数えなくても、それはすでに71 + 31 = 102文字です...

今、私はcodeGolfを失うことを確信しているので、私は整数で面白い実装をしています:

doesNotUnderstand:m
    (m selector allSatisfy:[:c|c=$+])or:[^super doesNotUnderstand:m].
    self class compile:
        m selector,'y y=0or:[^(2to:y)inject:self into:[:x :i|self'
        ,m selector allButLast,'x]].^'
        ,(Character digitValue:()asBit)
        ,(m selector size-2min:1)hex last.
    thisContext sender restart

このメソッドは、n +で構成されるバイナリメッセージが存在しない場合(メッセージmの受信者に認識されない場合)を定義(コンパイル)し、送信者コンテキストの先頭から実行を再開します。読みやすくするために、追加のキャリッジリターンとスペースを挿入しました。

(m selector size-2min:1)hex lastはの短縮形であることに注意してください(m selector size>2)asBit printString

Smalltalkの邪悪な超大国を示すことではない場合、最後のステートメントをより短くシンプルなものに置き換えることができます。

^m sendTo:self

Characterに28文字のユーティリティを実装します(Stringでn回繰り返す)

*n^String new:n withAll:self

次に、この43文字の式を評価します。

|i s|i:=0class.s:='x'f r.[i<s]*2`($+*(i<s))

整数で実装することにより、さらに10文字で加速できます。

++y^self*y

この場合、次のコードで置き換えることができるため^',(m selector size-2min:1)hex last、コードも短くなります。^1'

このような高価格の場合、コードは2番目の整数= 0で動作します:)


0

グルーヴィー-77

h={x,y,n->n<2?x+y:y<2?x:h(x,h(x,y-1,n),n-1)}
print h(args.collect{it as int})

注:非小さな引数にはわいせつな量のスタック(および時間)が必要です。


0

AXIOMコンピューター代数システム、バイト69

p(x,y,n)==(n<=1=>y+x^n;n=2=>y*x;n=3=>x^y;y<=0=>1;p(x,p(x,y-1,n),n-1))

テスト:

(2) -> p(1,1,1)
   (2)  2
                                                 Type: Expression Integer
                                   Time: 0.05 (IN) + 0.03 (OT) = 0.08 sec
(3) -> p(2,4,4)
   (3)  65536
                                                 Type: Expression Integer
                                                              Time: 0 sec
(4) -> p(3,3,4)
   (4)  7625597484987
                                                 Type: Expression Integer
                                                              Time: 0 sec

これはいくつかの再帰を排除します...私はいくつかのリターンでxとyを交換する可能性があります...他のテスト値はありますか?


0

APL(NARS)、文字61、バイト122

{(x y n)←⍵⋄n≤1:y+x*n⋄n=2:x×y⋄n=3:x*y⋄y≤0:1⋄∇x,(∇x(y-1)n),n-1}

テスト:

  h←{(x y n)←⍵⋄n≤1:y+x*n⋄n=2:x×y⋄n=3:x*y⋄y≤0:1⋄∇x,(∇x(y-1)n),n-1}
  h 1 1 1
2
  h 2 4 4
65536
  h 3 4 4
∞
  h 3 3 4
7625597484987
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.