二次収束でπを計算する


20

正数取る関数または完全なプログラムの書き込みnとを行うn2外戻り又はプリント次いで(それはほぼすべての反復で正確な桁数を倍増IE)二次収束を有するπを計算するための反復アルゴリズムのステップを、N、正しい数字(含みます始まり3)。そのようなアルゴリズムの1つにGauss–Legendreアルゴリズムがありますが、必要に応じて別のアルゴリズムを自由に使用できます。

例:

入力1→出力3.1
入力2→出力3.141
入力5→出力3.1415926535897932384626433832795

要件:

  • アルゴリズムの各反復は、加算、減算、乗算、除算、累乗、およびルート(整数指数/度付き)などの一定数の基本演算を実行する必要があります。内部に1つ以上のループが含まれる場合。明確にするために、複素数を含む三角関数とべき乗は基本的な操作ではありません。
  • アルゴリズムには、一定数の操作が必要な初期化ステップが含まれることが期待されています。
  • アルゴリズムが2 n個の正しい数字を得るためにさらに1または2回の反復を必要とする場合、n+2ちょうどの代わりに最大反復を実行できますn
  • 十分に明確ではなかった場合、正しい2 n桁の後、プログラムは他のもの(より正確な数字、間違った数字、シェークスピアの完全な作品など)を印刷してはなりませ
  • プログラムはn、1〜20以上の値をサポートする必要があります。
  • あなたのプログラムはn、現代のコンピューターで= 20に1時間以上かかるべきではありません(厳密な規則ではありませんが、合理的なものにしてください)。
  • プログラムは、アルゴリズムの初期化と最初の反復の後、20を超える正確な数字を取得してはなりません。
  • プログラムは、自由に利用可能なソフトウェアを使用してLinuxで実行可能である必要があります。
  • ソースコードはASCII文字のみを使用する必要があります。

得点:

簡単なコードゴルフ、最短のコードが勝ちます。

勝者:

勝者はDigital Traumaです。私はついに彼のコードをn = 20で実行しました(冗談です)。特別賞は、非常に高速なpythonソリューションと異なるアルゴリズムでprimoに贈られます:)


1
二次収束は誤差〜N ^(1/2)です。説明するのは、指数収束誤差〜2 ^(-N)です。
yo

@yo ' ウィキペディアが間違っていると言っていますか?
-aditsu

1
誤解を招くような、少なくとも「二次収束」は~q^(n^2)、そこの最初のセクションとそこ~q^2の2番目のセクションによるものです。
yo

1
私はcodegolfを理解していません:確かに誰でもこのような単一のタスク専用に独自のプログラミング言語を書いてから、たとえば0バイトのプログラムを書くことができますか?
-theonlygusti

2
@theonlygustiは、標準の抜け穴であり、失格になります
aditsu

回答:


14

dc、99バイト

ゴルフ:

2?dsi1+^k1dddsa2v/sb4/stsp[lalb*vlalb+2/dla-d*lp*ltr-stsasblp2*spli1-dsi0<m]dsmxK2/1-klalb+d*4lt*/p

空白と「読みやすさ」のコメント付き:

2?dsi               # Push 2. push input n, duplicate and store in i
1+^k                # Set calculation precision to 2^(n+1)
1dddsa              # Push four 1s. Store 1st in a
2v/sb               # Store 1/sqrt(2) in b
4/st                # Store 1/4 in t
sp                  # Store 1 in p
[                   # Start iteration loop macro
lalb*v              # Save sqrt(a*b) on stack
lalb+2/d            # Save a[i+1] = (a[i]+b[i])/2 on stack and duplicate
la-d*lp*ltr-        # Save t-p(a[i]-a[i+1])^2 on the stack
st                  # Store t result from stack
sa                  # Store a result from stack
sb                  # Store b result from stack
lp2*sp              # Store 2p in p
li1-dsi0<m]         # Decrement iteration counter i; recurse into macro if < 0
dsmx                # Duplicate, store and run macro
K2/1-k              # Set display precision to 2^n-1
lalb+d*4lt*/        # Save (a+b)^2/4t on stack
p                   # Print result

dc使用する精度の桁数を指定する必要があります。計算精度は最終表示精度よりも高い必要があるため、計算精度は2^(n+1)数字に設定されます。http://www.angio.net/pi/digits/pi1000000.txtに対してn = 10の出力の精度を検証しました。

これは、nが大きくなると劇的に遅くなります。VMでn = 12は1.5分かかります。いくつかの異なるサンプルを実行すると、時間の複雑さがO(e ^ n)であることがわかります(驚くことではありません)。これをn = 20に外挿すると、実行時間は233日になります。しかたがない。少なくとも宇宙の熱死よりはましです。

