Pi'nin rasyonel yaklaşımları


22

Artan payda sırasına göre, pi'nin tüm rasyonel yaklaşımlarını, <1000000 payda ile yazdıran bir program yazın. a/bpi'ye göre daha büyük olmayan payda ile rasyonel olandan daha yakınsa, pi'nin "iyi bir rasyonel yaklaşımı" dır b.

Çıktı toplam 167 satıra sahip olmalı ve şöyle başlamalı ve bitmelidir:

3/1
13/4
16/5
19/6
22/7
179/57
...
833719/265381
1146408/364913
3126535/995207

En kısa program kazanır.

Yanıtlar:


23

Golfscript, 71 70 69 karakter

2\!:^2^..292^15.2/3]{(.)2/.9>+{\+.((}*;.}do;;]-1%{^0@{2$*+\}/"/"\n}/;

(Stdin'de hiçbir şey iletmediğinizi varsayar)

Pi için sabitleri olmayan insanlar tarafından daha fazla kulak çınlaması duymak istemiyorum. Kayan nokta numaralarım bile yok!

Arka plan için http://en.wikipedia.org/wiki/Continued_fraction#Best_rational_approximations bakın .

# No input, so the stack contains ""
2\!:^2^..292^15.2/3]
# ^ is used to store 1 because that saves a char by allowing the elimination of whitespace
# Otherwise straightforward: stack now contains [2 1 2 1 1 1 292 1 15 7 3]
# Pi as a continued fraction is 3+1/(7+1/(15+1/(...)))
# If you reverse the array now on the stack you get the first 10 continuants followed by 2
# (rather than 3)
# That's a little hack to avoid passing the denominator 1000000

{
    # Stack holds: ... [c_n c_{n-1} ... c_0]
    (.)2/.9>+
    # Stack holds ... [c_{n-1} ... c_0] c_n (1+c_n)/2+((1+c_n)/2 > 9 ? 1 : 0)
    # (1+c_n)/2 > 9 is an ad-hoc approximation of the "half rule"
    # which works in this case but not in general
    # Let k = (1+c_n)/2+((1+c_n)/2 > 9 ? 1 : 0)
    # We execute the next block k times
    {
        # ... [c_{n-1} ... c_0] z
        \+.((
        # ... [z c_{n-1} ... c_0] [c_{n-1} ... c_0] z-1
    }*
    # So we now have ... [c_n c_{n-1} ... c_0] [(c_n)-1 c_{n-1} ... c_0] ...
    #                    [(c_n)-k+1 c_{n-1} ... c_0] [c_{n-1} ... c_0] c_n-k
    ;
    # Go round the loop until the array runs out
    .
}do

# Stack now contains all the solutions as CFs in reverse order, plus two surplus:
# [2 1 2 1 1 1 292 1 15 7 3] [1 2 1 1 1 292 1 15 7 3] ... [6 3] [5 3] [4 3] [3] [2] []
# Ditch the two surplus ones, bundle everything up in an array, and reverse it
;;]-1%

# For each CF...
{
    # Stack holds ... [(c_n)-j c_{n-1} ... c_0]
    # We now need to convert the CF into a rational in canonical form
    # We unwind from the inside out starting with (c_n)-j + 1/infinity,
    # representing infinity as 1/0
    ^0@
    # ... 1 0 [c_n-j c_{n-1} ... c_0]
    # Loop over the terms of the CF
    {
        # ... numerator denominator term-of-CF
        2$*+\
        # ... (term-of-CF * numerator + denominator) numerator
    }/

    # Presentation
    "/"\n
    # ... numerator "/" denominator newline
}/

# Pop that final newline to avoid a trailing blank line which isn't in the spec
;

1
Teknik olarak GolfScript, PI için kayan nokta numaralarına ve sabite sahiptir. Buna denir "#{Math.PI}".
Konrad Borowski

2
@GlitchMr, bir dize kayan nokta sayısı nedir?
Peter Taylor

Bunu yorumlarla birlikte görmeyi çok isterim.
primo

Şaşırtıcı. İlk satır 2\!:^2^..292^15.2/3]zaten aklımı başımdan aldı.
primo

@ PeterTaylor Bağlı . Daha iyisini yapabilir miyiz?
Eelvex

11

Mathematica, 67 63

Bu hızlı olmayacak, ama teknik olarak doğru olduğuna inanıyorum.

Round[π,1/Range@1*^6]//.x_:>First/@Split[x,#2≥#&@@Abs[π-{##}]&]

Round[π, x]steps 'a en yakın kesri adım adım verir x. Bu "listable" dır Round[π,1/Range@1*^6], bu yüzden bütün kesirler için bunu yapar 1/10^6. Pek çok "kötü" rasyonel yaklaşıma sahip olan sonuç listesi, art arda ( //.), bir öncekinden π'dan daha uzak olan herhangi bir eleman çıkarılarak işlenir.


Çok havalı, ama test edemem çünkü Mathematica'm yok.
Keith Randall

@Keith, işte mantık. adımlar halinde Round[Pi, x]en yakın kısmı verir . Bu "listable" yani 1/10 ^ 6'ya kadar olan tüm kesirler için bunu yapar. Pek çok "kötü" rasyonel yaklaşıma sahip olan sonuç listesi daha sonra tekrar tekrar ( ), pi'den öncekilerden daha uzak olan herhangi bir eleman çıkarılarak işlenir. PixRound[Pi,1/Range@1*^6]//.
Sayın Sihirbaz,

Mathematica, GolfScript'i yeniyor. Temiz.
SpellingD

61 yılında: Select[Round[f=Pi,1/Range@1*^6],If[#<f,f=#;True]&@Abs[#-Pi]&]... ama baskın önyargı verilen işe yaramaz
Dr. belisarius

Yarr, Matie. Bu kodda sihir olun.
Michael Stern,

7

Perl, 77 karakter

$e=$p=atan2 0,-1;($f=abs$p-($==$p*$_+.5)/$_)<$e&&($e=$f,say"$=/$_")for 1..1e6

Küçük bir zorluk, Perl'in yerleşik π sabitinin mevcut olmamasıdır , bu yüzden ilk önce onu hesaplamak zorunda kaldım atan2(0,-1). Bunun iş için daha uygun diller tarafından dövüleceğinden eminim, ancak çoğunlukla metin işleme için tasarlanmış bir dil için fena değil.


1
Sen değişebilir 999999için 1e6ve 3 karakter kaydedin.
Toto,

@ M42: Teşekkürler! Şimdi 82 karaktere kadar.
Ilmari Karonen,

Gerçekten güzel, $ = tamsayı almak için. Üzgünüm, iki defa oy kullanamıyorum.
Toto

Bunu çalıştırmak için alamam:String found where operator expected at prog.pl line 1, near "say"$=/$_""
Keith Randall

@KeithRandall: Komut için -M5.01anahtara (ve Perl 5.10.0 veya üstü) ihtiyacınız var say. Bahsetmediğim için üzgünüm.
Ilmari Karonen

5

Python, 96 93 89 karakter

a=b=d=1.
while b<=1e6:
 e=3.14159265359-a/b;x=abs(e)
 if x<d:print a,b;d=x
 a+=e>0;b+=e<0

Python, 95 93 karakter, farklı algoritmalar

p=3.14159265359;d=1
for a in range(3,p*1e6):
 b=round(a/p);e=abs(p-a/b)
 if e<d:print a,b;d=e

not: Yazmak için daha az karakterlerden oluşuyordu p=3.14159265359;daha from math import*. Kahrolası bu ithalat ithal!


1
Bazı kısaltmalar: 1.0-> 1.,10**6 ->1e6
Keith Randall

Gelişmelerinizle birlikte güncelleme yaptım. Çok teşekkürler.
Steven Rumbalski

@KeithRandall, ancak bunlardan ikincisi çıktıyı belirtimi ihlal ediyor.
Peter Taylor

İkinci yaklaşımda p değişkenine ihtiyaç yoktur. Bu 4 karakter.
Ante

@ PeterTaylor: Anlamıyorum. Spesifikasyonu nasıl ihlal ediyor?
Steven Rumbalski

4

JS (95 karakter)

for(i=k=1,m=Math;i<1e6;i++)if((j=m.abs((x=m.round(m.PI*i))/i-m.PI))<k)k=j,console.log(x+'/'+i)

167 satır yazdırıyor.


4

Yakut 1.9, 84 karakter

m=1;(1..1e6).map{|d|n=(d*q=Math::PI).round;k=(n-q*d).abs/d;k<m&&(m=k;puts [n,d]*?/)}

@Peter Taylor Haklısın. Ruby 1.9 kullanmalısın.
Howard,

4

C99, 113 karakter

main(d,n){double e=9,p=2*asin(1),c,a=1;for(;n=d*p+.5,c=fabsl(p-a*n/d),d<1e6;++d)c<e&&printf("%d/%d\n",n,d,e=c);}

Derlemeniz gerekiyor -lmve muhtemelen tanımsız davranışlarla dolu, ancak bu benim için çalışıyor.


2

Scala - 180 karakter

import math._
def p(z:Int,n:Int,s:Double):Unit=
if(n==1e6)0 else{val q=1.0*z/n
val x=if(abs(Pi-q)<s){println(z+"/"+n)
abs(Pi-q)}else s
if(Pi-q<0)p(z,n+1,x)else p(z+1,n,x)}
p(3,1,1)

// ungolfed: 457

val pi=math.Pi
@annotation.tailrec
def toPi (zaehler: Int = 3, nenner: Int = 1, sofar: Double=1): Unit = {
  if (nenner == 1000000) () 
  else {
    val quotient = 1.0*zaehler/nenner
    val diff = (pi - quotient)
    val adiff= math.abs (diff)
    val next = if (adiff < sofar) {
      println (zaehler + "/" + nenner) 
      adiff 
    }
    else sofar
    if (diff < 0) toPi (zaehler, nenner + 1, next) 
    else toPi (zaehler + 1, nenner, next) 
  }  
}

Tailrec ek açıklaması, genellikle performans iyileştirmesi olan, özyinelemeli olduğunu doğrulamak için sadece bir kontroldür.


Bunu işe alamıyorum:pi.scala:1 error: not found: value math
Keith Randall

Scala 2.8 kullanıyor musunuz?
kullanıcı bilinmeyen

Ölçekim "bilinmeyen versiyon" diyor, garip. İdeone.com'da 2.8.0 kullanıyorlar ve hala hata alıyorum.
Keith Randall

Simplyscala.com adresinde deneyin - benim için çalışıyor. Scala-2.8 için, mathbununla değiştirme Mathyeterli olabilir. Tekrar aramak istersen, bu metathread üzerinde basitçe söylemekten bahsettim: meta.codegolf.stackexchange.com/a/401/373
kullanıcı bilinmeyen

Tamam, işe yarıyor.
Keith Randall,

2

Mathematica 18 17 karakter

Ben, "en iyi" nin bir ölçüsü olarak, f'nın sürekli bir kesri temsilindeki terim sayısını kullanmayı seçtim. Bu kritere göre π'nın en rasyonel yaklaşımları yakınsaklarıdır.

Bir milyondan az bir payda ile conver 10 yakınsama vardır. Bu istenen 167 terimden daha az, ancak başkalarına ilgisini çekebileceği için buraya ekliyorum.

Convergents[π, 10] 

(* out *)
{3, 22/7, 333/106, 355/113, 103993/33102, 104348/33215, 208341/66317,
312689/99532, 833719/265381, 1146408/364913}

İlk yakınsak için paydayı gerçekten görmek istiyorsanız, ek 11 karaktere mal olacak:

Convergents[π, 10] /. {3 -> "3/1"}
(* out *)
{"3/1", 22/7, 333/106, 355/113, 103993/33102, 104348/33215,
208341/66317, 312689/99532, 833719/265381, 1146408/364913}

İlgilenenler için, aşağıdakiler yakınsaklar, kısmi alıntılar ve conver yakınsaklarının sürekli kesir ifadeleri arasındaki ilişkileri göstermektedir:

Table[ContinuedFraction[π, k], {k, 10}]
w[frac_] := Row[{Fold[(#1^-1 + #2) &, Last[#], Rest[Reverse[#]]] &[Text@Style[#, Blue, Bold, 14] & /@ ToString /@ ContinuedFraction[frac]]}];
w /@ FromContinuedFraction /@ ContinuedFraction /@ Convergents[π, 10]

sürekli kesirler

Lütfen devam eden kesirlerin tutarsız formatını affedin.


Bu, çözümün yarısına yakın, ancak en kolay yarısı. GolfScript çözümüm, devam etmekte olan kesimin sadece 2 karakterden daha fazlasında uygun bir gösterimini kodlar.
Peter Taylor,

Ama bu sorunun çözümünde sürekli kesirler kullanmadın, değil mi?
DavidC

Evet. Bunu yapmanın açık yoluydu.
Peter Taylor,

Kısa olmasının yanı sıra, bu, yayınlanan diğer çözümlerin çoğundan veya hepsinden daha hızlıdır.
Michael Stern,

1

C # 140 129 karakter

double n=3,d=1,e=d;while(n<4e5){double w=n/d-Math.PI,a=Math.Abs(w);if(a<e){e=a;Console.WriteLine(n+"/"+d);}if(w>0)d++;else n++;}

Sıkıştırılmamış kod

var numerator = 3d;
var denominator = 1d;
var delta = 4d;
while (numerator < 4e5) 
{
    var newDelta = (numerator / denominator) - Math.PI;
    var absNewDelta = Math.Abs(newDelta);
    if (absNewDelta < delta)
    {
        delta = absNewDelta;
        Console.WriteLine(string.Format("{0}/{1}", numerator, denominator));
    }

    if (newDelta > 0)
    {
        denominator++;
    }
    else
    {
        numerator++;
    }
}

2
varher zaman arkadaşın değil. Bunu doublesizin lehinize kaldırarak , bildirimleri birleştirme yeteneği kazanır, çift değişmez kullanma gereksinimini kaybeder ve 16 karakter kazanabilirsiniz. OTOH soruyu bir programa sorar, böylece bir sınıf beyanı ve bir Mainyöntem eklemek için birkaç tane kaybedersiniz .
Peter Taylor

1

J, 69 65

Yeni

]`,@.(<&j{.)/({~(i.<./)@j=.|@-l)@(%~(i:3x)+<.@*l=.1p1&)"0>:_i.1e3

Yine de kaba kuvvet yaklaşımı, fakat daha hızlı ve biraz daha kısa.

Eski

Basit bir "kaba kuvvet":

(#~({:<<./@}:)\@j)({~(i.<./)@j=.|@-l)@(%~(i:6x)+<.@*l=.1p1&)"0>:i.1e3

bir a/bs listesi yapın ve daha sonra π'dan daha uzak olanları atın.b'<b .

Not: Değişim 1e3için 1e6tam listesi için. Git başka bir şey yap ve sonra geri dön.

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.