piを5桁まで計算します


15

これは、http://programmers.blogoverflow.com/2012/08/20-controversial-programming-opinions/からのものです。

「Piは4 *(1 – 1/3 + 1/5 – 1/7 +…)の関数を使用して推定できるため、より多くの用語で精度が高くなるため、Piを小数点以下5桁の精度で計算する関数を記述します。 」

  • 上記のシーケンスを計算して、推定を行う必要があることに注意してください。

8
おそらく、そうでなければ、(パイソン)のような答えを得るだろう、いくつかのより多くのルールを追加する必要がありますp=lambda:3.14159
マット・

1
codegolf.stackexchange.com/questions/506/…を見ましたか?彼らは、このような本QBASICプログラムなど些細なソリューションを可能にするので非常に少なくとも、trigの機能は、この問題のために禁止されるべき:INT(4E5 * ATN(1))/ 1E5?
PleaseStand

アルゴリズムは逐次近似の1つである必要があると思います。計算時間が長くなるほど、piに近くなります。
DavidC

@DavidCarraher、これはこのシリーズを使用すると数学的に避けられませんが、数値分析の観点からは非常に疑わしいです。ゆっくりと収束する交互のシリーズは、重要性の喪失のポスターの子です。
ピーターテイラー

2
だまされやすい人が、それは、それはここではありませんので、古いです:stackoverflow.com/q/407518/12274
JB

回答:


10

JavaScript、46 58 56 45バイト

ES6更新:5年が経過した現在、利用可能な機能がさらに増えています。

let f=(i=0,a=0)=>i>1e6?a:f(i+4,a+8/-~i/(i+3))

このバージョン(45バイト。はい、let必須です)は、理論上はES6厳格モード動作ます。実際には、V8で(たとえば、ノードを使用して)を使用して実行できます--use-strict --harmony-tailcalls。残念ながら、適切なTailcalls機能はまだ広く実装されていません。ただし、動作は指定されているため、問題はありません。

厳格なモードを必要とせず、広く実装されているものに固執したい場合は、関数にES6ファットアロー構文を使用しますが、それ以外の場合は48バイトのコストで以前と同じ実装を保持します(ブライアンHが推奨)。

a=>{for(a=i=0;i<1e6;a+=8/++i/~-(i+=3));return a}

単一のパラメーターの名前の選択は実際には重要ではありませが、グローバルスコープの汚染を最小限に抑えるために、使用する名前の1つを選択することもできます。


function(){for(a=i=0;i<1e6;a+=8/++i/~-(i+=3));return a}

このバージョンは関数式です。f名前を付けたい場合は、2文字(たとえば " ")を追加します。このバージョンでは、グローバルを切り詰めaia,iパラメータリストに「」を追加すると、これを防ぐことができます。

減算の必要性を回避するために、アルゴリズムの再公式化されたバージョンを使用します。

 1/1 - 1/3  +   1/5 - 1/7   +    1/9 - 1/11  + ...
(3/3 - 1/3) + (7/35 - 5/35) + (11/99 - 9/99) + ...
    2/3     +      2/35     +       2/99     + ...
  2/(1*3)   +    2/(5*7)    +     2/(9*11)   + ...

この調整なしの「プレーン」バージョンは次のとおりです。

function(){for(a=0,i=1;i<1e6;i+=2)a+=[,4,,-4][i%4]/i;return a}

64 62文字でクロックインします。

取り除くための提案のために@ardnewのおかげ4*return


歴史

function(){for(a=i=0;i<1e6;a+=8/++i/~-(i+=3));return a}     // got rid of `i+=4`; restructured
// Old versions below.
function(){for(a=0,i=1;i<1e6;i+=4)a+=8/i/-~-~i;return a}    // got rid of `4*`
function(){for(a=0,i=1;i<1e6;i+=4)a+=2/i/-~-~i;return 4*a}

非常に素晴らしい仕事です。
アコライト

1
すばらしい仕事ですが、適切な関数として記述する必要があります
-ardnew

@ardnew:ありがとう、問題の説明を読んだときにその詳細を見逃していたに違いない。更新しましたが、現在は呼び出し可能な関数式(ラムダ)です。これが許可されているかどうか、または名前を指定する必要があるかどうかはわかりません。その場合は、とにかく追加の2文字です。
FireFly

1
@FireFlyは、次のように変更a+=2/i/-~-~i;return 4*aすることで2文字を削除することもできますa+=8/i/-~-~i;return a
-ardnew

@ardnew:ああ、素晴らしい。それを考えなかった。:D
FireFly

8

Python 59バイト

