5秒找到派


11

Pi乘以e(如果喜欢模棱两可的表示法,则用Pie表示)到100个小数位:

8.5397342226735670654635508695465744950348885357651149618796011301792286111573308075725638697104739439...

OIES A019609)(可能不合理的论点

您的任务是编写一个程序,该程序采用正整数N,然后将Pi * e截断为N个小数位。例如,如果N = 2,则输出应为8.53

这是一个优化问题,因此可以为N的最大值提供正确输出的提交将获胜。

为了确保使用相同的计算能力来判断所有提交,您的代码必须使用支持的任何语言ideone上运行。根据ideone常见问题解答,未登录用户的运行时间限制为5秒。这5秒的限制是您必须使用的限制,而不是已登录用户的15秒的限制。(有关内存,代码大小等其他限制,请参见常见问题解答。)

具体来说,任何未登录ideone的人都应该能够在ideone上针对从1到某个最大Nmax的所有N值运行您的程序,并且几乎始终都能看到正确的输出。没有任何Time limit exceededMemory limit exceeded等错误。Nmax最大的提交者获胜。

(只要ideone不会出错,那么实际花费的时间是否超过5秒钟就无关紧要。“ 几乎所有的时间 ”都被定义为特定N的95%以上的时间。)

细节

  • 您可以使用任何喜欢的数学方法来计算Pi * e,但是您不能对输出的硬编码超出Pi,e或Pi * e的前十二个数字
    • 给定无限的资源,您的程序应该可以工作于任何N个。
    • 如果您的语言碰巧有Pi或e常量,则可以使用它们。
  • 您可能无法访问代码外部的网站或资源(如果ideone允许的话)。
  • 除了硬编码和访问外部资源之外,ideone允许的任何事情几乎都可以确定。
  • 您的输入和输出必须(显然)必须与ideone提供的I / O一起使用(看起来只有stdin / stdout)。如果您需要在输入N周围加引号或输出类似的东西ans = ...,等等就可以了。
  • 请提供一个以Nmax为输入的代码的ideone片段的链接。
  • 如果碰巧出现平局(仅当多个提交都达到64kB输出字符限制时才有可能),以最高票数回答为准。

3
嗯... pie昧的馅饼。
丹尼斯2014年

这很容易成为一个代码高尔夫,如果可以的话,它会更有趣。
Optimizer

2
@Optimizer可能是代码高尔夫,但随后几乎就像其他所有数字生成代码高尔夫一样。我想尝试一个可以在线验证的基于时间的竞赛。(尽管计算上更复杂的问题可能会更好。)
卡尔文的爱好

如果这是代码高尔夫球,APL可能会赢(减去任意精度部分)
TwiNight

1
我怀疑这些程序将完全受IO限制,试图将数字写出到stdout。像y-cruncher这样的东西要花五秒钟。
2014年

Answers:


12

蟒蛇-65535

http://ideone.com/knKRhn

from math import exp, log

def divnr(p, q):
  """
    Integer division p/q using Newton-Raphson Division.
    Assumes p > q > 0.
  """

  sp = p.bit_length()-1
  sq = q.bit_length()-1
  sr = sp - sq + 1

  s = []
  t = sr
  while t > 15:
    s = [t] + s
    t = (t>>1) + 1
  # Base-case division
  r = (1 << (t<<1)) / (q >> sq-t)

  for u in s:
    r = (r << u-t+1) - (r*r * (q >> sq-u) >> (t<<1))
    t = u
  return (r * (p >> sq)) >> sr

def pibs(a, b):
  if a == b:
    if a == 0:
      return (1, 1, 1123)
    p = a*(a*(32*a-48)+22)-3
    q = a*a*a*24893568
    t = 21460*a+1123
    return (p, -q, p*t)
  m = (a+b) >> 1
  p1, q1, t1 = pibs(a, m)
  p2, q2, t2 = pibs(m+1, b)
  return (p1*p2, q1*q2, q2*t1 + p1*t2)

def ebs(a, b):
  if a == b:
    if a == 0:
      return (1, 1)
    return (1, a)
  m = (a+b) >> 1
  p1, q1 = ebs(a, m)
  p2, q2 = ebs(m+1, b)
  return (p1*q2+p2, q1*q2)

if __name__ == '__main__':
  n = input()

  pi_terms = int(n*0.16975227728583067)

  # 10^n == e^p
  p = n*2.3025850929940457

  # Lambert W_0(p/e) a la Newton
  k = log(p) - 1
  w = k - (k-1)/(k+1)
  while k > w:
    k = w
    w -= (k - p*exp(-k-1))/(k+1)

  # InverseGamma(e^p) approximation
  e_terms = int(p / w)

  pp, pq, pt = pibs(0, pi_terms)
  ep, eq = ebs(0, e_terms)

  z = 10**n
  p = 3528*z*ep*abs(pq)
  q = eq*abs(pt)

  pie = divnr(p, q)
  print pie,

Ideone似乎尚未gmpy2安装,这很不幸,至少有两个原因。一种是因为它会使计算更快,另一种是因为它使得需要任意精度平方根的任何公式都不可行。

式I使用π由拉马努金列出作为式(39):

每个术语以〜5.89位数的速率收敛。据我所知,这是同类中最快的收敛级数,不需要评估任意精度的平方根。式(44)在相同的纸(收敛速率〜7.98每术语位数)是最经常被称为所述的Ramanujan式。

我为e使用的公式是阶乘的和。使用我在mathoverflow上找到的近似值,所需项的数量计算为Γ -110 n)。使用牛顿法可以找到Lambert W 0分量。

