これは、http://programmers.blogoverflow.com/2012/08/20-controversial-programming-opinions/からのものです。
「Piは4 *(1 – 1/3 + 1/5 – 1/7 +…)の関数を使用して推定できるため、より多くの用語で精度が高くなるため、Piを小数点以下5桁の精度で計算する関数を記述します。 」
- 上記のシーケンスを計算して、推定を行う必要があることに注意してください。
これは、http://programmers.blogoverflow.com/2012/08/20-controversial-programming-opinions/からのものです。
「Piは4 *(1 – 1/3 + 1/5 – 1/7 +…)の関数を使用して推定できるため、より多くの用語で精度が高くなるため、Piを小数点以下5桁の精度で計算する関数を記述します。 」
回答:
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文字(たとえば " ")を追加します。このバージョンでは、グローバルを切り詰めa
とi
、a,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}
a+=2/i/-~-~i;return 4*a
することで2文字を削除することもできますa+=8/i/-~-~i;return a
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つの隣接する用語の算術平均が、用語自体のいずれよりも収束点に近いことを意味します。私が何を意味するのかをよりよく理解するために、次の画像を検討してください。
外側の系列は元の系列であり、内側の系列は、隣接する各用語の平均を取ることで見つかります。顕著な違い。しかし、本当に注目すべきことは、この新しいシリーズにも交互収束があり、その収束点に関して絶対的に単調であることです。それは、このプロセスが何度も何度も適用される可能性があることを意味します。
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)))
P_1 = ..., P_2 = ..., P_3 = ..., P_4 = ...
、「... kth
パスカルの三角形の行の対応する用語をそれぞれ乗算し、。で除算する」ことを意味しませんでしたか?2^{k-1}
nth
2^{n-1}
アルキメデスのアプローチ 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}]
foldr(\k->(4/(2*k+1)-))0[0..8^7]
GHCi> foldr(\ k->(4 /(2 * k + 1)-))0 [0..8 ^ 7]
3.141593130426724
関数名を数える
π=foldr(\k->(4/(2*k+1)-))0[0..8^7]
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文字です)。
p(0)
。3.で文字を保存しますreturn++i...
。4. 2つ++i
は未定義の動作をします。
q
-名前を変更した後、再確認することを教えてくれます。私は-O2
3文字としてカウントする通常の慣行に従っていると思いますが、必要に応じてメタで開くことができます。meta.codegolf.stackexchange.com/questions/19は、私が見つけることができる唯一の関連する議論です。使用しているgccのバージョンを追加しましたp()
。これにより、として呼び出すことができます。文字を保存すると、オプティマイザーが停止し、セグメンテーション違反が発生します。meta.codegolf.stackexchange.com/questions/21に従って
p()
- p()
どんなコンテキストから呼び出しても動作しますか?それとも、あなたのテストでたまたまスタック上にあったものですか?
p()
vs に対してわずかに異なるコードを生成するように見えますがp(0)
、それがどのような動作を文書化するのかわかりませんし、実際にはCプログラマーでもありません。
J、26文字
+ / + / _ 2((4 _4)&%)>:+:i.100
シーケンスの100アイテムから1e6アイテムに移動しました。また、今ではタグ付けされたコードであり、ブラウザからコンソールにエラーなしでコピーペーストできます。
+/+/_2((4 _4)&%)\>:+:i.1e6
-/4%>:2*i.1e6
-13文字。(#jsoftwareのb_jonasに感謝し-/
ます。これは、交互に符号を付けて合計を計算するように働きます。[これは、Jのすべての演算子が同じ優先順位で右結合であるため、-/ 1 2 3 4
< 1 - (2 - (3 - 4))
= > < = > 1 - 2 + 3 - 4
。])
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)
。
あなたが本当に長い間走ることを気にしないなら、あなたは単に使うことができます
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
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
。
(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
<?for($j=$i=-1;1e6>$j;){$p+=($i=-$i)/($j+=2);}echo$p*4;
アルゴリズムの規則を破らずにもっと小さくできることはわかりません。
<?for(;1e6>$j;)$p+=($i=-$i|4)/~-$j+=2;echo$p;
私はピーター・テイラーの結果をはるかに上回ることはできませんが、ここに私のものがあります:
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;
}
編集:三項演算子を使用して数文字を保存しました。
まあ、私のpython-fuは十分に強力ではありません。ショートカットはこれ以上表示できませんでしたが、経験豊富なゴルファーはここでトリムするものを見つけることができますか?
t=s=0
k=i=1
while t<1e6:t,s,i,k=t+1,k*4./i+s,i+2,-k
4.
-> 4
)のために1バイトを保存できます。他のニュースで、Python 3が実際にコードゴルフでPython 2に勝るケースを見つけました!
ルビー-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()
。
$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
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
と、同じ桁数の精度ではないことは明らかです。
p08p109p^v*86%+55:<$$$<
\$\>:#,_@>+\55+/:#^_"."
v>p"~"/:"~"%08p"~"/00p:2\4%-*"(}"
8^90%"~":+2:+g90*+g80*<
>*:**\/+>"~~"00g:"~"`!|
誰かが疑問に思っている場合、それは象です。
p=lambda:3.14159