これは中程度のゴルフです-スタックは各反復の計算中に一時変数を削除するために使用されますが、これを短縮するためにスタックをより多く使用する可能性があります。

$ dc glpi.dc <<< 1
3.1
$ dc glpi.dc <<< 2
3.141
$ dc glpi.dc <<< 5
3.1415926535897932384626433832795
$ time dc glpi.dc <<< 7
3.1415926535897932384626433832795028841971693993751058209749445923078\
164062862089986280348253421170679821480865132823066470938446

real    0m0.048s
user    0m0.039s
sys 0m0.000s
$ 

dc出力を70文字でラップしたくない場合は、環境変数DC_LINE_LENGTHを0に設定できます。

$ DC_LINE_LENGTH=0 dc glpi.dc <<< 8
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648
$ 

2
ハハ、「読みやすさ」。実際にはDCには適用されません。;)
アレックスA.

入力5に対して32桁以上を印刷するようです
-aditsu

そのためのルールに加えて、実行時間に関するルールを追加しました(ただし、厳密ではありません)。また、出力がバックスラッシュを使用して複数の行に分割される方法が好きではありませんが、それはDCの制限ですか?
-aditsu

出力がn = 6で間違っているのではないかと
思う-aditsu

1
素晴らしい、そしてあなたもそれを100以下にした:)また、実際のゴルフされた99文字のプログラムを空白やコメントなしで投稿できますか?
-aditsu

10

R、156バイト

このパーティーを始めましょう... Gauss-Legendreアルゴリズムの絶対的な最適実装をこれまでに使用しました。

for(i in 1:scan()){if(i<2){a=p=Rmpfr::mpfr(1,2e6);t=a/4;b=t^t}else{x=(a+b)/2;b=(a*b)^.5;t=t-p*(a-x)^2;a=x;p=2*p};o=(a+b)^2/(4*t)};cat(Rmpfr::format(o,2^i))

Ungolfed +説明:

# Generate n approximations of pi, where n is read from stdin
for (i in 1:scan()) {

    # Initial values on the first iteration
    if (i < 2) {
        a <- p <- Rmpfr::mpfr(1, 1e7)
        t <- a/4
        b <- t^t
    } else {
        # Compute new values
        x <- (a + b) / 2
        b <- (a*b)^0.5
        t <- t - p*(a - x)^2

        # Store values for next iteration
        a <- x
        p <- 2*p
    }

    # Approximate pi 
    o <- (a + b)^2 / (4*t)
}

# Print the result with 2^n digits
cat(Rmpfr::format(o, 2^i))

このmpfr()関数はRmpfrパッケージの一部です。mpfr最初の引数を値として使用し、2番目の引数を精度のビット数として使用してオブジェクトを作成します。1に割り当てap1にt基づいてa(およびにb基づいてt)定義するmpfrことにより、4つの変数すべてに型が伝播し、全体の精度が維持されます。

前述のとおり、これにはRパッケージが必要ですRmpfr。これは、「R Multiple Precision Floating point Reliable」の頭字語です。パッケージはバックグラウンドでGMPを使用します。残念ながら、ベースRには高精度の演算を行う機能がないため、パッケージの依存関係があります。

持っていないRmpfr?汗かいていない。install.packages("Rmpfr")そしてあなたの夢はすべて叶います。

2e6精度として指定されたことに注意してください。つまり、2,000,000ビットの精度があり、少なくともn= 20の精度を維持するのに十分です。(注:n= 20は長い時間がかかりますが、コンピューターでは1時間未満です。)

ここでのアプローチは、文字通りウィキペディアのページにある式を逆流するだけですが、ちょっと、どこかから始めなければなりません。

どんな入力でも大歓迎です!


私はこれの多くを書き直さなければなりませんでしたが、ピーター・テイラーが私の最初のスコアから70バイトをノックするのを助けたことをまだ認めなければなりません。DigitalTraumaの言葉では、「ブーム」。


7

Python 2、214バイト

このチャレンジは、Decimalモジュールを学習する良い言い訳になりました。10進数には定義可能な精度があり、平方根がサポートされています。ループカウントに応じた精度の控えめな推定値に精度を設定しました。

更新

ゴルフを犠牲にして、精度と速度を改善するためにプログラムを更新しました。decimal sqrt()メソッドをx**2使用しx*x、使用法をに置き換えることにより、200倍高速になりました。つまり、20ループを計算できるようになり、6.5時間で100万桁の結果が得られます。10進数の最後の桁にエラーが発生することがよくあります(精度の限界に対する操作が原因)。このため、プログラムは余分な5桁を使用および破棄するため、正確な桁のみが出力されます。

