piの適切な合理的近似


22

分母の順序が小さい順に、分母<1000000のpiのすべての適切な合理的近似を出力するプログラムを作成します。 a/bは、分母がを超えない他の有理数よりもpiに近い場合、piの「適切な有理数近似」ですb

出力には合計167行が含まれ、開始と終了は次のようになります。

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

最短のプログラムが勝ちます。

回答:


23

Golfscript、71 70 69文字

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

(stdinで何も渡さないと仮定)

piの組み込み定数を持たない人からは、これ以上のうなり声を聞きたくありません。浮動小数点数さえありません!

背景については、http://en.wikipedia.org/wiki/Continued_fraction#Best_rational_approximationsを参照してください

# 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
技術的には、GolfScriptにはPIの浮動小数点数と定数の両方があります。という名前"#{Math.PI}"です。
コンラッドボロスキー

2
@GlitchMr、文字列はどのように浮動小数点数ですか?
ピーターテイラー

これがコメント付きで展開されるのを本当に見たいです。
プリモ

すごい。最初の行は2\!:^2^..292^15.2/3]すでに私の心を吹き飛ばしました。
プリモ

@PeterTaylor Tied。もっと良くできますか?
エルベックス14

11

Mathematica、67 63

これは高速ではありませんが、技術的には正しいと思います。

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

Round[π, x]はに最も近い分数をのステップで与えますx。これは「リスト可能」なのでRound[π,1/Range@1*^6]、すべての分数について1/10^6順番にこれを行います。多くの「悪い」有理近似を持つ結果リスト//.は、前の要素よりもπから遠い要素を削除することにより繰り返し処理されます()。


かなりクールですが、Mathematicaを持っていないのでテストできません。
キースランドール

@キース、ここにロジックがあります。 Round[Pi, x]に最も近い分数をのPiステップで与えるx。これは「リスト可能」なのでRound[Pi,1/Range@1*^6]、1/10 ^ 6までのすべての分数に対して順番にこれを行います。多くの「悪い」有理近似を持つ結果リスト//.は、前の要素よりもπから遠い要素を削除することにより繰り返し処理されます()。
Mr.Wizard

GolfScriptを破るMathematica。きちんとした。
SpellingD

61年:Select[Round[f=Pi,1/Range@1*^6],If[#<f,f=#;True]&@Abs[#-Pi]&]...しかし、支配的なバイアスを考えると役に立たない
ベリサリウス博士14

ヤール、マティ。このコードでは魔法になります。
マイケルスターン14

7

Perl、77文字

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

些細な課題は、Perlには組み込みのπ定数がないため、最初にとして計算する必要があったことatan2(0,-1)です。これは仕事により適した言語に負けてしまうと思いますが、主にテキスト処理用に設計された言語にとっては悪くありません。


1
3文字に変更9999991e6て保存できます。
トト

@ M42:ありがとう!現在82文字まで。
イルマリカロネン

本当にいい、整数を取得するには$ =。申し訳ありませんが、2回は投票できません。
トト

これを実行することはできません:String found where operator expected at prog.pl line 1, near "say"$=/$_""
キースランドール

@KeithRandall:コマンドには-M5.01スイッチ(およびPerl 5.10.0以降)が必要sayです。それについて言及していないことを申し訳ありません。
イルマリカロネン

5

Python、96 93 89文字

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文字、異なるアルゴリズム

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

注:書くために以下の文字だったp=3.14159265359;よりもfrom math import*。これらの冗長なインポートをくそ!


1
いくつかの短縮:1.0-> 1.10**6->1e6
キースランドール

私はあなたの改善で更新しました。どうもありがとう。
スティーブンランバルスキー

@KeithRandall。ただし、2番目の出力は仕様に違反します。
ピーターテイラー

2番目のアプローチでは、変数pは必要ありません。それは4文字です。
アンテ

@PeterTaylor:わかりません。仕様にどのように違反しますか?
スティーブンランバルスキー

4

JS(95文字)

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行を印刷します。


4

Ruby 1.9、84文字

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]*?/)}

@ピーター・テイラーそうですね。Ruby 1.9を使用する必要があります。
ハワード

4

C99、113文字

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);}

でコンパイルする必要が-lmあり、おそらく未定義の動作でいっぱいですが、それは私のために機能します。


2

Scala-180文字

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)

//制限なし: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注釈は、末尾再帰であることを確認するための単なるチェックであり、多くの場合、パフォーマンスが向上します。


私は仕事にこれを取得することはできません:pi.scala:1 error: not found: value math
キース・ランドール

Scala 2.8を使用していますか?
ユーザー不明

私のscalaは「不明なバージョン」と言っていますが、変です。ideone.comでは、2.8.0を使用していますが、それでもエラーが発生します。
キースランドール

simplyscala.comで試してみてください。Scalaの-2.8の場合は、交換mathをすることはMath十分かもしれません。あなたは再びそれを検索するために起こる場合、私は、このmetathreadにsimplyscalaを述べた:meta.codegolf.stackexchange.com/a/401/373
ユーザーの不明を


2

Mathematica 18 17文字

私は、「最良」の尺度として、πの連続分数表現の項の数を使用することを選択しました。この基準により、πの最良の有理近似はその収束です。

πの収束点は10個あり、分母は100万未満です。これは要求された167の用語よりも少ないですが、他の人に興味があるかもしれないので、ここに含めています。

Convergents[π, 10] 

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

最初の収束の分母を本当に見たい場合は、追加の11文字がかかります。

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}

興味のある人のために、以下は、収束、部分商、およびπの収束の連分数表現の間の関係を示しています。

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]

連続分数

継続分数の一貫性のないフォーマットを許してください。


これは解決策のほぼ半分ですが、最も簡単な半分です。私のGolfScriptソリューションは、継続分数の適切な表現をさらに2文字だけでハードコーディングします。
ピーターテイラー

しかし、あなたはこの質問の解決に連続した分数を使用しませんでしたか?
DavidC

はい。それは明らかな方法でした。
ピーターテイラー

簡潔であることに加えて、これは投稿されている他のほとんどまたはすべてのソリューションよりもはるかに高速です。
マイケルスターン14

1

C#140 129文字

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++;}

非圧縮コード

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
varいつもあなたの友達ではありません。削除することで、double宣言をマージする機能が得られ、ダブルリテラルを使用する要件がなくなり、16文字を節約できます。質問はプログラムを要求するOTOHなので、クラス宣言とMainメソッドを追加するためにいくつかを失います。
ピーターテイラー

1

J、69 65

新しい

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

依然としてブルートフォースアプローチですが、はるかに高速で少し短いです。

古い

単純な「ブルートフォース」:

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

a/bsのリストを作成して から、一部のについてπから遠いものを破棄しb'<bます。

注:完全なリストに変更1e31e6ます。他のことをして、後で戻ってください。

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