49

チャレンジ

Fractranインタープリターとして機能するプログラムを作成します。どの言語でも、文字数で最も短い通訳者が勝者です。プログラムは、実行するフラクトランプログラムと入力整数nの2つの入力を受け取る必要があります。プログラムは、プログラムに便利な任意の形式にすることができます。たとえば、2タプルのリスト、またはフラットリストなどです。出力は、実行終了時のレジスタの値である単一の整数である必要があります。

フラクトラン

Fractranは、JohnConwayによって発明された簡単な難解言語です。フラクトランプログラムは、正の分数のリストと初期状態nで構成されます。インタプリタはプログラムカウンタを維持し、最初はリストの最初の部分を指します。Fractranプログラムは、次の方法で実行されます。

  1. 現在の状態と現在プログラムカウンターの下にある分数の積が整数であるかどうかを確認します。そうである場合は、現在の状態に現在の端数を掛けて、プログラムカウンターをリストの先頭にリセットします。
  2. プログラムカウンターを進めます。リストの最後に達した場合は停止し、そうでない場合は手順1に戻ります。

Fractranが機能する方法と理由の詳細については、esolangエントリと良い数学/悪い数学に関するこのエントリを参照してください。

テストベクトル

プログラム: [(3、2)]
入力: 72(2 3 3 2
出力: 243(3 5

プログラム: [(3、2)]
入力: 1296(2 4 3 4
出力: 6561(3 8

プログラム: [(455、33)、(11、13)、(1、11)、(3、7)、(11、2)、(1、3)]
入力: 72(2 3 3 2
出力: 15625(5 6

ボーナステストベクトル:

あなたの提出物は、受け入れられる答えであるためにこの最後のプログラムを正しく実行する必要はありません。しかし、もしそうなら賞賛!

プログラム: [(455、33)、(11、13)、(1、11)、(3、7)、(11、2)、(1、3)]
入力: 60466176(2 10 3 10
出力: 7888609052210118054117285652827862296732064351090230047702789306640625(5100

提出物と採点

プログラムは文字の長さで厳密にランク付けされます-最短が最適です。うまくレイアウトされ、文書化されたバージョンと「縮小された」バージョンのコードの両方を自由に提出して、人々が何が起こっているかを確認できるようにしてください。

言語「J」は許容されません。これは、リンクされたページの1つにJですでによく知られている解決策があるためです。Jファンならごめんなさい!

ただし、追加のボーナスとして、フラクトランで実用的なフラクトラン通訳を提供できる人は誰でも、500レピュテーションポイントのボーナスを受け取ります。万が一、複数のセルフホスティング通訳者がいる場合は、端数が最も少ない通訳者がバウンティを受け取ります。

勝者

1779の分数を含む自己ホスティングフラクトランソリューションを提出した後の公式の勝者は、JesseBederのソリューションです。ただし、実際には、ソリューションは遅すぎて1+1でも実行できません。

信じられないことに、これはその後、別のフラクトランソリューション(わずか84分数のAmadaeusのソリューション)によって打ち負かされました!私のリファレンスPythonソリューションで実行すると、最初の2つのテストケースを数秒で実行できます。分数には新しいエンコード方法を使用しており、これもよく見る価値があります。

名誉ある言及:

4

25 に答える 25

45

フクトラン - 1779 フラクション

(編集:修正済み)

(これには時間がかかったので、人々がまだこのスレッドをフォローしていることを願っています!)

SOはこれまで何かを投稿することを許可していないようですので、Fractranのソースをここに投稿しました.

入力は次のように指定されます。

まず、分数を次のようにエンコードm/n = p_0^a0... p_k^akします。

  • 1 から始めます。次に、それぞれについてai:
  • p_2i^aiifを掛けるai > 0
  • p_2i+1^{-ai}ifを掛けるa_i < 0

このようにして、任意の分数を正の整数としてエンコードします。ここで、プログラム (エンコードされた分数 F0、F1、... のシーケンス) が与えられると、それを次のようにエンコードします。

p_0^F0 p1^F1 ...

最後に、インタプリタへの入力は次のように与えられます。

2^(program) 3^(input) 5

whereprograminputは上記のようにエンコードされます。たとえば、最初のテスト問題では、3/2にエンコードされる15ため、プログラムは にエンコードされ2^15ます。に108エンコードされ500ます。だから、私たちは渡します

2^{2^15} 3^500 5

プログラムに。出力は次の形式になります

2^(program) 3^(output)

最初の例では、

2^{2^15} 3^3125

それはどのように機能しますか?

Fractran にコンパイルされるメタ言語を書きました。関数 (単純な Fractran と他の関数のシーケンス)、およびwhileループとifステートメント (便宜上!) を使用できます。そのためのコードはここにあります。

そのコードを自分で Fractran にコンパイルしたい場合は、私の (C++) プログラムが[tar.gz]にあります。ドッグフーディング (および誇示) の見事な表示では、C++ YAML パーサーyaml-cppを使用したので、ダウンロードしてリンクする必要があります。yaml-cpp と「コンパイラ」の両方で、クロスプラットフォームの makefile 生成用にCMakeが必要です。

このプログラムの使用法は次のとおりです。

./fracc interpreter.frp

これは、標準入力から関数の名前を読み取り、対応する「疑似分数」(すぐに説明します) を標準出力に書き込みます。したがって、インタープリター (Interpret 関数) をコンパイルするには、次のように実行できます。

echo "Interpret" | ./fracc interpreter.frp > interpret

出力 ("pseudo-Fractran") は一連の行で、それぞれにスペースで区切られた数字の文字列があります。行は分数に対応します。n行の 1 桁目が の場合an、分数は の積ですp_n^an

これを Fractran に変換するのは非常に簡単ですが、面倒な場合はto-fractions.pyを使用できます。[: 以前は C++ プログラムを使用していましたが、不用意に整数オーバーフローを無視していました。これを避けるためにPythonに翻訳しました。]

入力に関する注意: この方法で別の関数をテストする場合、規則は常に同じです。疑似Fractranにはいくつかのパラメータがあります(通常、関数の上のコメントで説明されています)。したがって、必要なものを与え、さらに1次のスロットに a を加えます(通常のFractranでは、勝った最初の素数を1回掛けます)使用しません)。これは、機能を開始するための「シグナル」ビットです。


でも、

実際に Fractran インタープリターを実行しようとすることはお勧めしません (悲しいかな)。私はそのコンポーネントの多くをテストしました。たとえば、IncrementPrimes素数のペアを取り、次の 2 つの素数を返す関数 は、愚かな C++ インタープリターを使用して実行するのに約8 分かかります (それを投稿する必要はありません :)。さらに、関数呼び出しの数は (少なくとも) 二次関数になります。関数呼び出しの数を 2 倍にすると、少なくとも 4 倍の時間がかかります (whileループやifステートメントがある場合はさらに長くなります)。したがって、インタープリターの実行には、数年ではないにしても、少なくとも数日かかると思います:(

では、どうすればそれが機能するかを知ることができますか? もちろん、100%確実ではありませんが、かなり近いと思います。まず第一に、私は非常に多くのコンポーネントをテストしました。特に、メタ言語のすべての要素 (関数ifwhileステートメントのシーケンス) を非常に徹底的にテストしました。

また、メタ言語は、関数のすべてのパラメーターが参照によって渡されるため、お気に入りの言語に簡単に翻訳でき、C++ に簡単に翻訳できます。また怠けている場合は、私の翻訳をここ[tar.gz] からダウンロードできます (makefile はありません。2 つの .cpp ファイルだけなので、gcc を直接呼び出しても問題ありません)。

したがって、2 つのインタープリターを比較し、C++ バージョンを実行して (疑似 Fractran での入出力も受け取ります)、それが機能することを確認してから、メタ言語も機能することを確信できます。


または!

インスピレーションを得て、このインタープリターが解釈されるのを本当に見たい場合は、取得する Fractran 出力のタイプに基づいて「賢い」Fractran インタープリターを作成できます。出力は非常に構造化されています。関数のシーケンスはシグナルを使用して実装されているため、インタープリターがあった場所を何らかの方法でキャッシュすると、重要な変更がなければすぐにそこにジャンプできます。これにより、プログラムが劇的に高速化されると思います (おそらく、実行時間が 1 つまたは複数の累乗で削減されます)。

しかし、これを行う方法がよくわかりません。完了したことに満足しているので、読者の演習として残しておきます。

于 2009-11-20T23:28:59.997 に答える
41

フラクトラン:84分数

FTEVAL = [197*103/(2^11*101), 101/103, 103*127/(2*101), 101/103, 109/101,
  2*23/(197*109), 109/23, 29/109,197*41*47/(31*59), 11^10*53/(127*197), 197/53,
  37/197, 7^10*43/(11^10*37), 37/43, 59/(37*47), 59/47, 41*61/59, 31*67/(41*61),
  61/67, 7*67/(127*61), 61/67,101/71, 73/(127^9*29), 79/(127^2*73),
  83/(127*73), 89/(2*29), 163/29, 127^11*89/79, 337/83, 2*59/89, 71/61,
  7*173/(127*163), 163/173, 337*167/163, 347/(31*337), 337/347, 151/337,
  1/71,19*179/(3*7*193), 193/179, 157/(7*193), 17*181/193, 7*211/(19*181),
  181/211, 193/181, 157/193, 223/(7*157), 157/223, 281*283/239,
  3*257*269/(7*241), 241/269, 263/241, 7*271/(257*263), 263/271, 281/263,
  241/(17*281), 1/281, 307/(7*283), 283/307, 293/283, 71*131/107, 193/(131*151),
  227/(19*157), 71*311/227, 233/(151*167*311), 151*311/229, 7*317/(19*229),
  229/317, 239*331/217, 71*313/157, 239*251/(151*167*313), 239*251/(151*313),
  149/(251*293), 107/(293*331), 137/199, 2^100*13^100*353/(5^100*137),
  2*13*353/(5*137), 137/353, 349/137, 107/349, 5^100*359/(13^100*149),
  5*359/(13*149), 149/359, 199/149]

これは完全に手書きです。私は物事をより明確に表現できるように疑似言語を作成しましたが、コンパイラーを作成せず、最適化されたFractranコードを直接作成することを選択しました。

FTEVALは入力を受け取り3^initial_state * 5^encoded_program * 199、中間結果を生成3^interpreted_program_state * 199し、で割り切れる数で完全に停止し233ます。

解釈されたプログラムは、単一の基数11の数字の中に基数10の数字のリストとして埋め込まれ、最後を除いて境界を示すために数字「a」を使用します。追加プログラム[3/2]は次のようにエンコードされます

int("3a2", 11) = 475.

乗算プログラム[455/33、11 / 13、1 / 11、3 / 7、11 / 2、1/3]は次のようにエンコードされます。

int("1a3a11a2a3a7a1a11a11a13a455a33", 11) = 3079784207925154324249736405657

これは本当に大きな数です。

最初のテストベクトルは1秒未満で終了し、4545回の反復後に目的の結果を生成し、6172回の反復後に停止しました。これが完全な出力です。

残念ながら、2番目のテストベクトルを試したときにsageは失敗しました(ただし、プライム指数ベクトルを使用したNickの実装では機能すると思います)。

ここのスペースは本当に小さすぎてすべてを説明できません。しかし、これが私の擬似コードです。うまくいけば、私は数日以内に私のプロセスを書き留めます。

# Notations:
# %p
#     designates the exponent of prime factor p that divides the
#     current state.
# mov x y
#     directly translates to the fraction y/x; its meaning: test if x divides
#     the current state, if so divide the current state by x and multiply it by
#     y.  In effect, the prime exponents of x and y are exchanged.  A Fractran
#     program only comprises of these instructions; when one is executable, the
#     program continues from the beginning.
# dec x => mov x, 1
#     wipes out all factors of x
# inc x => mov 1, x
#     this form is here for the sake of clarity, it usually appears in a
#     loop's entry statement and is merged as such when compiled
# sub n ret m {...}
#     conceptually represents a Fractran sub-program, which will execute just
#     like a normal Fractran program, that is, the sub-program's statements
#     execute when triggered and loop back.  The sub-program only exits when none of
#     its statement is executable, in which occasion we multiply the program's
#     state by m.  We can also explicitly break out early on some conditions.
#     It is also possible to enter a sub-prorgram via multiple entry points and
#     we must take care to avoiding this kind of behavior (except in case where
#     it is desirable).

# entry point 101: return 29
# Divide %2 modulo 11:
#   - quotient is modified in-place
#   - remainder goes to %127
sub 101 ret 101 { mov 2^11, 197 }
sub 101 ret 109 { mov 2, 127 }
sub 109 ret 29 { mov 197, 2 }

# entry point 59: return 61
# Multiply %127 by 10^%31 then add result to %7,
# also multiply %31 by 10 in-place.
sub 59 ret 41*61 {
  mov 31, 197*41
  sub 197 ret 37 { mov 127, 11^10 }
  sub 37 { mov 11^10, 7^10 }
}
sub 61 ret 61 { mov 41, 31 }
sub 61 ret 61 { mov 127, 7 } # the case where %31==0

# entry point 71: return 151 if success, 151*167 if reached last value
# Pop the interpreted program stack (at %2) to %7.
sub 71 {
  # call sub 101
  inc 101

  # if remainder >= 9:
  mov 29*127^9, 73
  #     if remainder == 11, goto 79
  mov 73*127^2, 79
  #     else:
  #         if remainder == 10, goto 83
  mov 73*127, 83
  #         else:
  #             if quotient >= 1: goto 89
  mov 29*2, 89
  #             else: goto 163
  mov 29, 163

  # 79: restore remainder to original value, then goto 89
  mov 79, 127^11*89

  # 83: reached a border marker, ret
  mov 83, 337

  # 89: the default loop branch
  # restore quotient to original value, call 59 and loop when that rets
  mov 2*89, 59
  mov 61, 71

  # 163: reached stack bottom,
  # ret with the halt signal
  sub 163 ret 337*167 { mov 127, 7 }

  # 337: clean up %31 before ret
  sub 337 ret 151 { dec 31 }
}

# entry point 193, return 157
# Divide %3 modulo %7:
#   - quotient goes to %17
#   - remainder goes to %19
sub 193 ret 17*181 {
  mov 3*7, 19
}
mov 7*193, 157
sub 181 ret 193 { mov 19, 7 }
mov 193, 157
sub 157 ret 157 { dec 7 }

# entry point 239: return 293
# Multiply %17 by %7, result goes to %3
mov 239, 281*283
sub 241 { mov 7, 3*257 }
sub 263 ret 281 { mov 257, 7 }
mov 281*17, 241
sub 283 ret 293 { dec 7 }

# entry point 107: return 149 if success, 233 if stack empty
# Pop the stack to try execute each fraction
sub 107 {
  # pop the stack
  inc 71*131

  # 151: popped a value
  # call divmod %3 %7
  mov 131*151, 193

  # if remainder > 0:
  mov 19*157, 227
  #     pop and throw away the numerator
  mov 227, 71*311
  #     if stack is empty: halt!
  mov 151*167*311, 233
  #     else: call 239 to multiply back the program state and gave loop signal
  mov 151*311, 229
  sub 229 ret 239*331 { mov 19, 7 }
  # else: (remainder == 0)
  #     pop the numerator
  mov 157, 71*313
  #     clear the stack empty signal if present
  #     call 239 to update program state and gave ret signal
  mov 151*167*313, 239*251
  mov 151*313, 239*251

  # after program state is updated
  # 313: ret
  mov 293*251, 149
  # 331: loop
  mov 293*331, 107
}

# main
sub 199 {
  # copy the stack from %5 to %2 and %13
  sub 137 ret 137 { mov 5^100, 2^100*13^100 }
  sub 137 ret 349 { mov 5, 2*13 }

  # call sub 107
  mov 349, 107

  # if a statement executed, restore stack and loop
  sub 149 ret 149 { mov 13^100, 5^100 }
  sub 149 ret 199 { mov 13, 5 }
}
于 2009-11-26T09:27:22.410 に答える
20

x86_64 アセンブリ、165 文字 (28 バイトのマシン コード)。

状態は %rdi で渡され、プログラム (null で終わる分数の配列へのポインター) は %rsi で渡されます。結果は、通常の C スタイルの呼び出し規約に従って %rax で返されます。非標準の呼び出し規則または Intel 構文 (これは AT&T 構文です) を使用すると、さらにいくつかの文字が削除されますが、私は怠け者です。他の誰かがそれを行うことができます。制御フローを再配置することで、ほぼ確実に 1 つまたは 2 つの命令を節約できます。

中間計算 (状態 * 分子) は 128 ビット幅まで可能ですが、サポートされているのは 64 ビット状態のみです。

_fractran:
0:  mov     %rsi,   %rcx    // set aside pointer to beginning of list
1:  mov    (%rcx),  %rax    // load numerator
    test    %rax,   %rax    // check for null-termination of array
    jz      9f              // if zero, exit
    mul     %rdi
    mov   8(%rcx),  %r8     // load denominator
    div     %r8
    test    %rdx,   %rdx    // check remainder of division
    cmovz   %rax,   %rdi    // if zero, keep result
    jz      0b              // and jump back to program start
    add     $16,    %rcx    // otherwise, advance to next instruction
    jmp     1b
9:  mov     %rdi,   %rax    // copy result for return
    ret

_fractran最小化されたバージョンのコメント、余分な空白、冗長ラベルを削除します。

于 2009-11-17T17:49:31.590 に答える
16

ルビー、58 57 56 5352文字

初めてのコードゴルフエントリーですのでお手柔らかにお願いします。

def f(n,c)d,e=c.find{|i,j|n%j<1};d ?f(n*d/e,c):n end

使用法:

irb> f 108, [[455, 33], [11, 13], [1,11], [3,7], [11,2], [1,3]]
=> 15625

irb> f 60466176, [[455, 33], [11, 13], [1, 11], [3, 7], [11, 2], [1, 3]]
=> 7888609052210118054117285652827862296732064351090230047702789306640625

きれいなバージョン (252):

def fractran(instruction, program)
  numerator, denominator = program.find do |numerator, denominator|
    instruction % denominator < 1
  end

  if numerator
    fractran(instruction * numerator / denominator, program)
  else
    instruction
  end
end

ルビー、5352 合理的な使用

gnibbler のソリューションに触発されて、Rational を使用してソリューションを得ることができました。5352文字。上記の(あまりエレガントではない)ソリューションよりもさらに1つ長くなります。

def f(n,c)c.map{|i|return f(n*i,c)if i*n%1==0};n end

使用法:

irb> require 'rational'
irb> f 60466176, [Rational(455, 33), Rational(11, 13), Rational(1, 11), Rational(3, 7), Rational(11, 2), Rational(1, 3)]
=> Rational(7888609052210118054117285652827862296732064351090230047702789306640625, 1)

(to_iよりきれいな出力を求めると、さらに 5 文字追加されます。)

于 2009-11-17T20:00:30.937 に答える
12

ゴルフスクリプト - 32

    
    {:^{1=1$\%!}?.1={~@\/*^f}{}if}:f

    ; 108 [[3 2]] fp
    #243
    ; 1296 [[3 2]] fp
    #6561
    ; 108 [[455 33][11 13][1 11][3 7][11 2][1 3]] fp
    #15625
    ; 60466176 [[455 33][11 13][1 11][3 7][11 2][1 3]] fp
    # 7888609052210118054117285652827862296732064351090230047702789306640625
于 2009-11-18T04:37:54.753 に答える
7

Haskell、102文字

import List
import Ratio
l&n=maybe n((&)l.numerator.(n%1*).(!!)l)$findIndex((==)1.denominator.(n%1*))l
$ ghci
Prelude> :m リスト比
Prelude List Ratio> let l&n=maybe n((&)l.numerator.(n%1*).(!!)l)$findIndex((==)1.denominator.(n%1*))l
前奏曲リスト比率>[3%2]&108
243
前奏曲リスト比率> [3%2]&1296
6561
前奏曲リスト比率> [455%33,11%13,1%11,3%7,11%2,1%3]&108
15625

88 の入出力形式の制限が緩和されました。

import List
import Ratio
l&n=maybe n((&)l.(*)n.(!!)l)$findIndex((==)1.denominator.(*)n)l
前奏曲リスト比率> let l&n=maybe n((&)l.(*)n.(!!)l)$findIndex((==)1.denominator
前奏曲リスト比率> [455%33,11%13,1%11,3%7,11%2,1%3]&108
15625% 1
于 2009-11-17T16:56:36.657 に答える
6

Python、83 82 81 72 70 文字。

fractions.Fraction オブジェクトとして入力すると便利です。Rubyソリューションと同じ考え方。

def f(n,c):d=[x for x in c if x*n%1==0];return d and f(n*d[0],c) or n

# Test code:
from fractions import Fraction as fr
assert f(108, [fr(3, 2)]) == 243
assert f(1296, [fr(3, 2)]) == 6561
assert f(108, [fr(455, 33), fr(11, 13), fr(1, 11), fr(3, 7), fr(11, 2), fr(1, 3)]) == 15625
assert f(60466176, [fr(455, 33), fr(11, 13), fr(1, 11), fr(3, 7), fr(11, 2), fr(1, 3)]) == 7888609052210118054117285652827862296732064351090230047702789306640625
于 2009-11-18T01:32:25.190 に答える
6

C , 159 153 151 131 111 110 文字

v[99],c,d;main(){for(;scanf("%d",v+c++););while(d++,v[++d])
*v%v[d]?0:(*v=*v/v[d]*v[d-1],d=0);printf("%d",*v);}
$ cc fc
$エコー108 3 2。| | ./a.out; エコー
243
$エコー1296 3 2。| | ./a.out; エコー
6561
$ echo 108 455 33 11 13 1 11 3 7 11 2 1 3 . | | ./a.out; エコー
15625
于 2009-11-17T17:30:39.723 に答える
5

F#:80文字

let rec f p=function|x,(e,d)::t->f p (if e*x%d=0I then(e*x/d,p)else(x,t))|x,_->x

match pattern with |cases代わりにを使用した拡張バージョンは次のfunctionとおりです。

//program' is the current remainder of the program
//program is the full program
let rec run program (input,remainingProgram) =
    match input, remainingProgram with
        | x, (e,d)::rest -> 
            if e*x%d = 0I then //suffix I --> bigint
                run program (e*x/d, program) //reset the program counter
            else    
                run program (x, rest) //advance the program
        | x, _ -> x //no more program left -> output the state   

テストコード:

let runtests() = 
    [ f p1 (108I,p1) = 243I
      f p1 (1296I,p1) = 6561I
      f p2 (108I,p2) = 15625I
      f p2 (60466176I,p2) = pown 5I 100] 

そして結果(F#インタラクティブでテスト済み):

> runtests();;
val it : bool list = [true; true; true; true]

編集これをもっと楽しんで、いくつかの素数を計算しましょう(最初の投稿のリンクされたページを参照してください)。g状態の中間値を生成する新しい関数を作成しました。

//calculate the first n primes with fractran
let primes n = 
    let ispow2 n = 
        let rec aux p = function
            | n when n = 1I -> Some p
            | n when n%2I = 0I -> aux (p+1) (n/2I)
            | _ -> None
        aux 0 n

    let pp = [(17I,91I);(78I,85I);(19I,51I);(23I,38I);(29I,33I);(77I,29I);(95I,23I); 
              (77I,19I);(1I,17I);(11I,13I);(13I,11I);(15I,14I);(15I,2I);(55I,1I)]

    let rec g p (x,pp) =
        seq { match x,pp with 
                |x,(e,d)::t -> yield x
                               yield! g p (if e*x%d=0I then (e*x/d,p) else (x,t))
                |x,_ -> yield x }

    g pp (2I,pp)
    |> Seq.choose ispow2
    |> Seq.distinct
    |> Seq.skip 1 //1 is not prime
    |> Seq.take n
    |> Seq.to_list

最初の10個の素数を咳き込むのになんと4.7秒かかります。

> primes 10;;
Real: 00:00:04.741, CPU: 00:00:04.005, GC gen0: 334, gen1: 0, gen2: 0
val it : int list = [2; 3; 5; 7; 11; 13; 17; 19; 23; 29]

これは間違いなく、私がこれまでに書いた中で最も奇妙で遅い素数ジェネレータです。それが良いことなのか悪いことなのかわかりません。

于 2009-11-18T15:06:16.627 に答える
5

パイソン - 53

ポールのおかげで改善

f=lambda n,c:next((f(n*x,c)for x in c if x*n%1==0),n)

テストケース

from fractions import Fraction as fr
assert f(108, [fr(3, 2)]) == 243
assert f(1296, [fr(3, 2)]) == 6561
assert f(108, [fr(455, 33), fr(11, 13), fr(1, 11), fr(3, 7), fr(11, 2), fr(1, 3)]) == 15625
assert f(60466176, [fr(455, 33), fr(11, 13), fr(1, 11), fr(3, 7), fr(11, 2), fr(1, 3)]) == 7888609052210118054117285652827862296732064351090230047702789306640625

Python - 54 分数を使用しない

f=lambda n,c:next((f(n*i/j,c)for i,j in c if n%j<1),n)

パイソン - 55

これはやや理論的です。最初の 2 つのケースは正常に実行されますが、他の 2 つのケースは再帰の深さから失敗します。多分誰かがジェネレーター式で動作させることができます

f=lambda n,c:([f(n*i/j,c)for i,j in c if n%j<1]+[n])[0]

ここに 1 つの可能性がありますが、インポートを含めなくても 65 に増加します

from itertools import chain
f=lambda n,c:(chain((f(n*i/j,c)for i,j in c if n%j<1),[n])).next()
于 2009-11-18T07:51:08.623 に答える
4

Javascriptの1つ:99文字。ボーナスベクトルなし:(

function g(n,p,q,i,c){i=0;while(q=p[i],c=n*q[0],(c%q[1]?++i:(n=c/q[1],i=0))<p.length){};return n;};

入力はの形式です[[a,b],[c,d]]。私はJavascriptの寛大さを利用しました。実行する代わりにvar x=0, y=0;、必要な数のパラメーターを追加できます。デフォルトでは。であるため、実際に渡すかどうかは関係ありませんnull

きれいなバージョン:

関数g(n、p){
    var q、c、i = 0;
    while(i <p.length){
        q = p [i];
        c = n * q [0];
        if(c%q [1]!= 0){
            ++ i;
        } そうしないと {
            n = c%q [1];
            i = 0;
        }
    }
    nを返します。
};
于 2009-11-18T07:41:45.587 に答える
4

C#:

きちんとしたバージョン:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            int ip = 1;
            decimal reg = Convert.ToInt32(args[0]);
            while (true)
            {
                if (ip+1 > args.Length)
                {
                    break;
                }
                decimal curfrac = Convert.ToDecimal(args[ip]) / Convert.ToDecimal(args[ip+1]);
                if ((curfrac * reg) % 1 == 0)
                {
                    ip = 1;
                    reg = curfrac * reg;
                }
                else
                {
                    ip += 2;
                }
            }
            Console.WriteLine(reg);
            Console.ReadKey(true);
        }
    }
}

バージョンを201 文字に減らします (名前空間の宣言などはなく、単一の using ステートメント (システムではなく) と Main 関数のみ):

using System;namespace T{using b=Convert;static class P{static void Main(string[] a){int i=1;var c=b.ToDecimal(a[0]);while(i+1<=a.Length){var f=b.ToDecimal(a[i])/b.ToDecimal(a[i+1]);if((f*c)%1==0){i=1;c*=f;}else{i+=2;}}Console.Write(c);}}}

例 (コマンドライン引数による入力):

input: 108 3 2
output: 243.00
input: 1296 3 2
output: 6561.0000
input: 108 455 33 11 13 1 11 3 7 11 2 1 3
output: 45045.000000000000000000000000
于 2009-11-18T06:18:10.587 に答える
4

Python、110 103 95 87 文字

frc.py

def f(n,c):
 d=c
 while len(d):
  if n%d[1]:d=d[2:]
  else:n=d[0]*n/d[1];d=c
 return n

test.py

(運転方法を示します)

from frc import f
def test():
 """
 >>> f(108, [3,2])
 243
 >>> f(1296, [3,2])
 6561
 >>> f(108, [455,33,11,13,1,11,3,7,11,2,1,3])
 15625
 >>> f(60466176, [455, 33,11, 13,1, 11,3, 7,11, 2,1, 3])
 7888609052210118054117285652827862296732064351090230047702789306640625L
 """
 pass
import doctest
doctest.testmod()
于 2009-11-17T17:54:26.593 に答える
2

ハスケル:116109文字

f p x[]=x
f p x((n,d):b)|x*n`mod`d==0=f p(x*n`div`d)p|True=f p x b
main=do{p<-readLn;x<-readLn;print$f p x p}

これは、ダリオのエントリの模造品のようなものになりました。

于 2009-11-18T12:34:27.890 に答える
2

ルア:

きちんとしたコード:

a=arg;
ip=2;
reg=a[1];
while a[ip] do
    curfrac = a[ip] / a[ip+1];
    if (curfrac * reg) % 1 == 0 then
        ip=2;
        reg = curfrac * reg
    else
        ip=ip+2
    end
end
print(reg)

98文字のコンパクトなコード(私の他の回答でScoregraphicによって提案された削減、およびgwellによってさらに提案された削減):

a=arg i=2 r=a[1]while a[i]do c=a[i]/a[i+1]v=c*r if v%1==0 then i=2 r=v else i=i+2 end end print(r)

次のように、最初に基数を指定してから、スペースで区切られた数値として示される一連の分数を指定して、コマンド ラインから実行します。

C:\Users\--------\Desktop>fractran.lua 108 3 2
243
C:\Users\--------\Desktop>fractran.lua 1296 3 2
6561
C:\Users\--------\Desktop>fractran.lua 108 455 33 11 13 1 11 3 7 11 2 1 3
15625

(コマンドラインから何かを取得するのは面倒なので、その一部を手動で入力しましたが、それが返された結果です)

悲しいことにボーナスベクトルを処理しません:(

于 2009-11-18T05:42:07.150 に答える
2

Groovy136 117 107 文字。

groovy として呼び出す fractal.groovy [入力状態] [数値のリストとしてのプログラム ベクトル]

a=args.collect{it as int}
int c=a[0]
for(i=1;i<a.size;i+=2) if(c%a[i+1]==0){c=c/a[i+1]*a[i];i=-1}
println c

サンプル

bash$ groovy fractal.groovy 108 455 33 11 13 1 11 3 7 11 2 1 3
Output: 15625
于 2009-11-17T16:57:42.443 に答える
2

Python での参照実装

この実装は素因数分解で動作します。

最初に、分子と分母を (idx, value) タプルのリストとしてエンコードすることにより、分数タプルのリストをデコードします。ここで、idx は素数の数です (2 は素数 0、3 は素数 1 など)。

現在の状態は、インデックスごとの各素数の指数のリストです。命令を実行するには、最初に分母を反復処理し、インデックス付きの状態要素が少なくとも指定された値であるかどうかを確認し、一致する場合は、分母で指定された状態要素をデクリメントし、分子で指定された要素をインクリメントする必要があります。

このアプローチは、Python で大きな整数に対して算術演算を実行する場合の約 5 倍の速度であり、デバッグがはるかに簡単です!

各素数インデックス (変数) を分数の分母で最初にチェックされる時点にマッピングする配列を構築し、それを使用して「jump_map」を構築することにより、さらなる最適化が提供されます。プログラムでの指導。

def primes():
  """Generates an infinite sequence of primes using the Sieve of Erathsones."""
  D = {}
  q = 2
  idx = 0
  while True:
    if q not in D:
      yield idx, q
      idx += 1
      D[q * q] = [q]
    else:
      for p in D[q]:
        D.setdefault(p + q, []).append(p)
      del D[q]
    q += 1

def factorize(num, sign = 1):
  """Factorizes a number, returning a list of (prime index, exponent) tuples."""
  ret = []
  for idx, p in primes():
    count = 0
    while num % p == 0:
      num //= p
      count += 1
    if count > 0:
      ret.append((idx, count * sign))
    if num == 1:
      return tuple(ret)

def decode(program):
  """Decodes a program expressed as a list of fractions by factorizing it."""
  return [(factorize(n), factorize(d)) for n, d in program]

def check(state, denom):
  """Checks if the program has at least the specified exponents for each prime."""
  for p, val in denom:
    if state[p] < val:
      return False
  return True

def update_state(state, num, denom):
  """Checks the program's state and updates it according to an instruction."""
  if check(state, denom):
    for p, val in denom:
      state[p] -= val
    for p, val in num:
      state[p] += val
    return True
  else:
    return False

def format_state(state):
  return dict((i, v) for i, v in enumerate(state) if v != 0)

def make_usage_map(program, maxidx):
  firstref = [len(program)] * maxidx
  for i, (num, denom) in enumerate(program):
    for idx, value in denom:
      if firstref[idx] == len(program):
        firstref[idx] = i
  return firstref

def make_jump_map(program, firstref):
  jump_map = []
  for i, (num, denom) in enumerate(program):
    if num:
      jump_map.append(min(min(firstref[idx] for idx, val in num), i))
    else:
      jump_map.append(i)
  return jump_map

def fractran(program, input, debug_when=None):
  """Executes a Fractran program and returns the state at the end."""
  maxidx = max(z[0] for instr in program for part in instr for z in part) + 1
  state = [0]*maxidx

  if isinstance(input, (int, long)):
    input = factorize(input)

  for prime, val in input:
    state[prime] = val

  firstref = make_usage_map(program, maxidx)
  jump_map = make_jump_map(program, firstref)

  pc = 0
  length = len(program)
  while pc < length:
    num, denom = program[pc]
    if update_state(state, num, denom):
      if num:
        pc = jump_map[pc]
      if debug_when and debug_when(state):
        print format_state(state)
    else:
      pc += 1

  return format_state(state)
于 2009-11-22T22:33:27.147 に答える
2

Perl、84 82 文字

標準入力を使用します。

@P=<>=~/\d+/g;$_=<>;
($a,$%)=@P[$i++,$i++],$_*$a%$%or$i=0,$_*=$a/$%while$i<@P;
print

ボーナス テストに合格するには 110 文字必要です。

use Math'BigInt blcm;@P=<>=~/\d+/g;$_=blcm<>;
($%,$=)=@P[$i++,$i++],$_*$%%$=or$i=0,($_*=$%)/=$=while$i<@P;print
于 2009-11-17T17:29:05.550 に答える
2

Perl 6: 77 文字 (実験的)

sub f(@p,$n is copy){
loop {my$s=first {!($n%(1/$_))},@p or return $n;$n*=$s}}

改行はオプションです。次のように呼び出します。

say f([3/2], 1296).Int;
say f([455/33, 11/13, 1/11, 3/7, 11/2, 1/3], 60466176).Int;

読み取り可能なバージョン:

sub Fractran (@program, $state is copy) {
  loop {
    if my $instruction = first @program:
      -> $inst { $state % (1 / $inst) == 0 } {
      $state *= $instruction;
    } else {
      return $state.Int;
    }
  }
}

ノート:

  1. コロン表記first @program: pointy-subは現在の実装では機能しません。最初のブロックでは、代わりに @program を使用する必要があります。

  2. Rakudo にはバグがありRat、間違った結果を出しているようです。現在の Niecza は、「ボーナス」部分を含め、すべてのテスト プログラムを正確かつ迅速に実行します。

于 2009-11-18T09:00:53.460 に答える
2

スキーム: 326

同等性のために、Scheme の提出が必要だと思いました。また、それで遊ぶ言い訳が欲しかっただけです。(初歩的な知識で申し訳ありませんが、これは最適化できると確信しており、提案を受け付けています!)

#lang scheme
(define fractran_interpreter
(lambda (state pc program)
    (cond
        ((eq? pc (length program)) 
            (print state))
        ((integer? (* state (list-ref program pc)))
            (fractran_interpreter (* state (list-ref program pc)) 0 program))
        (else
            (fractran_interpreter state (+ pc 1) program)))))

テスト:

(fractran_interpreter 108 0 '(3/2))

(fractran_interpreter 60466176 0 '(455/33 11/13 1/11 3/7 11/2 1/3))

ボーナスベクトルをゲット!(Dr. Scheme を使用し、256 mb を割り当てます)

于 2009-11-18T09:22:47.740 に答える
1

Java 、200192179 文字

Javaの実装が最短ではないことは誰もが知っていると思いますが、それがどのように比較されるかを見たかったのです。些細な例は解決しますが、ボーナスの例は解決しません。

最小化されたバージョンは次のとおりです。

class F{public static void main(String[]a){long p=new Long(a[0]);for(int i=1;i<a.length;){long n=p*new Long(a[i++]),d=new Long(a[i++]);if(n%d<1){p=n/d;i=1;}}System.out.print(p);}}

java-cp。F 108455 33 11 13 1 11 3 7 11 2 1 3

15625

java-cp。F 1296 3 2

6561

クリーンアップされたバージョンは次のとおりです。

public class Fractran {

    public static void main(String[] args) {
        long product = new Long(args[0]);

        for (int index = 1; index < args.length;) {
            long numerator = product * new Long(args[index++]);
            long denominator = new Long(args[index++]);

            if (numerator % denominator < 1) {
                product = numerator / denominator;
                index = 1;
            } // if
        } // for

        System.out.print(product);
    }
}
于 2009-11-17T20:56:34.993 に答える
1

スキーム 73 文字

完全に標準的な R 5 RS スキームでこれを行う私の最初の試みは、104 文字になりました。

(define(fpn)(let l((qp)(nn))(if(null? q)n(let((a(* n(car q))))(if(integer?
a)(lpa)(l(cdr q)n))))))

テスト ベクトルのいくつかの項目に対して実行します。

>(f'(3/2)1296)
6561
> (f '(455/33 11/13 1/11 3/7 11/2 1/3) 60466176)
7888609052210118054117285652827862296732064351090230047702789306640625

λそれがバインドされlambda、定義されていると仮定する場合let/cc(それらは PLT スキームにあるため、それらを定義していないスキームでこれを実行するための定義については以下を参照してください)、ジョーダンの 2 番目の Ruby ソリューションをスキームに適合させることができます。 73 文字 (引数の順序は私の最初の解決策の逆ですが、Jordan のものと同じであることに注意してください。このバージョンでは、1 文字節約されます):

(define(fnp)(let/cc r(map(λ(i)(if(整数?(* ni))(r(f(* ni)p))))p)n))

λ事前定義されていない場合、これは 111 文字になります (かなり一般的な略語が定義されlet/ccている場合は 88 文字)。call/cc

(define(fnp)(call-with-current-continuation(lambda(r)(map(lambda(i)(if(integer?(*))
ni))(r(f(* ni)p))))p)n)))

λとの定義let/cc:

(定義構文 λ
  (構文規則 ()
    ((_ . body) (ラムダ . body)))

(define-syntax let/cc
  (構文規則 ()
    ((_ var . body) (call-with-current-continuation (lambda (var) . body)))))
于 2009-11-22T04:41:15.757 に答える
1

少し遅い... dc 84文字

楽しみのためのdcソリューション(OpenBSD)

[ss1sp]s1[Rlp1+sp]s2?l1xz2/sz[z2/ds_:bl_:az0<L]dsLx
1[;als*lp;b~0=1e2lpdlz!<L]dsLxlsp

すべてのケースを処理します。

$ dc fractran.dc  
455 33 11 13 1 11 3 7 11 2 1 3 60466176
7888609052210118054117285652827862296732064351090230047702789306640625
于 2010-03-23T23:03:08.203 に答える
1

Haskell、142 文字

追加のライブラリと完全な I/O はありません。

t n f=case f of{(a,b):f'->if mod n b == 0then(\r->r:(t r f))$a*n`div`b else t n f';_->[]}
main=readLn>>=(\f->readLn>>=(\n->print$last$t n f))
于 2009-11-17T17:37:04.600 に答える
0

まだコメントを残すことはできませんが、これは RCIX の C# バージョンの「わずかに」短いバージョンです (7 文字短いと思います)。

using System;namespace T{static class P{static void Main(string[] a){int i=1;Func<string,decimal> d=Convert.ToDecimal;var c=d(a[0]);while(i+1<=a.Length){var f=d(a[i])/d(a[++i]);if((f*c)%1==0){i=1;c*=f;}else i++;}Console.Write(c);}}}

使用する

Func<string,decimal> d=Convert.ToDecimal

d();の代わりに呼び出します

using b=Convert;

と繰り返し呼び出しb.ToDecimal();ます。

また、else ステートメントを囲む不要な中括弧のペアを削除して、1 文字を取得しました :)。

また、a[i+1]を置き換えa[++i]、次のelseボディで置き換えi+=2i++、別の文字を取得しました:P

于 2009-11-26T11:24:03.297 に答える