5 giây để tìm Pie


11

Pi lần e (hoặc Pie nếu bạn thích ký hiệu mơ hồ) đến 100 chữ số thập phân là:

8.5397342226735670654635508695465744950348885357651149618796011301792286111573308075725638697104739439...

( OIES A019609 ) ( lập luận cho sự bất hợp lý có thể )

Nhiệm vụ của bạn là viết một chương trình lấy số nguyên dương N và xuất ra Pi * e bị cắt cụt thành N vị trí thập phân. ví dụ nếu N = 2, thì đầu ra phải là 8.53.

Đây là một vấn đề tối ưu hóa, vì vậy bài nộp có thể đưa ra đầu ra chính xác cho giá trị cao nhất của N sẽ giành chiến thắng.

Để đảm bảo tất cả các bài nộp được đánh giá bằng cùng một sức mạnh tính toán, mã của bạn phải được chạy trên ideone , sử dụng bất kỳ ngôn ngữ nào chúng hỗ trợ. Theo faq ideone , có giới hạn thời gian chạy 5 giây cho người dùng không đăng nhập. Giới hạn 5 giây này là giới hạn bạn phải sử dụng, không phải giới hạn 15 giây cho người dùng đã đăng nhập. (Xem faq để biết các giới hạn khác như bộ nhớ, kích thước mã, v.v.)

Cụ thể, bất kỳ ai không đăng nhập vào ideone đều có thể chạy chương trình của bạn trên ideone cho tất cả các giá trị của N từ 1 đến một số Nmax tối đa và xem đầu ra chính xác gần như mọi lúc . không có bất kỳ Time limit exceededhoặc Memory limit exceeded, vv lỗi. Trình nộp với Nmax lớn nhất sẽ thắng.

(Cho dù thời gian thực tế là một nụ cười trên 5 giây không quan trọng miễn là ideone không mắc lỗi. " Gần như toàn bộ thời gian " được định nghĩa là hơn 95% thời gian cho bất kỳ N. cụ thể nào)

Chi tiết

  • Bạn có thể sử dụng bất kỳ phương pháp toán học nào bạn muốn để tính toán Pi * e, nhưng bạn không thể mã hóa đầu ra vượt quá hàng chục chữ số đầu tiên của Pi, e hoặc Pi * e .
    • Chương trình của bạn sẽ có thể làm việc cho bất kỳ N, được cung cấp tài nguyên không giới hạn.
    • Bạn có thể sử dụng các hằng số tích hợp trong Pi hoặc e nếu ngôn ngữ của bạn có chúng.
  • Bạn không thể truy cập các trang web hoặc tài nguyên bên ngoài mã của mình (nếu ideone thậm chí cho phép điều này).
  • Ngoài mã hóa cứng và truy cập các tài nguyên bên ngoài, bất cứ điều gì mà ideone cho phép gần như chắc chắn đều ổn.
  • Đầu vào và đầu ra của bạn phải (rõ ràng) hoạt động với bất kỳ ideone nào cung cấp cho i / o (chỉ có vẻ như stdin / stdout). Sẽ tốt thôi nếu bạn cần trích dẫn xung quanh đầu vào N hoặc đầu ra giống như vậy ans = ..., v.v.
  • Vui lòng bao gồm một liên kết đến một đoạn mã ideone của mã của bạn với Nmax làm đầu vào.
  • Nếu có một sự ràng buộc (chỉ có khả năng nếu nhiều lần gửi đạt giới hạn ký tự đầu ra 64kB), câu trả lời phiếu cao nhất sẽ thắng.

3
Mmm ... chiếc bánh mơ hồ.
Dennis

Điều này có thể rất dễ dàng là một golf-code và thay vào đó sẽ vui hơn.
Tối ưu hóa

2
@Optimizer Nó có thể là golf-code nhưng sau đó nó sẽ khá giống với mọi golf-code thế hệ chữ số khác. Tôi muốn thử một cuộc thi dựa trên thời gian có thể được xác minh trực tuyến. (Mặc dù một vấn đề phức tạp hơn về mặt tính toán có thể đã tốt hơn.)
Sở thích của Calvin

Nếu đây là mã golf, APL có thể sẽ thắng (trừ phần chính xác tùy ý)
TwiNight

1
Tôi nghi ngờ rằng các chương trình này sẽ hoàn toàn bị ràng buộc IO khi cố gắng viết ra các chữ số cho thiết bị xuất chuẩn. Năm giây là một thời gian dài đối với một cái gì đó như y-cruncher .
Sẽ

Câu trả lời:


12

Con trăn - 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 dường như không gmpy2cài đặt, điều này thật đáng tiếc vì ít nhất hai lý do. Một, bởi vì nó sẽ làm cho quá trình tính toán nhanh hơn rất nhiều, và hai, bởi vì nó làm cho bất kỳ công thức nào đòi hỏi một căn bậc hai chính xác tùy ý không thực tế.

Công thức tôi sử dụng cho π được liệt kê bởi Ramanujan là Công thức (39):

hội tụ ở tốc độ ~ 5,89 chữ số mỗi kỳ. Theo hiểu biết của tôi, đây là loạt hội tụ nhanh nhất của loại hình này không yêu cầu đánh giá căn bậc hai chính xác tùy ý. Công thức (44) trong giấy cùng (tốc độ hội tụ ~ 7,98 chữ số cho mỗi thuật ngữ) thường được gọi là các công thức Ramanujan.