from decimal import*
d=Decimal
e=input()
getcontext().prec=5+(1<<e)
k=d(1)
j=d(2)
g=j*j
h=k/j
a=k
b=k/j.sqrt()
t=k/g
p=k
for i in[0]*e:f=a;a,b=(a+b)/j,(a*b).sqrt();c=f-a;t-=c*c*p;p+=p
l=a+b
print str(l*l/g/t)[:-5]

サンプル実行:

$ echo 1 | python min.py 
3.1
$ echo 2 | python min.py 
3.141
$ echo 3 | python min.py 
3.1415926
$ echo 5 | python min.py 
3.1415926535897932384626433832795
$ echo 12 | python min.py
3.141592653589793238462643383279502884197169399375105820974944592307816406286208
99862803482534211706798214808651328230664709384460955058223172535940812848111745
02841027019385211055596446229489549303819644288109756659334461284756482337867831
65271201909145648566923460348610454326648213393607260249141273724587006606315588
17488152092096282925409171536436789259036001133053054882046652138414695194151160
94330572703657595919530921861173819326117931051185480744623799627495673518857527
24891227938183011949129833673362440656643086021394946395224737190702179860943702
77053921717629317675238467481846766940513200056812714526356082778577134275778960
91736371787214684409012249534301465495853710507922796892589235420199561121290219
60864034418159813629774771309960518707211349999998372978049951059731732816096318
59502445945534690830264252230825334468503526193118817101000313783875288658753320
83814206171776691473035982534904287554687311595628638823537875937519577818577805
32171226806613001927876611195909216420198938095257201065485863278865936153381827
96823030195203530185296899577362259941389124972177528347913151557485724245415069
59508295331168617278558890750983817546374649393192550604009277016711390098488240
12858361603563707660104710181942955596198946767837449448255379774726847104047534
64620804668425906949129331367702898915210475216205696602405803815019351125338243
00355876402474964732639141992726042699227967823547816360093417216412199245863150
30286182974555706749838505494588586926995690927210797509302955321165344987202755
96023648066549911988183479775356636980742654252786255181841757467289097777279380
00816470600161452491921732172147723501414419735685481613611573525521334757418494
68438523323907394143334547762416862518983569485562099219222184272550254256887671
79049460165346680498862723279178608578438382796797668145410095388378636095068006
42251252051173929848960841284886269456042419652850222106611863067442786220391949
45047123713786960956364371917287467764657573962413890865832645995813390478027590
09946576407895126946839835259570982582262052248940772671947826848260147699090264
01363944374553050682034962524517493996514314298091906592509372216964615157098583
87410597885959772975498930161753928468138268683868942774155991855925245953959431
04997252468084598727364469584865383673622262609912460805124388439045124413654976
27807977156914359977001296160894416948685558484063534220722258284886481584560285
06016842739452267467678895252138522549954666727823986456596116354886230577456498
03559363456817432411251507606947945109659609402522887971089314566913686722874894
05601015033086179286809208747609178249385890097149096759852613655497818931297848
21682998948722658804857564014270477555132379641451523746234364542858444795265867
82105114135473573952311342716610213596953623144295248493718711014576540359027993
44037420073105785390621983874478084784896833214457138687519435064302184531910484
81005370614680674919278191197939952061419663428754440643745123718192179998391015
91956181467514269123974894090718649423196156794520809514655022523160388193014209
37621378559566389377870830390697920773467221825625996615014215030680384477345492
02605414665925201497442850732518666002132434088190710486331734649651453905796268
56100550810665879699816357473638405257145910289706414011097120628043903975951567
71577004203378699360072305587631763594218731251471205329281918261861258673215791
98414848829164470609575270695722091756711672291098169091528017350671274858322287
18352093539657251210835791513698820914442100675103346711031412671113699086585163
98315019701651511685171437657618351556508849099898599823873455283316355076479185
35893226185489632132933089857064204675259070915481416549859461637180270981994309
92448895757128289059232332609729971208443357326548938239119325974636673058360414
28138830320382490375898524374417029132765618093773444030707469211201913020330380
19762110110044929321516084244485963766983895228684783123552658213144957685726243
34418930396864262434107732269780280731891544110104468232527162010526522721116603
96665573092547110557853763466820653109896526918620564769312570586356620185581007
29360659876486117

改変されていないコード:

from decimal import *
d = Decimal

loops = input()
# this is a conservative estimate for precision increase with each loop:
getcontext().prec = 5 + (1<<loops)

