Pasta Bulmak İçin 5 Saniye


11

100 ondalık basamağa Pi çarpı e (veya belirsiz gösterimi isterseniz Pie):

8.5397342226735670654635508695465744950348885357651149618796011301792286111573308075725638697104739439...

( OIES A019609 ) ( olası irrasyonalite iddiası )

Göreviniz, pozitif bir tamsayı N alan ve Pi * e çıktısını N ondalık basamağa kesen bir program yazmaktır. örneğin N = 2 ise, çıkış olmalıdır 8.53.

Bu bir optimizasyon problemidir, bu nedenle en yüksek N değeri için doğru çıktıyı verebilen gönderim kazanacaktır.

Tüm gönderimlerin aynı bilgi işlem gücü kullanılarak değerlendirildiğinden emin olmak için, kodunuzun destekledikleri herhangi bir dil kullanılarak ideone üzerinde çalıştırılması gerekir . Göre ideone sss , kullanıcılar yapmadınız için 5 saniye çalışma zamanı sınırı vardır. Bu 5 saniyelik sınır, oturum açmış kullanıcılar için 15 saniyelik sınır değil , kullanmanız gereken sınırdır. ( Bellek, kod boyutu vb. Gibi diğer sınırlar için SSS'ye bakın )

Özellikle, ideone'de oturum açmamış olan herkes 1'den maksimum Nmax'a kadar tüm N değerleri için programınızı ideone'de çalıştırabilmeli ve neredeyse her zaman doğru çıktıyı görebilmelidir . herhangi olmadan Time limit exceededveya Memory limit exceededvb hataları. En büyük Nmax değerine sahip olan başvuru kazanır.

(Gerçek zamanın 5 saniyeden fazla bir sürüngen olup olmadığı, ideone hata vermediği sürece önemli değildir. " Neredeyse her zaman ", belirli bir N. için zamanın% 95'inden fazlası olarak tanımlanır.)

ayrıntılar

  • Pi * e'yi hesaplamak için herhangi bir matematiksel yöntemi kullanabilirsiniz, ancak çıktıyı Pi, e veya Pi * e'nin ilk düzine basamağının ötesinde kodlayamayabilirsiniz .
    • Programınız, sınırsız kaynaklar verildiğinde herhangi bir N için çalışabilmelidir.
    • Eğer diliniz varsa, Pi ya da e sabitlerini kullanabilirsiniz.
  • Kodunuzun dışındaki web sitelerine veya kaynaklara erişemezsiniz (ideone buna izin veriyorsa).
  • Sabit kodlamanın ve harici kaynaklara erişmenin ötesinde, ideone'nin izin verdiği her şey neredeyse kesinlikle iyidir.
  • Girdiniz ve çıktınız (açıkça) ideone i / o için ne sağlıyorsa onu kullanmalıdır (stdin / stdout sadece görünüyor). N girişinde tırnaklara ihtiyacınız varsa veya çıktı ans = ...vb.
  • Lütfen giriş olarak Nmax değerinizle kodunuzun ideone snippet'ine bir bağlantı ekleyin.
  • Beraberlik olursa (sadece 64kB çıkış karakteri sınırına ulaşan birden fazla başvuru olması muhtemeldir) en yüksek oy yanıtı kazanır.

3
Mmm ... belirsiz pasta.
Dennis

Bu çok kolay bir kod-golf olabilir ve eğer daha eğlenceli olurdu.
Optimizer

2
@Optimizer Bu kod-golf olabilir ama sonra hemen hemen her diğer nesil nesil kod-golf gibi olurdu. Çevrimiçi olarak doğrulanabilen zamana dayalı bir yarışma denemek istedim. (Daha hesaplama açısından karmaşık bir sorun daha iyi olsa da.)
Calvin'in Hobileri

Eğer bu kod golf APL muhtemelen kazanır (keyfi hassas kısmı eksi)
TwiNight

1
Bu programların basamakları stdout'a yazmaya çalışırken tamamen IO'ya bağlı olacağından şüpheleniyorum. Beş saniye, y krizi gibi bir şey için uzun bir zaman .
Will

Yanıtlar:


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,

Ideone gmpy2yüklü görünmüyor , bu en az iki nedenden dolayı talihsiz bir durum. Birincisi, hesaplamayı çok daha hızlı ve iki tane yapar, çünkü keyfi bir kare kök gerektiren herhangi bir formülü pratik yapmaz.

İçin formül I kullanımı tt edildi Ramanujan listelenen Formül (39) olarak:

Bu, terim başına ~ 5.89 basamak oranında yakınsar . Bildiğim kadarıyla, bu, türünün en hızlı yakınsak serisidir ve keyfi bir kare kökün değerlendirilmesini gerektirmez. Aynı kağıt (yakınsama hızı Formül (44) ~ 7.98 dönem başına basamak) en sık olarak da adlandırılır Ramanujan formül.

E için kullandığım formül , ters faktörlerin toplamıdır. Gerekli terim sayısı , mathoverflow'da bulunan bir yaklaşım I kullanılarak Γ -1 ( 10 n ) olarak hesaplanır . Lambert W 0 bileşeni Newton Metodu kullanılarak bulunur.

Bu özetlerin her birinin hesaplanması , başlangıçta Karatsuba tarafından tasarlanan Hızlı E-İşlev Değerlendirmesi (daha genel olarak ikili bölme olarak bilinir) aracılığıyla yapılır. Yöntem toplamı n terime indirgeyerek tek bir rasyonel değer p / q'ya indirir . Bu iki değer daha sonra nihai sonucu elde etmek için çarpılır.

Güncelleme:
Profil oluşturma, hesaplama için gereken sürenin yarısından fazlasının son bölümde harcandığını ortaya koydu. Tam kesinlik elde etmek için sadece q'nun en üst log 2 (10 n ) bitine ihtiyaç duyulur, bu yüzden önceden birkaç tane kırparım. Kod şimdi Ideone çıktı arabelleğini 3.33s içinde doldurur .

Güncelleme 2:
Bu bir zorluğu olduğundan, CPython'un yavaşlığıyla mücadele etmek için kendi bölüm rutinimi yazmaya karar verdim. Uygulanması divnrYukarıda kullandığı Newton-Raphson Bölümü . Genel fikir, Newton'un Yöntemini kullanarak d = 1 / q · 2 n değerini hesaplamaktır ; burada n , sonucun gerektirdiği bit sayısıdır ve sonucu p · d >> n olarak hesaplar . Çalışma zamanı şimdi 2.87s - ve bu hesaplamadan önce bitleri kesmeden bile; bu yöntem için gereksizdir.


4

PARI / GP: 33000

Bu temelde OEIS'te verilen programdır. girdi ve format çıktısını doğru şekilde almak . Başka bir şey yoksa, yenmek için bir temel görevi görmelidir.

Ben varsayalım doğru . Ben 100 ve 20k OEIS karşı kontrol ve her ikisi için eşleşti. Kontrol etmek için çevrimiçi daha fazla basamak bulmak oldukça zor.

33.000 için yaklaşık 4.5 saniye sürer, bu yüzden muhtemelen biraz çarpılabilir. Sadece girdi ve ideone yavaş eşek gönderme / derleme / çalıştırma döngüsü ile uğraşmaktan bıktım.

{ 
    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 bağlantısı


Basamaklarınız benimkiyle eşleşiyor, bu yüzden uzuvlara gideceğim ve muhtemelen doğru olduklarını söyleyeceğim.
primo

Bu program esasen tüm zamanlarını döngüde harcar ve tek tek rakamlar üretir. Sadece alırsanız Str(floor(frac(x)*10^m), yüzlerce / binlerce kez daha hızlı gider.
Charles

2

Python 3

Dahili pi ve e'nin yeterli basamakları olmadığından, kendim hesaplamaya karar verdim.

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 bağlantısı

STDIN = 1000 için çıkış:

8.5397342226735669504281233688422467204743749305568824722710929852470173635361001388261308713809518841081669216573834376992066672804294594807026609638293539437286935503772101801433821053915371716284188665787967232464763808892618434263301810056154560438283877633957941572944822034479453916753507796910068912594560500836608215235605783723340714760960119319145912948480279651779184356994356172418603464628747082162475871780202868607325544781551065680583616058471475977367814338295574582450942453416002008665325253385672668994300796223139976640645190237481531851902147391807396201201799703915343423499008135819239684881566321559967077443367982975103648727755579256820566722752546407521965713336095320920822985129589997143740696972018563360331663471959214120971348584257396673542429063767170337770469161945592685537660073097456725716654388703941509676413429681372333615691533682226329180996924321063261666235129175134250645330301407536588271020457172050227357541822742441070313522061438812060477519238440079

Nmax, ideone artık çalışmadan önce programınıza verebileceğiniz en büyük giriş değeridir.
Calvin'in Hobileri

1
@ Calvin'sHobbies Sanırım nmax keyfi olarak büyük ...
Beta Decay

1
ideone size sonsuz bilgi işlem gücü vermez. Büyük giriş değeri nedir senin programın ideone çalışabilir? (Aslında programınız should be able to work for any N, given unlimited resourceskurallara uymaz . Çıktının çoğu N = 10000 civarında sıfırdır.)
Calvin'in Hobileri

Bu python3 değil: NameError: name 'xrange' not defined.
Bakuriu

2

Scala - 1790

En IDEOne http://ideone.com/A2CIto .

Biz kullanmak Wetherfield formülü (kabaca taşıdık ve Machin-formül kodu tt için buraya ). E'yi normal kuvvet serilerini kullanarak hesaplıyoruz.

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) 
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.