Công thức tôi sử dụng cho e là tổng các yếu tố nghịch đảo. Số lượng thuật ngữ cần thiết được tính bằng Γ -1 ( 10 n ), bằng cách sử dụng một xấp xỉ tôi tìm thấy trên mathoverflow . Thành phần Lambert W 0 được tìm thấy bằng Phương pháp của Newton.

Việc tính toán từng tổng kết này được thực hiện thông qua Đánh giá chức năng điện tử nhanh (thường được gọi là phân tách nhị phân), ban đầu được Karatsuba nghĩ ra. Phương pháp này làm giảm tổng của n thành một giá trị hợp lý p / q . Hai giá trị này sau đó được nhân lên để tạo ra kết quả cuối cùng.

Cập nhật:
Hồ sơ tiết lộ rằng hơn một nửa thời gian cần thiết cho việc tính toán đã được dành cho bộ phận cuối cùng. Chỉ có trên hầu hết các log 2 (10 n ) bit của q là cần thiết để có được chính xác đầy đủ, vì vậy tôi cắt một vài tắt trước đó. Mã bây giờ điền vào bộ đệm đầu ra Ideone trong 3,33s .

Cập nhật 2:
Vì đây là một thách thức , tôi quyết định viết thói quen phân chia của riêng mình để chống lại sự chậm chạp của CPython. Việc thực hiện divnrở trên sử dụng Bộ phận Newton-Raphson . Ý tưởng chung là tính toán d = 1 / q · 2 n bằng Phương pháp Newton, trong đó n là số bit mà kết quả yêu cầu và tính kết quả là p · d >> n . Thời gian chạy bây giờ là 2,87 - và điều này thậm chí không cần cắt các bit trước khi tính toán; nó không cần thiết cho phương pháp này.


4

PARI / GP: 33000

Về cơ bản, đây là chương trình được đưa ra tại OEIS , được sửa đổi để lấy đầu vào và định dạng đầu ra chính xác. Nó sẽ phục vụ như là một đường cơ sở để đánh bại, nếu không có gì khác.

Tôi cho rằng điều này là chính xác. Tôi đã kiểm tra nó ở mức 100 và 20k so với OEIS và nó phù hợp với cả hai. Thật khó để tìm thêm chữ số trực tuyến để kiểm tra.

Đối với 33.000 phải mất khoảng 4,5 giây, vì vậy nó có thể bị va đập một chút. Tôi cảm thấy mệt mỏi khi phải loay hoay với vòng lặp gửi / biên dịch / chạy chậm của 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);
}

Liên kết Ideone.com


Các chữ số của bạn khớp với chữ số của tôi, vì vậy tôi sẽ đi ra ngoài và nói rằng chúng có thể đúng.
Primo

Chương trình này dành cơ bản tất cả thời gian của nó trong vòng lặp, tạo ra các chữ số từng cái một. Nếu bạn chỉ mất Str(floor(frac(x)*10^m)nó đi nhanh hơn hàng trăm / ngàn lần.
Charles

2

Con trăn 3

Vì số pi và e không có đủ chữ số, tôi quyết định tự tính toán.

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])

Liên kết IDEOne

Đầu ra cho STDIN = 1000:

8.5397342226735669504281233688422467204743749305568824722710929852470173635361001388261308713809518841081669216573834376992066672804294594807026609638293539437286935503772101801433821053915371716284188665787967232464763808892618434263301810056154560438283877633957941572944822034479453916753507796910068912594560500836608215235605783723340714760960119319145912948480279651779184356994356172418603464628747082162475871780202868607325544781551065680583616058471475977367814338295574582450942453416002008665325253385672668994300796223139976640645190237481531851902147391807396201201799703915343423499008135819239684881566321559967077443367982975103648727755579256820566722752546407521965713336095320920822985129589997143740696972018563360331663471959214120971348584257396673542429063767170337770469161945592685537660073097456725716654388703941509676413429681372333615691533682226329180996924321063261666235129175134250645330301407536588271020457172050227357541822742441070313522061438812060477519238440079

Nmax là giá trị đầu vào lớn nhất bạn có thể cung cấp cho chương trình của mình trước khi ideone sẽ không còn chạy nó nữa.
Sở thích của Calvin

1
@ Calvin'sHob sở thích Tôi nghĩ rằng nmax lớn tùy ý mặc dù ...
Beta Decay

1
ideone không cung cấp cho bạn sức mạnh tính toán vô hạn. Giá trị đầu vào lớn nhất chương trình của bạn có thể chạy trên ideone là gì? (Mặc dù trên thực tế, chương trình của bạn không tuân theo should be able to work for any N, given unlimited resourcesquy tắc. Hầu hết đầu ra là số không vào khoảng N = 10000.)
Sở thích của Calvin

Đó không phải là python3 : NameError: name 'xrange' not defined.
Bakuriu

2

Scala - 1790

IDEOne tại http://ideone.com/A2CIto .

Chúng tôi sử dụng công thức của Wetherfield cho số π (và mã công thức Machin được chuyển hoàn toàn từ đây ). Chúng tôi tính toán e sử dụng chuỗi lũy thừa thông thường.

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) 
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.