# constants:
one = d(1)
two = d(2)
four = two*two
half = one/two

# initialise:
a = one
b = one / two.sqrt()
t = one / four
p = one

for i in [0]*loops :
    temp = a;
    a, b = (a+b)/two, (a*b).sqrt();
    pterm = temp-a;
    t -= pterm*pterm * p;
    p += p

ab = a+b
print str(ab*ab / four / t)[:-5]

4
Hehhalf = one/two
デジタルトラウマ

正しい桁数を印刷していないようです。そして、私は遅さが不必要な使用によるものかと思い**ます。
aditsu

1
@aditsu、精度を予想桁数に減らしました(ただし、反復から完全に良好な精度を捨てると、歯がかゆくなります)。**効果に関する良い提案。私はそれらを取り除くことで多くの速度を見つけました。しかし、1時間で20のループに会えません。おそらくpypyまたはCythonを使用していますか?うーん。私はそれを検討します。
ロジックナイト

はるかに良い:)この問題については、良い精度を捨てることは、悪い精度を続けることよりも悪いことではありません。1時間の制限は、java 8で実行したcjam / javaテストコードに基づいています。多分pythonには、多数(Karatsuba&co)の効率的な乗算/除算/ sqrtがありませんか?
-aditsu

@aditsu:整数にはカラツバ(とそれだけ)があると思いますが、64ビットのリムサイズではなく32ビットのリムサイズです。Decimalを知っている人。

5

Python(2.7)-131バイト

from gmpy import*
n=input()
p=a=fsqrt(mpf(8,4<<n));b=0
exec"a=fsqrt(a/2);b=1/(a-a*b+b/a+1);p*=b+a*a*b;a+=1/a;"*n
print`p`[5:2**n+6]

更新:gmpyではなくを使用するようになりましたgmpy2。何らかの理由でgmpy2、単一の値に精度を設定しても、他の値には伝播しません。計算の結果は、現在のコンテキストの精度に戻ります。精度はに伝播しますがgmpy、これは私にとってより直感的です。また、冗長性もかなり低くなります。

BorweinとBorweinによって考案された多くのアルゴリズムの1つを使用して、わずかにリファクタリングしました。n = 20は私のボックスで約11秒かかります。最も効率的な方法ではありませんが、それでも悪くはありません。


リファクタリング

元のアルゴリズムは次のとおりです。




リファクタリングは段階的に行われましたが、最終的な結果は




主な単純化はp n + 1で行われます。また、除算を削除したため、わずかに高速です。

現在の実装では、プッシュnはバックの計算における1回の反復のP N + 1の異なる初期化を可能にする、P 02√2に)、それ以外は同一です。


サンプルの使用法

$ echo 1 | python pi-borwein.py
3.1

$ echo 2 | python pi-borwein.py
3.141

$ echo 5 | python pi-borwein.py
3.1415926535897932384626433832795

$ echo 10 | python pi-borwein.py
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420198938095257201065485863278

素晴らしいですが、n = 7の数字がありません
-aditsu

また、それはこのアルゴリズムですか?
-aditsu

@aditsuは修正しました。そうです。
プリモ

ここで、n = 5の最後の桁が間違っています
-aditsu

1
@aditsu pip install gmpyは私のために働いた。gmpygmpy2は別個のパッケージです。ただし、非推奨に依存していdistutilsます。
プリモ

3

bcおよびNewtonのメソッド、43バイト

関数のゼロを見つけるためのニュートンの方法は二次的に収束し、アルゴリズムはガウス・レジェンドレよりもはるかに簡単です。基本的には次のように要約されます。

xnew = xold-f(xold)/ f '(xold)

したがって、ここに対応するスニペットがあります:

n=20;x=3;scale=2^n;while(n--)x-=s(x)/c(x);x

もう少し読みやすい:

/* desired number of iterations */
n = 20;

/* starting estimate for pi */
x = 3;

/* set precision to 2^n */
scale = 2^n;

/* perform n iteration steps */
while(n--)
  // f:=sin, f'=cos
  x -= s(x)/c(x)

これをテストするにbc -lは、シェルで実行し、上記のスニペットを貼り付けます。しばらく待つ準備をしてください。n=20約5分間実行されており、まだ終わりはありません。n=10約40秒かかります。


4
サインとコサインが「加算、減算、乗算、除算、累乗(根を含む)などの基本演算」として適格かどうかはわかりません。ただし、独自のサイン/コサインをロールした場合は、おそらく受け入れられます。
プリモ

1
ニート式、しかし-それはπをfの固定点(x)であると言う= X - (X)を黄褐色
ケーシーチュー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.