print reduce(lambda x,p:p/2*x/p+2*10**999,range(6637,1,-2))

これにより、1000桁が出力されます。必要な5よりわずかに多い5.規定の反復を使用する代わりに、これを使用します

pi = 2 + 1/3*(2 + 2/5*(2 + 3/7*(2 + 4/9*(2 + 5/11*(2 + ...)))))

6637(最も内側の分母)として製剤化することができます。

数字* 2 * log 2(10)

これは、線形収束を意味します。より深い反復ごとに、piのもう 1つのバイナリビットが生成されます。

場合は、しかし、あなたが使用して主張日焼け-1アイデンティティをあなたは少し異なる問題について行く気にしない場合は、同様の収束が、実現することができます。部分的な合計を見てみましょう:

4.0、2.66667、3.46667、2.89524、3.33968、2.97605、3.28374、...

各項が収束点の両側に前後にジャンプすることは明らかです。シリーズには交互収束があります。さらに、各用語は前の用語よりも収束点に近くなります。収束点に関して絶対的に単調です。これら2つの特性の組み合わせは、2つの隣接する用語の算術平均が、用語自体のいずれよりも収束点に近いことを意味します。私が何を意味するのかをよりよく理解するために、次の画像を検討してください。

Partial Sums

外側の系列は元の系列であり、内側の系列は、隣接する各用語の平均を取ることで見つかります。顕著な違い。しかし、本当に注目すべきことは、この新しいシリーズにも交互収束があり、その収束点に関して絶対的に単調であることです。それは、このプロセスが何度も何度も適用される可能性があることを意味します。

OK。しかし、どのように?

いくつかの正式な定義。LET P 1(N)であるN 番目の第一の配列の用語、P 2(n)はであるN 番目の第二の配列の用語は、同様にPのK(n)は、N 番目の用語のk 番目の上記で定義された配列。

P 1 = [P 1(1)、P 1(2)、P 1(3)、P 1(4)、P 1(5)、...]

P 2 = [(P 1(1)+ P 1(2))/ 2、(P 1(2)+ P 1(3))/ 2、(P 1(3)+ P 1(4))/ 2、(P 1(4)+ P 1(5))/ 2、...]

P 3 = [(P 1(1)+ 2P 1(2)+ P 1(3))/ 4、(P 1(2)+ 2P 1(3)+ P 1(4))/ 4、(P 1(3)+ 2P 1(4)+ P 1(5))/ 4、...]

P 4 = [(P 1(1)+ 3P 1(2)+ 3P 1(3)+ P 1(4))/ 8、(P 1(2)+ 3P 1(3)+ 3P 1(4) + P 1(5))/ 8、...]

驚くことではないが、これらの係数は二項係数に正確に従い、Pascalの三角形の単一行として表すことができます。パスカルの三角形の任意の行は計算するのが簡単なので、最初のn個の部分和を取るだけで、パスカルの三角形のk 番目の行の対応する項をそれぞれ乗算し、2で除算することにより、任意の「深い」系列を見つけることができますK-1

このようにして、完全な32ビット浮動小数点精度(小数点以下14桁)をたった36回の反復で達成できます。これは明らかにゴルフではありません:

# used for pascal's triangle
t = 36; v = 1.0/(1<<t-1); e = 1
# used for the partial sums of pi
p = 4; d = 3; s = -4.0

x = 0
while t:
  t -= 1
  p += s/d; d += 2; s *= -1
  x += p*v
  v = v*t/e; e += 1

print "%.14f"%x

任意の精度が必要な場合は、少し変更するだけでこれを実現できます。ここでもう一度1000桁を計算します。

# used for pascal's triangle
f = t = 3318; v = 1; e = 1
# used for the partial sums of pi
p = 4096*10**999; d = 3; s = -p

x = 0
while t:
  t -= 1
  p += s/d; d += 2; s *= -1
  x += p*v
  v = v*t/e; e += 1

print x>>f+9

初期値pが始まる2 10の整数除算の影響を打ち消すために、より大きなS / Dとして、Dが収束していないために、最後の数桁を引き起こし、大きくなります。ここでも、次のことに注意してください3318

桁*ログ2(10)

最初のアルゴリズムと同じ回数の反復(tは反復ごとに2ではなく1ずつ減少するため、半分になります)。繰り返しますが、これは線形収束を示します:反復ごとに1 ビットのpiのバイナリ。どちらの場合でも、1000 piの計算には3318回の反復が必要です。これは、5を計算する100万回の反復よりもわずかに優れたクォータです。


それははるかに良い私の解決策よります:4 * sum(1/(1+i*2) if not i%2 else -1/(1+i*2) for i in xrange(places*10**(places)))
アーロン・ホール

