继Pi的蒙特卡洛估计器之后,这一挑战是为常数Pi生成最短的代码。除了此处,您的代码必须永远输出pi的连续数字。
这是代码高尔夫,因此最短的提交(以字节为单位)获胜,只是它必须在合理的PC上在不到10秒的时间内输出前10,000位数字,并且永远不能终止。
Pi或Trig函数不能使用任何内置函数。
删除了对代码大小的硬限制。
3141...
是-pi的连续数字。
继Pi的蒙特卡洛估计器之后,这一挑战是为常数Pi生成最短的代码。除了此处,您的代码必须永远输出pi的连续数字。
这是代码高尔夫,因此最短的提交(以字节为单位)获胜,只是它必须在合理的PC上在不到10秒的时间内输出前10,000位数字,并且永远不能终止。
Pi或Trig函数不能使用任何内置函数。
删除了对代码大小的硬限制。
3141...
是-pi的连续数字。
Answers:
3.1o{1YAZ2*:Z#*{_2$*2$2*)/@)\}h*]:+sX2*:X>X<o1}g
这会以越来越高的精度将π计算为2 * sum(k!/(2k + 1)!!),并且在每一步都从其中断处打印出一堆数字。
您可以在线尝试仅执行8次(外循环)迭代并输出512位数字的修改版本,或者将Java解释器用于真实内容。在我的笔记本电脑上,它在6秒钟内达到了16384位数字。
注意:该程序非常耗内存;表现较好但稍长的版本是:
3.1o{T2AZ2*:Z#*1{@2$+@2$*2$2*)/@)1$}g;;sX2*:X>X<o1}g
说明:
3.1o print 3.1
{…1}g repeat indefinitely
1YA push 1, 2 and 10 (Y=2, A=10)
Z2*:Z push Z*2 (Z=3 initially) and store back in Z
#* calculate 2*10^Z (2 from the formula and 10^Z for precision)
this is the term for k=0, and the earlier 1 represents k
{…}h do-while
at each iteration, the stack contains: terms, k, last-term
_2$* copy the previous term and k and multiply them
2$2*)/ divide the previous number by 2*k+1
this is the current term of the series
@)\ increment k and move it before the current term
the current term now serves as the loop condition
so the loop terminates when the term becomes 0
* multiply k and the last term (0), to get rid of k
]:+s put all the terms in an array, add them and convert to string
we obtain an approximation of π*10^Z
X2*:X push X*2 (X=1 initially) and store back in X
>X<o print X digits starting from the X position
q,r,t,i=1,180,60,2
while 1:u,y=27*i*(i+1)+6,(q*(27*i-12)+5*r)//(5*t);print(y,end="");q,r,t,i=10*q*i*(2*i-1),10*u*(q*(5*i-2)+r-y*t),t*u,i+1
http://www.cs.ox.ac.uk/jeremy.gibbons/publications/spigot.pdf的实现。
1:i:^3{3i):i*(.(*3*.@*.5*3$27i*12-*+@^*:^5*/.print^*2$5i*2-*--\10*i*2i*(*\10*.}do
在线演示(比合理的台式机慢得多,并且进行了微小的代码更改以循环有限的次数)。
当然,我使用了我在先前的评论中提到的自锁算法,但是花了我一段时间才使它满意。Gibbons的论文中提出的算法是(伪代码)
q = 1; r = 180; t = 60; i = 2
while (true) {
u = 3*(3*i+1)*(3*i+2)
y = (q*(27*i-12)+5*r) / (5*t)
print y
r += q*(5*i-2)-y*t
r *= 10*u
q *= 10*i*(2*i-1)
t *= u
i += 1
}
上面的GolfScript等效于(伪代码)
t = i = q = 1; r = 3
while (true) {
u = 3*(3*i+1)*(3*i+2)
i += 1
r *= u
t *= u
y = (q*(27*i-12)+5*r) / (5*t)
print y
r -= y*t - q*(5*i-2)
q *= 10*i*(2*i-1)
r *= 10
}
这样可以在初始化和堆栈管理中节省一些字符。
http://www.cs.ox.ac.uk/jeremy.gibbons/publications/spigot.pdf的另一种翻译。我本来打算做Python,但是@orlp击败了我,所以我做了Pyth。足够小以适合推文。
=H3=d1=bd=Gd#K+**hb27b6~b1=H*HK=d*dKJ/+*-*27b12G*5H*5d=H*T-H-*Jd*-*5b2G=G***GTbtybpkJ
由于来自end=""
打印设置的打印缓冲区,它以间歇性步骤将输出提供给stdout 。由于规范显示“连续数字”,因此我目前不打印小数点。它的任务正在杀死我的分数。
=H3 Set H to 3
=d1 Set d to 1
=bd Set b to d which is 1
=Gd Set G to d which is 1
# Infinte Loop
K Set K to
+**hb27b6 27*b*(b+1)+6
~b1 b+=1
=H*HK H*=K
=d*dK d*=K
J Set J to
/ Integer division
+*-*27b12G*5H G*(27*b-12)+5*H
*5d 5*d
=H Set H to
*T-H-*Jd*-*5b2G 10*(H-(J*d -G*(5*b-2)))
=G Set G to
***GTbtyb G*10*b*(2*b-1)
pkJ Print J with the end as "", not a newline
在这里尝试。(注意:由于在线解释器仅给出完整的结果,因此无限循环已结束,因此仅打印前100个,这会增加代码大小。要尝试无限循环,请下载本地解释器。)
在我的Google云端计算微型实例上,根据花费的总时间:real: 0m2.062s
这样显然足够快。
下面的代码直接来自Pi数字的Spigot算法的附录2中的Pascal代码。显然,几乎没有打高尔夫球。该代码的确会在10秒内生成10,000位数字,piSpigot(10000)
并且如果有一个无限内存,则可以对其进行参数化以生成很多数字,但不是无限。我不确定这是否满足问题限制,因此请提供反馈。
def piSpigot(n: Int): Unit = {
val len=10*n/3
var nines=0
var predigit=0
val a=Array.fill(len)(2)
(1 to n).foreach {_=>
var q=0
(1 to n).reverse.foreach{i=>
var x=10*a(i)+q*i
a(i)=x%(2*i-1)
q=x/(2*i-1)
}
a(1)=q%10
q/=10
if (q==9) {
nines+=1
} else if (q==10) {
print(predigit+1)
1.to(nines).foreach(_=>print(0))
predigit=0
nines=0
} else {
print(predigit)
predigit=q
if (nines!=0) {
1.to(nines).foreach(_=>print(9))
nines=0
}
}
}
println(predigit)
}
piSpigot(10000)
n
。参见例如cs.ox.ac.uk/people/jeremy.gibbons/publications/spigot.pdf
cf*10p'<20p11>00p1+:30p:::*+39**6+:30g39**c-00g*10gv
>:2*1-*00g*a*^
^:p02*g02p01*a*-*g02\+g01*g00-2*5g03,+*86:/*5g02+*5<
就时间限制而言,这是临界点。10,000位数在我的笔记本电脑上花费11秒钟左右,但是我确定必须有一台“合理的” PC,它的处理速度比这更快。
但是,如果您要在TIO上进行尝试,请注意,直到达到60秒的时间限制,它才会返回任何内容,因为该算法旨在永久运行。到那时,您将拥有超过10,000位数。
我正在使用Jeremy Gibbons插口算法,我认为它与此处的大多数其他答案相同。但是,请注意,这依赖于具有任意精度存储单元的解释器,而我知道支持的唯一实现是PyFunge。
说明
cf*10p Initialise r to 180.
'<20p Initialise t to 60.
11 Initialise i and q on the stack to 1.
> Start of the main loop.
00p Save the current value of q in memory.
1+:30p Increment i and save a copy in memory.
:::*+39**6+ Calculate u = 27*(i*i+i)+6.
: Make a duplicate, since we'll need two copies later.
30g39**c-00g*10gv Calculate y = (q*(27*i-12)+5*r)/(5*t).
/*5g02+*5<
,+*86: Convert y to a character so we can output it.
*a*-*g02\+g01*g00-2*5g03 Calculate r = 10*u*(q*(i*5-2)+r-y*t)
p01 Save the updated r.
*g02 Calculate t = t*u
p02 Save the updated t.
>:2*1-*00g*a* Calculate q = 10*q*i*(i*2-1).
^:
^ Return to the start of the main loop.