编写一个充当Fractran解释器的程序。任何语言的字符数最短的翻译都是赢家。你的程序必须有两个输入:要执行的fractran程序和输入整数n。该程序可以是任何方便您的程序的形式 - 例如,2元组列表或平面列表。输出必须是一个整数,是执行结束时寄存器的值。
Fractran是John Conway发明的一种微不足道的深奥语言。 fractran程序由一系列正分数和一个初始状态n组成。解释器维护一个程序计数器,最初指向列表中的第一个部分。 Fractran程序以下列方式执行:
有关Fractran的工作原理和原因的详细信息,请参阅the esolang entry和this 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 )
程序严格按字符长度排列 - 最短是最好的。随意提交一个布局合理,文档化和代码的“缩小”版本,以便人们可以看到正在发生的事情。
语言“J”不可接受。这是因为在其中一个链接页面上已经有一个众所周知的J解决方案。如果你是J粉丝,抱歉!
然而,作为额外的奖励,任何能够在 fractran中提供工作分形翻译的人都将获得500点声望点奖励。在不太可能发生多个自托管口译员的情况下,分数最短的口译员将获得赏金。
在提交包含1779个分数的自托管fractran解决方案后,官方获胜者为Jesse Beder's solution。实际上,解决方案太慢,甚至无法执行1 + 1。
令人难以置信的是,这已被另一个fractran解决方案击败 - Amadaeus's solution只有84个分数!在我的参考Python解决方案上运行时,它能够在几秒钟内执行前两个测试用例。它使用了一种新颖的分数编码方法,值得仔细研究。
尊敬的提及:
答案 0 :(得分:45)
(编辑:已修复)
(我希望人们仍然关注这个帖子,因为这需要一段时间!)
看起来不会让我发布一些东西,所以我发布了Fractran来源here。
输入指定如下:
首先,我们通过以下方式对分数m/n = p_0^a0... p_k^ak
进行编码:
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
其中program
和input
按上述方式编码。例如,在第一个测试问题中,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
语句则更多) 。所以我猜测运行翻译至少需要几天,如果不是几年:(
那么我怎么知道它有效呢?嗯,当然我不是百分百肯定,但我非常接近。首先,我测试了很多很多组件,特别是,我非常彻底地测试了元语言的所有元素(函数序列以及if
和while
语句)。 / p>
此外,元语言很容易翻译成您喜欢的语言,甚至更容易翻译成C ++,因为函数的所有参数都是通过引用传递的。如果你再次感到懒惰,你可以下载我的翻译here [tar.gz](没有makefile;它只是两个.cpp文件,所以直接调用gcc就可以了。)
所以你可以比较两个解释器,运行C ++版本(它还需要伪Fractran中的输入/输出),检查它是否有效,然后说服自己元语言也能正常工作。
如果您感到受到启发,并且确实希望看到此解释器被解释,您可以根据我们获得的Fractran输出类型编写一个“聪明的”Fractran解释器。输出是非常结构化的 - 函数序列是使用信号实现的,所以如果你以某种方式缓存解释器所在的位置,如果没有重要的改变,你可以立即跳转到那里。我认为,这将大大加快计划的速度(可能会减少一个或多个权力的运行时间)。
但是,我不确定如何做到这一点,我对所做的事感到满意,所以我会把它作为读者的练习。
答案 1 :(得分:41)
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)
这是我有史以来的第一个高尔夫球场,所以请保持温和。
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
受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)
{:^{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)
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)
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)
将输入作为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)
感谢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]
这是一种可能性,但即使不包含导入
,也会增加到65from 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)
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
(显示如何开车)
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)
此实施以主要分解为基础。
首先,它通过将分子和分母编码为(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)
我认为需要一个方案提交,以便进行平价。我也只是想借口玩它。 (请原谅我的基本知识,我相信这可以优化,我愿意接受建议!)
#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)
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;
}
}
}
冒号符号first @program: pointy-sub
不适用于当前的实现;首先是BLOCK,必须使用@program。
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)
使用标准输入。
@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不会有最短的实现,但我想知道它将如何进行比较。它解决了一些微不足道的例子,但不是奖金。
以下是最小化版本:
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)
我的第一次尝试是使用完全标准的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)
没有任何额外的库和完整的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
解决方案(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