这些总和中的每一个的计算都是通过Karatsuba最初设计的快速电子功能评估(通常称为二进制拆分)完成的。该方法将n项的和减少为单个有理值p / q。然后将这两个值相乘以产生最终结果。

更新:
分析显示,计算所需时间的一半以上花在了最后的划分上。仅需要q的最高log 2(10 n位即可获得完全精度,因此我事先进行了一些修整。现在,该代码填写在Ideone输出缓冲区3.33s

更新2:
由于这是一个挑战,所以我决定编写自己的除法例程以应对CPython的缓慢性。divnr上面的实现使用Newton-Raphson Division。通常的想法是使用牛顿法计算d = 1 / q·2 n,其中n是结果所需的位数,并将结果计算为p·d >> n。现在的运行时间为2.87秒 -甚至在计算之前就不会砍掉位;这种方法是不必要的。


4

PARI / GP:33000

基本上,这是OEIS提供的程序,已修改为正确输入和格式化输出。如果没有别的,它应该作为击败的基准。

认为这是正确的。我对照OEIS分别以100和20k的价格对其进行了检查,两者均匹配。很难在网上找到更多数字进行检查。

对于33,000,大约需要4.5秒,因此它可能会碰一点。我只是厌倦了摆弄输入和ideone的慢驴提交/编译/运行循环。

{ 
    m=eval(input());
    default(realprecision, m+80); 
    x=Pi*exp(1);
    s="8.";
    d=floor(x);
    x=(x-d)*10;
    for (n=1, m, d=floor(x); 
         x=(x-d)*10; 
         s=Str(s,d));
    print(s);
}

Ideone.com链接


您的数字与我的数字相符,所以我将不胜枚举,说他们可能是正确的。
primo 2014年

该程序将其所有时间基本上都花在循环中,一次一位地生成数字。如果您只是选择Str(floor(frac(x)*10^m)它,它的运行速度将提高数百/千倍。
查尔斯

2

Python 3

由于内置的​​pi和e没有足够的数字,我决定自己计算。

import decimal
import math
decimal.getcontext().prec=1000000
decimal=decimal.Decimal;b=2500
print(str(sum([decimal(1/math.factorial(x)) for x in range(b)])*sum([decimal(1/16**i*(4/(8*i+1)-2/(8*i+4)-1/(8*i+5)-1/(8*i+6))) for i in range(b)]))[0:int(input())+2])

IDEOne链接

STDIN = 1000的输出:

8.5397342226735669504281233688422467204743749305568824722710929852470173635361001388261308713809518841081669216573834376992066672804294594807026609638293539437286935503772101801433821053915371716284188665787967232464763808892618434263301810056154560438283877633957941572944822034479453916753507796910068912594560500836608215235605783723340714760960119319145912948480279651779184356994356172418603464628747082162475871780202868607325544781551065680583616058471475977367814338295574582450942453416002008665325253385672668994300796223139976640645190237481531851902147391807396201201799703915343423499008135819239684881566321559967077443367982975103648727755579256820566722752546407521965713336095320920822985129589997143740696972018563360331663471959214120971348584257396673542429063767170337770469161945592685537660073097456725716654388703941509676413429681372333615691533682226329180996924321063261666235129175134250645330301407536588271020457172050227357541822742441070313522061438812060477519238440079

Nmax是您可以在ideone不再运行之前为程序提供的最大输入值。
加尔文的爱好

1
@ Calvin'sHobbies我认为尽管nmax任意大……
Beta Decay

1
ideone不会给您无限的计算能力。您的程序可以在ideone上运行的最大输入值是多少?(尽管实际上您的程序不遵循should be able to work for any N, given unlimited resources规则。大多数输出​​在N = 10000处为零。)
Calvin's Hobbies

这不是python3: NameError: name 'xrange' not defined
Bakuriu 2014年

2

斯卡拉-1790年

IDEOne位于http://ideone.com/A2CIto

我们对π 使用Wetherfield公式(以及从此处粗略移植的Machin公式代码)。我们使用普通幂级数计算e。

object Main extends App {
  import java.math.{BigDecimal => JDecimal}
  import java.math.RoundingMode._
  import scala.concurrent.Future
  import scala.concurrent.Await
  import scala.concurrent.ExecutionContext.Implicits._
  import scala.concurrent.duration._
  val precision = 1800

  def acotPrecision(numDigits: Int)(x: BigDecimal) = {
    val x1 = x.underlying
    val two = JDecimal.valueOf(2)
    val xSquared = x1 pow 2
    val unity = JDecimal.ONE.setScale(numDigits, HALF_EVEN)
    var sum = unity.divide(x1, HALF_EVEN)
    var xpower = new JDecimal(sum.toString)
    var term = unity

    var add = false

    var n = JDecimal.valueOf(3).setScale(numDigits)
    while (term.setScale(numDigits, HALF_EVEN).compareTo(JDecimal.ZERO) != 0) {
      xpower = xpower.divide(xSquared, HALF_EVEN)
      term = xpower.divide(n, HALF_EVEN)
      sum = if (add) sum add term else sum subtract term
      add = !add
      n = n add two
    }
    sum
  }

  def ePrecision(numDigits: Int) = {
    val zero = JDecimal.ZERO
    var sum = zero
    var term = JDecimal.ONE.setScale(numDigits, HALF_EVEN)
    var n = JDecimal.ONE.setScale(numDigits, HALF_EVEN)
    while(term.setScale(numDigits, HALF_EVEN).compareTo(zero) != 0) {
      sum = sum add term
      term = term.divide(n, HALF_EVEN)
      n = n add JDecimal.ONE
    }
    sum
  }

  val acot = acotPrecision(precision) _

  def d(x: Int) = JDecimal.valueOf(x)

  def piFuture = Future(d(4) multiply (
    (d(83) multiply acot(107)) add (d(17) multiply acot(1710)) subtract (d(22) multiply acot(103697))
    subtract (d(24) multiply acot(2513489)) subtract (d(44) multiply acot(18280007883L))
   add (d(12) multiply acot(7939642926390344818L))
   add (d(22) multiply acot(BigDecimal("3054211727257704725384731479018")))
  ))

  def eFuture = Future(ePrecision(precision))

  Await.result(
    for (pi <- piFuture;
         e <- eFuture) yield println((pi multiply e).setScale(precision - 10, DOWN))
  , 5 seconds) 
}
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.