1
これは私のアプローチと非常によく似ていますが、たまたまあなたのものとは異なる形になっています。私の場合、としてk → ∞f(-1,k)オイラー合計に近づきます。
単に美しいアート

1
とてもかっこいい; 素晴らしい分析と説明、ありがとう。
ジェレミーラドクリフ

ほんの小さなこと。行と?の代わりにP_1 = ..., P_2 = ..., P_3 = ..., P_4 = ...、「... kthパスカルの三角形の行の対応する用語をそれぞれ乗算し、。で除算する」ことを意味しませんでしたか?2^{k-1}nth2^{n-1}
ジェレミーラドクリフ

@jeremyradcliffはい、そうでした。修正していただきありがとうございます。
プリモ

5

Mathematica 42 39 34 33 31 26 32

アルキメデスのアプローチ 26文字

N@#*Sin[180 Degree/#]&

これは、入力が822のときに基準に達します。

質問:180度の罪をどのように計算したか誰もが知っていますか?しません。


ライプニッツのアプローチ(グレゴリーのシリーズ)32文字

これは、問題提起者が例として与えたのと同じ機能です。約50万回の反復で基準に達します。

N@4Sum[(-1)^k/(2k+1),{k,0,10^6}]

Madhava-Leibniz Approach 37 chars

このバリエーションではさらにいくつかの文字を使用しますが、わずか9回の反復で基準に収束します!

N@Sqrt@12 Sum[(-1/3)^k/(2k+1),{k,0,9}]

それらはすべて問題定義で与えられたアルゴリズムによってそれを計算しますか?
アコライト

@acolyte Leibnizのアプローチ(現在リストされている最初のアプローチ)は、実際に問題の説明で言及されているものです。収束に非常に時間がかかります。そのわずかな変化(Madhava-Leibniz)は非常に迅速に収束します。
DavidC

180°のサインは非常に簡単です。Nの通常の容疑者以外ではトリッキーになる可能性があるのは180°/ Nです。
JB12年

説明してください、@ JB Tricky to measure?
DavidC

ライプニッツのアプローチのみが要件を満たしているため、このエントリは「32」を示す必要があります(コード内の文字をカウントすると、34が得られますが、両方のスペースを安全に削除でき、実際に32の長さが得られます)。
celtschk


4

Java(67文字)

float r(){float p=0,s=4,i=1E6f;while(--i>0)p+=(s=-s)/i--;return p;}

これは、正しい順序で数字を加算することにより、重要性の損失を回避することに注意してください。


これも完全に準拠したCコードです。Cとして投稿した場合は、2文字に変更while(--i>0)while(i--)て保存できます
-ardnew

1
@ardnew、真のは、しかし、Cと遊ぶのがはるかに興味深いトリックが...ある
ピーター・テイラー



3

C(GCC)(44文字)

float p(i){return i<1E6?4./++i-p(++i):0;}

これは41文字ですが-O2、オプティマイザーが末尾再帰を排除するようにコンパイルする必要もあります。これ++は、実行される順序に関して未定義の動作にも依存します。これを指摘してくれたugorenに感謝します。64ビットLinuxでgcc 4.4.3を使用してテストしました。

オプティマイザーが合計も並べ替えない限り、最小数から加算されるため、重要性が失われることはありません。

として呼び出しますp()


あなたの再帰呼び出しはq()、ではありませんp()。そして、私は-O2カウントされるべきではないと思います(しかし、あなたがそれをカウントするなら、それは必要なスペースのために4文字です)。
ウゴレン

また:1. gcc 4.1.1は再帰を最適化しません(そしてどのようにできるかわかりません)。そのため、スタックがオーバーフローします。2.として呼び出す必要がありますp(0)。3.で文字を保存しますreturn++i...。4. 2つ++iは未定義の動作をします。
ウゴレン

@ugoren、コメントありがとう。順序:q-名前を変更した後、再確認することを教えてくれます。私は-O23文字としてカウントする通常の慣行に従っていると思いますが、必要に応じてメタで開くことができます。meta.codegolf.stackexchange.com/questions/19は、私が見つけることができる唯一の関連する議論です。使用しているgccのバージョンを追加しましたp()。これにより、として呼び出すことができます。文字を保存すると、オプティマイザーが停止し、セグメンテーション違反が発生します。meta.codegolf.stackexchange.com/questions/21に従って
ピーターテイラー

フラグに関するメタ質問への回答を追加しました。についてp()- p()どんなコンテキストから呼び出しても動作しますか?それとも、あなたのテストでたまたまスタック上にあったものですか?
ウゴレン

