计算pi的幂的截断数字总和


12

给定一个正整数Ñ输出的第一总和Ñ的小数部分的十进制数字π Ñ

输入和输出示例:

1→1
2→14
3→6
4→13
5→24
50→211
500→2305
5000→22852

不允许使用内置函数计算π位数或评估幂级数或连续分数。有标准漏洞。输入/输出可以采用方便的格式(stdin,stdout,功能输入/输出等)。

以字节为单位的最短代码获胜。


是否还禁止了其他可用于计算pi的trig函数(但不一定是直接函数),例如反正切或虚对数?另外,n是否有上限,之后可能会失败?
FryAmTheEggman 2015年

@FryAmTheEggman如果这些触发函数可以计算pi的任意数字,则是的,它们被禁止了。理论上,您的程序应该对任何n都可以工作,但是如果运行时或内存太高,则可以原谅。
orlp 2015年

Answers:


4

Python-191字节

t=i=1L;k=n=input();f=2000*20**n;A=range(n+1)
for k in range(2,n):A=[(A[j-1]+A[j+1])*j>>1for j in range(n-k+1)];f*=k
while k:k=(1-~i*n%4)*f/A[1]/i**n;t+=k;i+=2
print sum(map(int,`t`[-n-4:-4]))

快约4倍的版本-206字节

t=i=1L;k=n=input();f=2000*20**n;A=[0,1]+[0]*n
for k in range(1,n):
 f*=k
 for j in range(-~n/2-k+1):A[j]=j*A[j-1]+A[j+1]*(j+2-n%2)
while k:k=(1-~i*n%4)*f/A[1]/i**n;t+=k;i+=2
print sum(map(int,`t`[-n-4:-4]))

输入来自标准输入。在第二个脚本中,n = 5000的输出大约需要14s(或在第一个脚本中需要60s)。


用法示例:

$ echo 1 | python pi-trunc.py
1

$ echo 2 | python pi-trunc.py
14

$ echo 3 | python pi-trunc.py
6

$ echo 4 | python pi-trunc.py
13

$ echo 5 | python pi-trunc.py
24

$ echo 50 | python pi-trunc.py
211

$ echo 500 | python pi-trunc.py
2305

$ echo 5000 | python pi-trunc.py
22852

使用的公式如下:

其中ÑÑ 交替号,其可以被正式地定义为交替排列的数目上的一组尺寸的Ñ(也参见:A000111)。可替代地,该序列可以被定义为切线数和割线数(A 2n= S nA 2n + 1= T n)的组成,其后更多。

随着n变大,小的校正因子c n迅速收敛到1,并由下式给出:

对于n = 1,这相当于评估Leibniz级数。近似π10 ½,所需的项数可被计算为:

收敛(向上舍入)到17,尽管较小的n值需要更多。

为了计算A n,有几种算法,甚至是一个显式公式,但是所有算法都是n的二次方。我最初编码了Seidel算法的实现,但是它变得太慢而无法实用。每次迭代都需要存储一个附加项,并且这些项的大小会非常迅速地增加(“错误”的O(n 2种类)。

第一个脚本使用最初由Knuth和Buckholtz给出的算法的实现:

对于所有k = 1..n 令T 1,k = 1

T的后续值由递归关系给出:

T n + 1,k = 1/2 [ (k-1)T n,k-1 +(k +1)T n,k + 1 ]

然后由T n,1给出一个n

(另请参阅:A185414

尽管没有明确说明,该算法同时计算切线数和割线数。第二脚本使用该算法通过的变化Brent和齐默尔曼,其计算要么Ť小号,取决于奇偶Ñ。改进是n / 2的二次方,因此〜4x速度改进。


1
答案背后的数学很好的解释。
逻辑骑士

3

Python 2,246字节

对于采用二次收敛的π计算,我采用了类似的方法。最后一行采用pi的N次方并求和。N = 5000测试需要一分钟左右的时间。

from decimal import*
d=Decimal
N=input()
getcontext().prec=2*N
j=d(1)
h=d(2)
f=h*h
g=j/h
a=j
b=j/h.sqrt()
t=j/f
p=j
for i in bin(N)[2:]:e=a;a,b=(a+b)/h,(a*b).sqrt();c=e-a;t-=c*c*p;p+=p
k=a+b
l=k*k/f/t
print sum(map(int,`l**N`.split('.')[1][:N]))

一些测试:

$ echo 1 | python soln.py
1
$ echo 3 | python soln.py
6
$ echo 5 | python soln.py
24
$ echo 500 | python soln.py
2305
$ echo 5000 | python soln.py
22852

未经处理的代码:

from decimal import *
d = Decimal

N = input()
getcontext().prec = 2 * N

# constants:
one = d(1)
two = d(2)
four = two*two
half = one/two

# initialise:
a = one
b = one / two.sqrt()
t = one / four
p = one

for i in bin(N)[2:] :
    temp = a;
    a, b = (a+b)/two, (a*b).sqrt();
    pterm = temp-a;
    t -= pterm*pterm * p;
    p += p

ab = a+b
pi = ab*ab / four / t
print sum(map(int, `pi ** N`.split('.')[1][:N]))

8号线,你可以打开a=jp=ja=p=jIIRC。也许。
伊莱亚斯·本尼维德斯

谢谢。此代码还有更多的高尔夫优化方法,但是如果不使用不带十进制数的算法进行重写,它就没有竞争力。
逻辑骑士

1

珀斯(33)

s<>j^u+/*GHhyHy^TyQr*TQ0ZQT_y*QQQ

基于isaacg的答案。可能会打更多的高尔夫球。慢。

s<>j            Digit sum of...
  ^                 
    u               Evaluate pi = 2 + 1/3*(2 + 2/5*(2 + 3/7*(2 + 4/9*(2 + ...))))
      +
        /
          *GH
          hyH
        y^TyQ       Except we generate a large integer containing 2n digits,
                    rather than a fraction.
      r*TQ0         Experimentally verified that 10*n iterations will give enough
                    precision for 2n digits (# digits correct grows faster than 2n).
      Z
    Q               To the nth power.
  T_y*QQQ         Get the last 2n^2 digits (all the fractional digits) and get the
                  first n fractional digits.

1
这个答案确实至少需要足够的解释,才能证明它计算出足够的数字来获得正确的答案。
彼得·泰勒

@PeterTaylor我明天要上床睡觉,再加一个解释。
orlp 2015年

每次迭代都会产生一个正确的位(请参见附录A)。2n个数字应需要约6.64n次迭代。
2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.