5 วินาทีในการค้นหาพาย


11

Piครั้งE (หรือพายถ้าคุณชอบโน้ตคลุมเครือ) 100 ตำแหน่งทศนิยมคือ:

8.5397342226735670654635508695465744950348885357651149618796011301792286111573308075725638697104739439...

( OIES A019609 ) ( อาร์กิวเมนต์สำหรับความไม่ลงตัวที่อาจเกิดขึ้นได้ )

งานของคุณคือการเขียนโปรแกรมที่ใช้จำนวนเต็มบวก N และเอาท์พุท Pi * e ที่ตัดปลายเป็นทศนิยมสิบตำแหน่ง เช่นถ้า N = 2 8.53แล้วออกที่ควรจะเป็น

นี่เป็นปัญหาการปรับให้เหมาะสมดังนั้นการส่งที่สามารถให้ผลลัพธ์ที่ถูกต้องสำหรับค่าสูงสุดของ N จะเป็นผู้ชนะ

เพื่อให้แน่ใจว่าการส่งทั้งหมดจะถูกตัดสินโดยใช้พลังการประมวลผลเดียวกันรหัสของคุณจะต้องทำงานบนideoneโดยใช้ภาษาใดก็ได้ที่พวกเขาสนับสนุน ตามideone faqมีการ จำกัด เวลารัน 5 วินาทีสำหรับผู้ใช้ที่ไม่ได้ล็อกอิน ขีด จำกัด 5 วินาทีนี้เป็นสิ่งที่คุณต้องใช้ไม่ใช่ขีด จำกัด 15 วินาทีสำหรับผู้ใช้ที่ล็อกอิน (ดูคำถามที่พบบ่อยสำหรับข้อ จำกัด อื่น ๆ เช่นหน่วยความจำขนาดรหัส ฯลฯ )

โดยเฉพาะคนที่ไม่ได้เข้าสู่ระบบ ideone ควรจะสามารถเรียกใช้โปรแกรมของคุณบน ideone ทุกค่าของ N จาก 1 ไปสูงสุดบาง nMax และเห็นผลลัพธ์ที่ถูกต้องเกือบตลอดเวลา ไม่มีข้อผิดพลาดใด ๆTime limit exceededหรือMemory limit exceededฯลฯ การส่งด้วย Nmax ที่ใหญ่ที่สุดชนะ

(ไม่ว่าเวลาที่ถ่ายจริงจะเป็น smidge นานกว่า 5 วินาทีหรือไม่ก็ตามตราบเท่าที่ ideone ไม่ให้ข้อผิดพลาด " เกือบตลอดเวลา " ถูกกำหนดเป็นมากกว่า 95% ของเวลาสำหรับ N ใด ๆ โดยเฉพาะ)

รายละเอียด

  • คุณอาจจะใช้วิธีการทางคณิตศาสตร์ที่คุณต้องการใดในการคำนวณ Pi * E, แต่คุณอาจไม่ hardcode ส่งออกเกินโหลหลักแรกของ Pi, E หรือ Pi *อีเมล
    • โปรแกรมของคุณควรทำงานให้กับ N ใด ๆ ที่ได้รับทรัพยากรไม่ จำกัด
    • คุณอาจใช้บิวท์อิน Pi หรือค่าคงที่หากภาษาของคุณมีอยู่
  • คุณไม่สามารถเข้าถึงเว็บไซต์หรือแหล่งข้อมูลภายนอกรหัสของคุณ (ถ้า ideone อนุญาตให้ทำได้)
  • นอกเหนือจากฮาร์ดโค้ดและการเข้าถึงทรัพยากรภายนอกแล้วสิ่งใดก็ตามที่ ideone อนุญาตให้ทำได้นั้นเกือบจะแน่นอน
  • อินพุตและเอาต์พุตของคุณจะต้องทำงานร่วมกับ ideone ที่ให้สำหรับ i / o (stdin / stdout เท่านั้นที่ดูเหมือน) ไม่เป็นไรถ้าคุณต้องการอัญประกาศรอบอินพุต N หรือเอาต์พุตเป็นอย่างans = ...อื่นเป็นต้น
  • โปรดใส่ลิงก์ไปยังตัวอย่างโค้ด ideone ของรหัสของคุณด้วย Nmax ของคุณ
  • หากมีการเสมอกัน (เป็นไปได้ก็ต่อเมื่อการส่งหลายครั้งมีขีด จำกัด จำนวนอักขระที่เอาต์พุต 64kB) คำตอบโหวตสูงสุดจะชนะ

3
อืมมมม ... พายที่คลุมเครือ
เดนนิส

นี่เป็นโค้ดกอล์ฟได้ง่ายและค่อนข้างสนุกกว่าถ้าเป็น
เครื่องมือเพิ่มประสิทธิภาพ

2
@Optimizer มันอาจเป็น code-golf แต่มันก็น่าจะเหมือนกับ code-golf รุ่นอื่น ๆ ฉันต้องการลองการแข่งขันตามเวลาที่สามารถยืนยันออนไลน์ได้ (แม้ว่าปัญหาที่ซับซ้อนยิ่งกว่าการคำนวณอาจดีกว่า)
งานอดิเรกของ Calvin

ถ้าเป็น APL รหัสกอล์ฟอาจจะชนะ (ลบส่วนที่มีความแม่นยำโดยพล)
TwiNight

1
ฉันสงสัยว่าโปรแกรมเหล่านี้จะถูก IO ทั้งหมดพยายามที่จะเขียนตัวเลขเพื่อ stdout ห้าวินาทีเป็นเวลานานเพื่อสิ่งที่ต้องการY-Cruncher
จะ

คำตอบ:


12

