Code Golf:Fractran

时间:2009-11-17 16:06:48

标签: code-golf esoteric-languages

挑战

编写一个充当Fractran解释器的程序。任何语言的字符数最短的翻译都是赢家。你的程序必须有两个输入:要执行的fractran程序和输入整数n。该程序可以是任何方便您的程序的形式 - 例如,2元组列表或平面列表。输出必须是一个整数,是执行结束时寄存器的值。

Fractran

Fractran是John Conway发明的一种微不足道的深奥语言。 fractran程序由一系列正分数和一个初始状态n组成。解释器维护一个程序计数器,最初指向列表中的第一个部分。 Fractran程序以下列方式执行:

  1. 检查当前状态的产品和当前在程序计数器下的分数是否为整数。如果是,则将当前状态乘以当前分数,并将程序计数器重置为列表的开头。
  2. 推进程序计数器。如果到达列表末尾,则停止,否则返回步骤1.
  3. 有关Fractran的工作原理和原因的详细信息,请参阅the esolang entrythis entry关于良好的数学/错误数学。

    测试向量

    计划: [(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(5 100

    提交&amp;得分

    程序严格按字符长度排列 - 最短是最好的。随意提交一个布局合理,文档化和代码的“缩小”版本,以便人们可以看到正在发生的事情。

    语言“J”不可接受。这是因为在其中一个链接页面上已经有一个众所周知的J解决方案。如果你是J粉丝,抱歉!

    然而,作为额外的奖励,任何能够在 fractran中提供工作分形翻译的人都将获得500点声望点奖励。在不太可能发生多个自托管口译员的情况下,分数最短的口译员将获得赏金。

    优胜者

    在提交包含1779个分数的自托管fractran解决方案后,官方获胜者为Jesse Beder's solution。实际上,解决方案太慢,甚至无法执行1 + 1。

    令人难以置信的是,这已被另一个fractran解决方案击败 - Amadaeus's solution只有84个分数!在我的参考Python解决方案上运行时,它能够在几秒钟内执行前两个测试用例。它使用了一种新颖的分数编码方法,值得仔细研究。

    尊敬的提及:

    • Stephen Canon's solution,在x86汇编的165个字符中(28个字节的机器代码)
    • Jordan's solution 52个ruby字符 - 处理长整数
    • Useless's solution在87个字符的Python中,虽然不是最短的Python解决方案,但它是少数几个不递归的解决方案之一,因此可以轻松处理更难的程序。它也非常易读。

25 个答案:

答案 0 :(得分:45)

Fractran - 1779分数

(编辑:已修复)

(我希望人们仍然关注这个帖子,因为这需要一段时间!)

看起来不会让我发布一些东西,所以我发布了Fractran来源here

输入指定如下:

首先,我们通过以下方式对分数m/n = p_0^a0... p_k^ak进行编码:

  • 从1开始。然后,为每个ai
  • 如果p_2i^ai
  • 乘以ai > 0
  • 如果p_2i+1^{-ai}
  • 乘以a_i < 0

这样,我们将任何分数编码为正整数。现在,给定一个progoram(编码分数序列F0,F1,...),我们按

编码
p_0^F0 p1^F1 ...

最后,解释器的输入由:

给出
2^(program) 3^(input) 5

其中programinput按上述方式编码。例如,在第一个测试问题中,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语句(为方便起见!)。可以找到here的代码。

如果你想自己编译代码到Fractran,可以找到我的(C ++)程序here [tar.gz]。在令人惊叹的dogfooding(和炫耀)展示中,我使用了我的C ++ YAML解析器yaml-cpp,所以你必须下载并链接它。对于yaml-cpp和“编译器”,您需要CMake来生成跨平台的makefile。

该程序的用法是:

./fracc interpreter.frp

它从标准输入读取函数的名称,并将相应的“伪分数”(我将在一秒钟内解释)写入标准输出。因此,要编译解释器(Interpret函数),您可以运行

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

输出(“pseudo-Fractran”)将是一系列行,每行都有一串以空格分隔的数字。一行对应一个分数:如果该行中n个数字为an,则该分数是p_n^an的乘积。

将此转换为Fractran很容易,但如果你很懒,可以使用to-fractions.py。 [注意:早些时候我有一个C ++程序,我不小心忽略了整数溢出。我把它翻译成Python以避免这种情况。]

关于输入的注意事项:如果要以这种方式测试不同的函数,则约定总是相同的。它在伪Fractran中有许多参数(通常是函数上面的注释解释这个),所以给它想要的东西,在下一个槽上加上1(所以在普通的Fractran中,乘以一次它不会使用的第一个素数)。这是函数开始运行的“信号”位。


然而,

我不建议实际尝试运行Fractran解释器(唉)。我测试了它的许多组件,例如,函数IncrementPrimes,它使用一对素数并返回接下来的两个素数,需要大约 8分钟来运行,使用我的傻瓜C ++解释器(无需发布:)。另外,它在函数调用的数量上(至少)是二次方的 - 函数调用的数量加倍使得它至少需要四倍的时间(如果有while个循环或if语句则更多) 。所以我猜测运行翻译至少需要几天,如果不是几年:(

那么我怎么知道它有效呢?嗯,当然我不是百分百肯定,但我非常接近。首先,我测试了很多很多组件,特别是,我非常彻底地测试了元语言的所有元素(函数序列以及ifwhile语句)。 / p>

此外,元语言很容易翻译成您喜欢的语言,甚至更容易翻译成C ++,因为函数的所有参数都是通过引用传递的。如果你再次感到懒惰,你可以下载我的翻译here [tar.gz](没有makefile;它只是两个.cpp文件,所以直接调用gcc就可以了。)

所以你可以比较两个解释器,运行C ++版本(它还需要伪Fractran中的输入/输出),检查它是否有效,然后说服自己元语言也能正常工作。


或者!

如果您感到受到启发,并且确实希望看到此解释器被解释,您可以根据我们获得的Fractran输出类型编写一个“聪明的”Fractran解释器。输出是非常结构化的 - 函数序列是使用信号实现的,所以如果你以某种方式缓存解释器所在的位置,如果没有重要的改变,你可以立即跳转到那里。我认为,这将大大加快计划的速度(可能会减少一个或多个权力的运行时间)。

但是,我不确定如何做到这一点,我对所做的事感到满意,所以我会把它作为读者的练习。

答案 1 :(得分:41)

Fractran: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

这是一个非常大的数字。

第一个测试向量以小于一秒结束,在4545次迭代后产生所需结果,并在6172次迭代后停止。这是the complete output

不幸的是,当我尝试使用第二个测试向量时,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 }
}

答案 2 :(得分:20)

x86_64程序集,165个字符(28个字节的机器代码)。

状态在%rdi中传递,Program(指向以null结尾的分数数组的指针)在%rsi中。根据通常的C风格调用约定,结果以%rax返回。使用非标准的调用约定或Intel语法(这是AT&amp; T语法)会丢弃更多的字符,但我很懒惰;别人可以做到这一点。通过重新安排控制流程几乎可以肯定地保存一两条指令,如果有人想这样做,请随意。

中间计算(state * numerator)最大可达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

答案 3 :(得分:16)

Ruby, 58 57 56 53 52个字符

这是我有史以来的第一个高尔夫球场,所以请保持温和。

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

Ruby, 53 52使用Rational

gnibbler's solution的启发,我能够使用Rational得到一个解决方案,直到 53 52个字符。 仍然比上面的(不太优雅)解决方案更长。

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个字符。)

答案 4 :(得分:12)

Golfscript - 32

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

    ; 108 [[3 2]] f p
    # 243
    ; 1296 [[3 2]] f p
    # 6561
    ; 108 [[455 33][11 13][1 11][3 7][11 2][1 3]] f p
    # 15625
    ; 60466176 [[455 33][11 13][1 11][3 7][11 2][1 3]] f p
    # 7888609052210118054117285652827862296732064351090230047702789306640625

答案 5 :(得分: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 List Ratio
Prelude List Ratio> let l&n=maybe n((&)l.numerator.(n%1*).(!!)l)$findIndex((==)1.denominator.(n%1*))l
Prelude List Ratio> [3%2]&108
243
Prelude List Ratio> [3%2]&1296
6561
Prelude List Ratio> [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
Prelude List Ratio> let l&n=maybe n((&)l.(*)n.(!!)l)$findIndex((==)1.denominator
Prelude List Ratio> [455%33,11%13,1%11,3%7,11%2,1%3]&108
15625 % 1

答案 6 :(得分: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 f.c
$ echo 108 3 2 . | ./a.out; echo
243
$ echo 1296 3 2 . | ./a.out; echo
6561
$ echo 108 455 33 11 13 1 11 3 7 11 2 1 3 . | ./a.out; echo
15625

答案 7 :(得分: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

答案 8 :(得分: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

需要花费4.7秒才能咳出前10个素数:

> 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]
毫无疑问,这是我写过的最离奇,最慢的素数发生器。我不确定这是好事还是坏事。

答案 9 :(得分:5)

Python - 53

感谢Paul的改进

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)

Python - 55

这个有点理论化。前两种情况运行正常,但另外两种情况从递归深度失败。也许有人可以让它使用生成器表达式

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

这是一种可能性,但即使不包含导入

,也会增加到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()

答案 10 :(得分: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()

答案 11 :(得分: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

答案 12 :(得分:4)

Javascript one: 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

漂亮版:

function 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;
        } else {
            n = c % q[1];
            i = 0;
        }
    }
    return n;
};

答案 13 :(得分:2)

Groovy 136 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

答案 14 :(得分: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)

答案 15 :(得分:2)

Haskell: 116 109个字符

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}

这最终有点像达里奥的入场。

答案 16 :(得分:2)

方案:326

我认为需要一个方案提交,以便进行平价。我也只是想借口玩它。 (请原谅我的基本知识,我相信这可以优化,我愿意接受建议!)

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

答案 17 :(得分: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不适用于当前的实现;首先是BLOCK,必须使用@program。

  2. Rakudo似乎有一个错误的Rat给出错误的结果。目前Niecza正确,快速地运行所有测试程序,包括“奖金”分数。

答案 18 :(得分:2)

<强>的Lua:

整洁的代码:

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

(手动输入其中的一部分,因为从命令行中获取东西很痛苦,尽管这是返回的结果)

不遗余地处理奖金矢量:(

答案 19 :(得分:2)

Perl, 84 82 char

使用标准输入。

@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

答案 20 :(得分:1)

Java, 200 192 179个字符

我想每个人都知道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 108 455 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);
    }
}

答案 21 :(得分:1)

方案73个字符

我的第一次尝试是使用完全标准的R 5 RS方案,以104个字符进行:

(define(f p n)(let l((q p)(n n))(if(null? q)n(let((a(* n(car q))))(if(integer?
a)(l p a)(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 Scheme中;请参阅下面有关在未定义的方案中运行此定义的定义那些,然后我可以调整Jordan's second Ruby solution到Scheme,它出现了73个字符(请注意,参数顺序与我的第一个解决方案相反,但与Jordan相同;在此版本中,保存一个字符) :

(define(f n p)(let/cc r(map(λ(i)(if(integer?(* n i))(r(f(* n i)p))))p)n))

如果我没有预定义λlet/cc,那么这个就会有111个字符(如果定义了相当常见的call/cc缩写,则为88个字符):

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

λlet/cc的定义:

(define-syntax λ 
  (syntax-rules () 
    ((_ . body) (lambda . body)))

(define-syntax let/cc 
  (syntax-rules () 
    ((_ var . body) (call-with-current-continuation (lambda (var) . body)))))

答案 22 :(得分: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))

答案 23 :(得分:1)

有点晚...... dc 84 chars

只是为了一个有趣的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

答案 24 :(得分: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个char:)。

我还将a[i+1]替换为a[++i],在以下其他正文中,我将i+=2替换为i++以获得另一个字符:P