파이를 찾는 데 5 초


11

Pi 곱하기 e (또는 모호한 표기법을 선호하는 경우 Pie)는 소수점 이하 100 자리입니다.

8.5397342226735670654635508695465744950348885357651149618796011301792286111573308075725638697104739439...

( OIES A019609 ) ( 불합리한 주장 )

당신의 임무는 양의 정수 N을 취하고 Pi * e를 N 소수점 이하 자릿수로 출력하는 프로그램을 작성하는 것입니다. 예를 들어 N = 2이면 출력은이어야합니다 8.53.

이것은 최적화 문제이므로 N의 가장 높은 값에 대한 올바른 출력을 제공 할 수있는 제출이 이길 것입니다.

모든 제출물이 동일한 컴퓨팅 성능을 사용하여 판단되도록하려면 지원되는 모든 언어를 사용하여 코드를 ideone 에서 실행해야합니다 . ideone faq 에 따르면 , 로그인하지 않은 사용자에게는 5 초의 런타임 제한이 있습니다. 이 5 초 제한은 로그인 한 사용자에 대한 15 초 제한이 아니라 사용해야하는 제한입니다. ( 메모리, 코드 크기 등과 같은 다른 제한에 대해서는 FAQ 를 참조하십시오 .)

특히, ideone에 로그인하지 않은 사람은 1에서 최대 Nmax까지의 모든 N 값에 대해 ideone에서 프로그램을 실행할 수 있어야하며 거의 항상 올바른 출력을 볼 수 있어야합니다 . 어떤없이 Time limit exceeded또는 Memory limit exceeded등 오류가 발생합니다. Nmax가 가장 큰 제출물이 이깁니다.

(실제로 걸린 시간이 5 초가 넘는 시간이든 문제가되지 않는 한 중요하지 않습니다. " 거의 모든 시간 "은 특정 N에 대한 시간의 95 % 이상으로 정의됩니다.)

세부

  • Pi * e를 계산하기 위해 원하는 수학적 방법을 사용할 수 있지만 Pi, e 또는 Pi * e의 처음 12 자리를 초과하여 출력을 하드 코딩 할 수 없습니다 .
    • 무제한 리소스가 주어지면 프로그램은 모든 N에서 작동 할 수 있어야합니다.
    • 언어에 내장 된 Pi 또는 e 상수가 내장되어있을 수 있습니다.
  • 코드 외부의 웹 사이트 나 리소스에 액세스 할 수 없습니다 (아이디어가 허용하는 경우).
  • 하드 코딩 및 외부 리소스 액세스 외에도, 아이디어가 허용하는 모든 것이 거의 확실합니다.
  • 입력 및 출력은 i / o에 제공하는 모든 아이디어 (stdin / stdout 만 해당)와 함께 작동해야합니다. 입력 N 주위에 따옴표가 필요하거나 출력이와 같은 경우 괜찮습니다 ans = ....
  • Nmax를 입력으로 사용하여 코드의 아이디어 스 니펫에 대한 링크를 포함하십시오.
  • 동점이 발생하는 경우 (여러 제출물이 64kB 출력 문자 제한에 도달 한 경우에만) 가장 높은 투표 응답이 승리합니다.

3
음 ... 모호한 파이.
Dennis

이것은 매우 쉽게 코드 골프가 될 수 있으며 그렇다면 더 재미있을 것입니다.
Optimizer

2
@Optimizer 코드 골프 일 수 있지만 다른 모든 숫자 생성 코드 골프와 거의 비슷합니다. 온라인에서 확인할 수있는 시간 기반 컨테스트를 시도하고 싶었습니다. (더 계산이 복잡한 문제가 더 좋았을 수도 있지만.)
칼빈의 취미

이것이 코드 골프라면 APL은 아마도 (임의의 정밀 부품을 빼고) 이길 것입니다
TwiNight

1
이 프로그램은 숫자를 stdout에 쓰려고 시도하면서 완전히 IO에 바인딩되어 있다고 생각합니다. 5 초는 y-cruncher 와 같은 데 오랜 시간이 걸립니다 .
Will

답변:


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설치 되지 않은 것 같습니다 . 적어도 두 가지 이유로 불행합니다. 하나는 계산을 훨씬 더 빠르게 할 것이기 때문이며, 두 번째는 임의의 정밀 제곱근을 요구하는 공식을 비실용적이기 때문입니다.

내가 π 에 사용하는 공식 은 Ramanujan에 의해 공식 (39)로 표시되었습니다 .

이는 용어 당 ~ 5.89 자리 의 비율로 수렴합니다 . 내 지식으로는, 이것은 임의의 정밀 제곱근의 평가가 필요하지 않은 가장 빠른 수렴 계열입니다. 동일한 종이 (수렴 레이트는 화학식 (44) ~ 7.98 기간 당 자리) 대부분이라 Ramanujan에 수식.

e에 사용하는 공식 은 역 계승의 합입니다. 필요한 항의 수는 mathoverflow 에서 찾은 근사값을 사용하여 Γ -1 ( 10 n ) 로 계산됩니다 . Lambert W 0 구성 요소는 Newton 's Method를 사용하여 찾을 수 있습니다.

이러한 각 합산의 계산은 원래 Karatsuba가 고안 한 Fast E-function Evalution (보다 일반적으로 이진 분할)을 통해 수행됩니다 . 이 방법은 합을 n 개의 항으로 단일 합리적인 값 p / q로 줄 입니다. 그런 다음이 두 값을 곱하여 최종 결과를 생성합니다.

업데이트 :
프로파일 링에 따르면 계산에 필요한 시간의 절반 이상이 최종 부서에서 소요 된 것으로 나타났습니다. 만 상위 대부분의 로그 2 (10 N ) 의 비트 Q는 내가 사전에 몇 오프 트림, 그래서 전 정밀도를 얻기 위해 필요하다. 이제 코드의 Ideone 출력 버퍼 채우는 3.33s가 .

업데이트 2 :
이것은 과제이므로 CPython의 속도 저하에 대처하기 위해 자체 부서 루틴을 작성하기로 결정했습니다. divnr위 의 구현에는 Newton-Raphson Division이 사용 됩니다. 일반적인 아이디어는 Newton 's Method를 사용하여 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

이 프로그램은 본질적으로 모든 시간을 루프에서 보내고 숫자를 하나씩 생성합니다. 방금 가져 Str(floor(frac(x)*10^m)가면 수백 / 수 천배 더 빠릅니다.
Charles

2

파이썬 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는 프로그램이 더 이상 실행되지 않기 전에 프로그램에 제공 할 수있는 가장 큰 입력 값입니다.
Calvin 's Hobbies

1
@ Calvin'sHobbies 비록 nmax는 임의로 큰 것 같아요 ...
Beta Decay

1
ideone은 무한한 컴퓨팅 능력을 제공하지 않습니다. 최대 입력 값 무엇 당신의 프로그램이 ideone에서 실행할 수는? (실제로 프로그램은 should be able to work for any N, given unlimited resources규칙을 따르지 않습니다 . 대부분의 출력은 N = 10000 부근에서 0입니다.)
Calvin 's Hobbies

그것은 python3이 아닙니다 : NameError: name 'xrange' not defined.
Bakuriu

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) 
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.