Python - 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,

ดูเหมือนจะไม่ได้gmpy2ติดตั้งIdeone ซึ่งน่าเสียดายอย่างน้อยสองเหตุผล หนึ่งเพราะมันจะทำให้การคำนวณเร็วขึ้นมากและสองเพราะมันทำให้สูตรใด ๆ ที่ต้องการรากที่สองที่มีความแม่นยำไม่สามารถทำได้

สูตรที่ฉันใช้สำหรับπถูกระบุโดย Ramanujanเป็นสูตร (39):

ซึ่งมาบรรจบกันในอัตรา~ 5.89หลักต่อเทอม สำหรับความรู้ของฉันนี่เป็นซีรี่ย์ที่มาบรรจบกันเร็วที่สุดซึ่งไม่ต้องการการประเมินสแควร์รูทที่แม่นยำ สูตร (44) ในกระดาษเดียวกัน (อัตราการลู่~ 7.98ตัวเลขต่อเทอม) ส่วนใหญ่มักจะเรียกว่าเป็นสูตร Ramanujan

สูตรที่ฉันใช้สำหรับeคือผลรวมของแฟคทอเรียล จำนวนคำที่จำเป็นจะถูกคำนวณเป็นΓ -1 ( 10 n ) โดยใช้การประมาณที่ฉันพบในmathoverflow พบองค์ประกอบ Lambert W 0โดยใช้วิธีของนิวตัน

การคำนวณของการสรุปแต่ละครั้งจะทำผ่านการประเมิน E-function อย่างรวดเร็ว (รู้จักกันโดยทั่วไปว่าการแยกแบบไบนารี) ที่สร้างสรรค์โดย Karatsuba วิธีการที่จะช่วยลดผลบวกกับnแง่ที่เดียวค่าเหตุผลP / q จากนั้นค่าทั้งสองนี้จะนำมาคูณกันเพื่อให้ได้ผลลัพธ์สุดท้าย

ปรับปรุง: การทำ
โปรไฟล์เปิดเผยว่าใช้เวลาในการคำนวณมากกว่าครึ่งหนึ่งในการแบ่งขั้นสุดท้าย เฉพาะส่วนใหญ่บนล็อก2 (10 n )บิตQที่มีความจำเป็นเพื่อให้ได้ความแม่นยำเต็มดังนั้นฉันตัดออกไม่กี่ก่อน รหัสในขณะนี้เติมบัฟเฟอร์ส่งออก Ideone ใน3.33s

อัปเดต 2:
เนื่องจากนี่เป็นความท้าทายด้านฉันจึงตัดสินใจเขียนกิจวัตรการหารของตัวเองเพื่อต่อสู้กับความเชื่องช้าของ CPython การดำเนินการdivnrดังกล่าวข้างต้นใช้Newton-Raphson กอง ความคิดทั่วไปคือการคำนวณd = 1 / q · 2 nโดยใช้วิธีของนิวตันที่nคือจำนวนของบิตผลต้องและคำนวณผลตามที่P · d >> n ขณะนี้รันไทม์เป็น2.87s - และนี่คือโดยไม่ต้องตัดบิตแม้แต่ก่อนการคำนวณ มันไม่จำเป็นสำหรับวิธีนี้


4

PARI / GP: 33000

นี่คือโปรแกรมที่กำหนดให้ที่OEISซึ่งแก้ไขเพื่อรับอินพุตและจัดรูปแบบเอาต์พุตอย่างถูกต้อง มันควรทำหน้าที่เป็นพื้นฐานในการตีถ้าไม่มีอะไรอื่น

ฉันถือว่านี่ถูกต้อง ฉันตรวจสอบที่ 100 และ 20k เทียบกับ OEIS และจับคู่กับทั้งคู่ มันค่อนข้างยากที่จะหาตัวเลขเพิ่มเติมทางออนไลน์เพื่อตรวจสอบ

สำหรับ 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


ตัวเลขของคุณตรงกับของฉันดังนั้นฉันจะออกไปที่กิ่งและบอกว่ามันอาจจะถูกต้อง
โม่

โปรแกรมนี้ใช้เวลาส่วนใหญ่ในการวนรอบสร้างตัวเลขทีละตัว หากคุณเพียงแค่นำStr(floor(frac(x)*10^m)มันไปเร็วขึ้นหลายร้อย / หลายพัน
ชาร์ลส์

2

Python 3

เนื่องจากตัวบิวท์อินและอีมีตัวเลขไม่เพียงพอฉันจึงตัดสินใจคำนวณเอง

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 จะไม่เรียกใช้อีกต่อไป
งานอดิเรกของ Calvin

1
@ Calvin's งานอดิเรกฉันคิดว่า nmax มีขนาดใหญ่โดยพลการแม้ว่า ...
Beta Decay

1
ideone ไม่ให้พลังการคำนวณที่ไม่มีขีด จำกัด แก่คุณ ค่าอินพุตที่ใหญ่ที่สุดของคุณคืออะไรโปรแกรมของคุณสามารถทำงานบน ideone ได้? (แม้ว่าอันที่จริงโปรแกรมของคุณไม่ปฏิบัติตามshould be able to work for any N, given unlimited resourcesกฎผลผลิตส่วนใหญ่จะเป็นศูนย์ที่ประมาณ N = 10,000)
Calvin's Hobbies

ที่ไม่ NameError: name 'xrange' not definedpython3:
Bakuriu

2

สกาลา - 1790

IDEOne ที่http://ideone.com/A2CIto

เราใช้สูตรของ Wetherfieldสำหรับπ (และโค้ดสูตรแมชชีนที่พอร์ตแบบหยาบจากที่นี่ ) เราคำนวณ 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.