@ugoren、多分私は一貫して幸運を得た。続けて2回呼び出しても、2番目の呼び出しは正しい値を返します。gccはp()vs に対してわずかに異なるコードを生成するように見えますがp(0)、それがどのような動作を文書化するのかわかりませんし、実際にはCプログラマーでもありません。
ピーターテイラー

3

J、26文字

+ / + / _ 2((4 _4)&%)>:+:i.100

シーケンスの100アイテムから1e6アイテムに移動しました。また、今ではタグ付けされたコードであり、ブラウザからコンソールにエラーなしでコピーペーストできます。

+/+/_2((4 _4)&%)\>:+:i.1e6

3
-/4%>:2*i.1e6-13文字。(#jsoftwareのb_jonasに感謝し-/ます。これは、交互に符号を付けて合計を計算するように働きます。[これは、Jのすべての演算子が同じ優先順位で右結合であるため、-/ 1 2 3 4< 1 - (2 - (3 - 4))= > < = > 1 - 2 + 3 - 4。])
FireFly

それはきちんとしていて、2倍素晴らしいです。またはさらに2 ^ 10ものすごい!
fftw

美しい@FireFly
ジョナ

2

Javascript-33文字

p=x=>4*(1-(x&2))/x+(x>1?p(x-2):0)

p正の奇数を渡して呼び出すxと、(x-1)/2項でPiを計算します。


2

ルビー-82文字

def f(n,k=n)k>0?(f(n,k-1)+f(n+1,k-1))/2:n<0?0:f(n-1,0)+(-1)**n/(2*n+1.0)end;4*f(9)

それを試してみてください : https //repl.it/LQ8w

このアプローチでは、数値加速アプローチを使用して、指定されたシリーズを間接的に使用します。結果の出力は

pi ≈ 3.14159265161

pi = 3.14159265359

それでは始まります

f(n,0) = 1/1 - 1/3 + 1/5 - ... + ((-1)**n)/(2*n+1)

そして、これは交互に行われるため、次を使用して収束を加速できます。

f(n,1) = (f(n,0) + f(n+1,0))/2

そして、これは繰り返し適用されます:

f(n,k) = (f(n,k-1) + f(n+1,k-1))/2

そして、簡単にするために、f(n) = f(n,n)


ルビー-50文字

あなたが本当に長い間走ることを気にしないなら、あなたは単に使うことができます

def f(n)n<0?0:f(n-1)+(-1)**n/(2*n+1.0)end;4*f(1e7)

または

a=0;for k in 0..1e7 do a+=(-1)**k/(2*k+1.0)end;4*a

1

C、69文字

float p,b;void main(a){b++<9e6?p+=a/b++,main(-a):printf("%f\n",4*p);}
  • コマンドラインパラメータなしで実行します(だから a、1に初期化されます)。
  • 最適化してコンパイルする必要があります。
  • void main奇妙で非標準ですが、動作します。これがないと、再帰は実際の呼び出しとして実装され、スタックオーバーフローが発生します。別の方法は追加ですreturnです。
  • 4*3つのコマンドラインパラメーターで実行する場合、2文字を保存できます。

あなたはにそれを短縮することができint main(a)、さらにはmain(a)、GCCは警告のみを提供します。void mainとにかく警告が表示されます。おそらく、に対する引数が1つしかないためですmain
nyuszika7h

1

Clojure-79文字

(fn [](* 4(apply +(map #(*(Math/pow -1 %1)(/ 1.0(+ 1 %1 %1)))(range 377000)))))

これにより、piを小数点以下5桁まで正しく近似するfloatを計算する引数なしの関数が作成されます。これはのような名前に関数を結合しないことに注意してくださいpi。このコードは、どちらかと所定の位置に評価されなければならないので、evalとして、(<code>)または溶液である場合には、名前にバインドされました

(defn p[](* 4(apply +(map #(*(Math/pow -1 %1)(/ 1.0(+ 1 %1 %1)))(range 377000)))))

82文字

(defn nth-term-of-pi [n] (* (Math/pow -1 n) (/ 1.0 (+ 1 n n))))
(defn pi [c] (* 4 (apply + (map nth-term-of-pi (range c)))))
(def  pi-accuracy-constant (loop [c 1000] (if (< (pi c) 3.14159) (recur (inc c)) c)))
; (pi pi-accuracy-constant) is then the value of pi to the accuracy of five decimal places

1

PHP- 56 55文字

<?for($j=$i=-1;1e6>$j;){$p+=($i=-$i)/($j+=2);}echo$p*4;

アルゴリズムの規則を破らずにもっと小さくできることはわかりません。


1
45でこれはどうですか?<?for(;1e6>$j;)$p+=($i=-$i|4)/~-$j+=2;echo$p;
プリモ

私はそれを考え出そうとしていましたが、ビット単位の操作を動作させることができませんでした。提案をありがとう!
-TwoScoopsofPig

最後のセミコロンを削除して、1文字節約できます。
nyuszika7h

1

Perl- 43 39文字

無名サブルーチンのルールは定かではありませんが、@ FireFlyのシリーズ構築を使用した別の実装があります

sub{$s+=8/((4*$_+2)**2-1)for 0..1e6;$s}

sub p{$s+=(-1)**$_*4/(2*$_+1)for 0..1e6;$s}


0

Java- 92 84文字

私はピーター・テイラーの結果をはるかに上回ることはできませんが、ここに私のものがあります:

double d(){float n=0,k=0,x;while(n<9E5){x=1/(1+2*n++);k+=(n%2==0)?-x:x;}return 4*k;}

ゴルフされていないバージョン:

double d() {
    float n = 0, k = 0, x;
    while (n < 9E5) {
        x = 1 / (1 + 2 * n++);
        k += (n % 2 == 0) ? -x : x;
    }
    return 4 * k;
}

編集:三項演算子を使用して数文字を保存しました。


0

Python-56文字

まあ、私のpython-fuは十分に強力ではありません。ショートカットはこれ以上表示できませんでしたが、経験豊富なゴルファーはここでトリムするものを見つけることができますか?

t=s=0
k=i=1
while t<1e6:t,s,i,k=t+1,k*4./i+s,i+2,-k

Python 3を使用して、フロート除算(4.-> 4)のために1バイトを保存できます。他のニュースで、Python 3が実際にコードゴルフでPython 2に勝るケースを見つけました!
nyuszika7h 14

0

ルビー-54文字

def a()p=0;1000000.times{|i|p+=8/(4*i*(4*i+2))};p;end;

コンソールでの最初の試行

def a()i=1;p=0;while i<2**100 do p+=8/(i*(i+2));i+=4;end;p;end;

63文字。


def a;代わりにを使用してバイトを保存できますdef a()
nyuszika7h 14

最後のセミコロンを削除する別の方法。
nyuszika7h 14

0

Perl(76文字)

$y=1e4;for$x(0..1e4-1){$y--while sqrt($x**2+$y**2)>1e4;$a+=$y}print 4*$a/1e8

(結果:3.14159052)

最短の解決策ではありませんが、興味深いかもしれません。それは幾何学的なものです。円の下の面積を計算します。

私は別の面白いアプローチを得ましたが、それは本当に遅いです。四分円より下にある正方形の離散点の数をカウントし、それからpiを計算します。

$i=shift;for$x(0..$i){for$y(0..$i){$h++if sqrt($x**2+$y**2)<$i}}print$h*4/$i**2

コマンドライン引数として反復回数が必要です。ここでは、実行時間と精度の関係を確認できます。;)

$ time perl -e '$i=shift;for$x(0..$i){for$y(0..$i){$h++if sqrt($x**2+$y**2)<$i}}print$h*4/$i**2' 100
3.1796
real    0m0.011s
user    0m0.005s
sys 0m0.003s

$ time perl -e '$i=shift;for$x(0..$i){for$y(0..$i){$h++if sqrt($x**2+$y**2)<$i}}print$h*4/$i**2' 1000
3.14552
real    0m0.354s
user    0m0.340s
sys 0m0.004s

$ time perl -e '$i=shift;for$x(0..$i){for$y(0..$i){$h++if sqrt($x**2+$y**2)<$i}}print$h*4/$i**2' 10000
3.14199016
real    0m34.941s
user    0m33.757s
sys 0m0.097s

0

k(25文字)

4 * + /%(i#1 -1)'1 + 2!i:1000000

少し短い:

+/(i#4 -4)%1+2*!i:1000000




0

SQL、253バイト

DECLARE @B int=3, @A varchar(max), @C varchar(max)='1'
WHILE @B<100000
BEGIN
SELECT @C=@C+(select case when (@B-1)%4=0 then'+'else'-'end)+
(SELECT cast(cast(1.0/@B as decimal(9,8)) as varchar(max)))
SELECT @B=@B+2
END
EXECUTE('SELECT 4*('+@C+')')

私はSQL Fiddleを提供しますが、これは1/3 1/5 1/7などの分数を見つけるためにループが深くなりすぎて、エラーを出します(笑)。ただし、次に変更@B<100000する1000と、同じ桁数の精度ではないことは明らかです。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.