Piでの数字の実行


13

あなたの目標は、pi(π)の連続した同一の数字の厳密に増加するシーケンスを出力することです。シーケンスの各用語は、前の用語より1桁長くする必要があります。したがって、3(piの0桁目)は、一連の数字(長さ1)が最初に発生するときです。次に発生するのは33(piの桁24および25)です。もちろん、このシーケンスでは、piの桁が10を底とする必要があります。

これまで知られているもの、および最初の6つはすべて最初の800桁以内で発生します。

3
33
111
9999
99999
999999
3333333
44444444
777777777
6666666666
... (not in first 2 billion digits)

同じランで連続した9がすべて一緒に発生することに注意してください。したがって、見つかった次の大きなランが1000の連続したものである場合、シーケンスの複数の0が埋められます。

私は自分のプログラムにこれ以上条件を見つけていません。最初の50000桁以上にはもう用語がないことを知っています。私のプログラムは500000桁で時間がかかりすぎたため、あきらめました。

参照実装

してもいいです:

  • シーケンスを永久に出力する
  • 整数nを取り、nシーケンスの最初の数を見つけます
  • 整数nn取得し、piの最初の桁に含まれるシーケンスの数値を見つけます。

コードで実行するものを指定してください。番号nは0または1である場合があります。

このmathoverflowの質問に触発されました。


1
関連 -9を実行すると、多くの回答で頭痛が発生しました。P
Mego

空のシーケンスで出力を開始できますか?
LegionMammal978

2
また、シーケンスの次の用語は、10 ^ -710100〜10 ^ -710106の数字で3333333のように見えます。n = 8 の値は、最初の5 000 000桁には表示されません。
LegionMammal978

4
さらに2つの用語:数字10 ^ -22931745から10 ^ -22931752の44444444と数字10 ^ -24658601から10 ^ -24658609の777777777。n = 10 の値は、最初の100,000桁には表示されません。
LegionMammal978

1
もう1つの用語:6666666666 at 10 ^ -386980412。11番目の用語は、最初の2 000 000 000桁には表示されません。
プリモ

回答:


5

Mathematica、85バイト

FromDigits/@DeleteDuplicatesBy[Join@@Subsets/@Split@RealDigits[Pi,10,#][[1]],Length]&

無名関数。テイク Nの入力として、及び第一のシーケンスの要素を返し、n個の πの桁。出力はの形式です{0, 3, 33, 111, ...}


4

Python 2、110バイト

n=input()
x=p=7*n|1
while~-p:x=p/2*x/p+2*10**n;p-=2
l=m=0
for c in`x`:
 l=l*(p==c)+1;p=c
 if l>m:m=l;print p*l

チェックする最大桁数は、stdinから取得されます。PyPy 5.3では、10,000桁が約2秒で終わります。

サンプルの使用法

$ echo 10000 | pypy pi-runs.py
3
33
111
9999
99999
999999

役に立つもの

from sys import argv
from gmpy2 import mpz

def pibs(a, b):
  if a == b:
    if a == 0:
      return (1, 1, 1123)
    p = a*(a*(32*a-48)+22)-3
    q = a*a*a*24893568
    t = 21460*a+1123
    return (p, -q, p*t)
  m = (a+b) >> 1
  p1, q1, t1 = pibs(a, m)
  p2, q2, t2 = pibs(m+1, b)
  return (p1*p2, q1*q2, q2*t1 + p1*t2)

if __name__ == '__main__':
  from sys import argv
  digits = int(argv[1])

  pi_terms = mpz(digits*0.16975227728583067)
  p, q, t = pibs(0, pi_terms)

  z = mpz(10)**digits
  pi = 3528*q*z/t

  l=m=0
  x=0
  for c in str(pi):
   l=l*(p==c)+1;p=c
   if l>m:m=l;print x,p*l
   x+=1

このために、CudnovskyからRamanujan 39に切り替えました。Chudnovskyは1億桁でシステムのメモリを使い果たしましたが、Ramanujanはわずか38分で4億に達しました。これは、少なくともリソースが限られているシステムでは、用語の成長率が最終的に遅くなる別のケースだと思います。

サンプルの使用法

$ python pi-ramanujan39-runs.py 400000000
0 3
25 33
155 111
765 9999
766 99999
767 999999
710106 3333333
22931752 44444444
24658609 777777777
386980421 6666666666

より高速な無制限ジェネレーター

問題の説明に記載されているリファレンス実装は興味深いものです。それは、Piの桁のための論文Unbounded Spigot Algorithmsから直接取られた、無制限のジェネレーターを使用します。著者によると、提供された実装は「意図的に曖昧」であるため、意図的に難読化することなく、著者によってリストされた3つのアルゴリズムすべての新しい実装を作成することにしました。また、Ramanujan#39に基づいて4番目を追加しました。

try:
  from gmpy2 import mpz
except:
  mpz = long

def g1_ref():
  # Leibniz/Euler, reference
  q, r, t = mpz(1), mpz(0), mpz(1)
  i, j = 1, 3
  while True:
    n = (q+r)/t
    if n*t > 4*q+r-t:
      yield n
      q, r = 10*q, 10*(r-n*t)
    q, r, t = q*i, (2*q+r)*j, t*j
    i += 1; j += 2

def g1_md():
  # Leibniz/Euler, multi-digit
  q, r, t = mpz(1), mpz(0), mpz(1)
  i, j = 1, 3
  z = mpz(10)**10
  while True:
    n = (q+r)/t
    if n*t > 4*q+r-t:
      for d in digits(n, i>34 and 10 or 1): yield d
      q, r = z*q, z*(r-n*t)
    u, v, x = 1, 0, 1
    for k in range(33):
      u, v, x = u*i, (2*u+v)*j, x*j
      i += 1; j += 2
    q, r, t = q*u, q*v+r*x, t*x

def g2_md():
  # Lambert, multi-digit
  q, r, s, t = mpz(0), mpz(4), mpz(1), mpz(0)
  i, j, k = 1, 1, 1
  z = mpz(10)**49
  while True:
    n = (q+r)/(s+t)
    if n == q/s:
      for d in digits(n, i>65 and 49 or 1): yield d
      q, r = z*(q-n*s), z*(r-n*t)
    u, v, w, x = 1, 0, 0, 1
    for l in range(64):
      u, v, w, x = u*j+v, u*k, w*j+x, w*k
      i += 1; j += 2; k += j
    q, r, s, t = q*u+r*w, q*v+r*x, s*u+t*w, s*v+t*x

def g3_ref():
  # Gosper, reference
  q, r, t = mpz(1), mpz(180), mpz(60)
  i = 2
  while True:
    u, y = i*(i*27+27)+6, (q+r)/t
    yield y
    q, r, t, i = 10*q*i*(2*i-1), 10*u*(q*(5*i-2)+r-y*t), t*u, i+1

def g3_md():
  # Gosper, multi-digit
  q, r, t = mpz(1), mpz(0), mpz(1)
  i, j = 1, 60
  z = mpz(10)**50
  while True:
    n = (q+r)/t
    if n*t > 6*i*q+r-t:
      for d in digits(n, i>38 and 50 or 1): yield d
      q, r = z*q, z*(r-n*t)
    u, v, x = 1, 0, 1
    for k in range(37):
      u, v, x = u*i*(2*i-1), j*(u*(5*i-2)+v), x*j
      i += 1; j += 54*i
    q, r, t = q*u, q*v+r*x, t*x

def g4_md():
  # Ramanujan 39, multi-digit
  q, r, s ,t = mpz(0), mpz(3528), mpz(1), mpz(0)
  i = 1
  z = mpz(10)**3511
  while True:
    n = (q+r)/(s+t)
    if n == (22583*i*q+r)/(22583*i*s+t):
      for d in digits(n, i>597 and 3511 or 1): yield d
      q, r = z*(q-n*s), z*(r-n*t)
    u, v, x = mpz(1), mpz(0), mpz(1)
    for k in range(596):
      c, d, f = i*(i*(i*32-48)+22)-3, 21460*i-20337, -i*i*i*24893568
      u, v, x = u*c, (u*d+v)*f, x*f
      i += 1
    q, r, s, t = q*u, q*v+r*x, s*u, s*v+t*x

def digits(x, n):
  o = []
  for k in range(n):
    x, r = divmod(x, 10)
    o.append(r)
  return reversed(o)

ノート

上記は6つの実装です。作成者が提供する2つのリファレンス実装(_ref)と、一括で用語を計算し、一度に複数の数字を生成する4 つのリファレンス実装(_md)です。すべての実装は100,000桁で確認されています。バッチサイズを選択するとき、時間の経過とともに徐々に精度が失われる値を選択しました。たとえばg1_md、33回の反復で、バッチごとに10桁を生成します。ただし、これは〜9.93の正しい数字のみを生成します。精度がなくなると、チェック条件が失敗し、追加のバッチが実行されます。これは、時間の経過とともに徐々に余分に必要とされる不必要な精度よりもパフォーマンスが高いようです。

  • g1(ライプニッツ/オイラー)を表す
    追加の変数jが保持され2*i+1ます。著者はリファレンス実装でも同じことを行います。n個別の計算は、次ではなくqrおよびの現在の値を使用するため、はるかに簡単です(わかりにくくなります)t
  • g2(Lambert)
    チェックn == q/sは明らかにかなり緩いです。これは読むべきn == (q*(k+2*j+4)+r)/(s*(k+2*j+4)+t)ところ、jある2*i-1kされますi*i。反復回数が増えるrと、t用語と用語の重要性はますます低くなります。そのままで、最初の100,000桁に適しているので、おそらくすべてに適しています。著者はリファレンス実装を提供していません。
  • g3(Gosper)
    著者はn、後続の反復で変化しないことを確認する必要はなく、アルゴリズムを遅くするだけであると推測します。おそらく本当ですが、ジェネレーターは現在生成されているよりも約13%多くの正しい数字を保持しています。チェックインを追加し直し、50桁が正しくなるまで待ち、それらを一度に生成し、パフォーマンスを著しく向上させました。
  • G4(ラマヌジャン39)
    として計算

    残念なことには、s原因初期(3528÷)組成物に、ゼロにしませんが、それはG3よりかなり速く、まだです。収束は用語ごとに〜5.89桁で、3511桁が一度に生成されます。それが少し多ければ、46回の反復ごとに271桁を生成することもまともな選択です。

タイミング

比較のみを目的として、私のシステムで撮影しました。時間は秒単位でリストされます。タイミングに10分以上かかった場合、それ以上のテストは実行しませんでした。

            |  g1_ref |  g1_md  |  g2_md  |  g3_ref |  g3_md  |  g4_md 
------------+---------+---------+---------+---------+---------+--------
    10,000  |  1.645  |  0.229  |  0.093  |  0.312  |  0.062  |  0.062 
    20,000  |  6.859  |  0.937  |  0.234  |  1.140  |  0.250  |  0.109 
    50,000  |  55.62  |  5.546  |  1.437  |  9.703  |  1.468  |  0.234 
   100,000  |  247.9  |  24.42  |  5.812  |  39.32  |  5.765  |  0.593 
   200,000  |  2,158  |  158.7  |  25.73  |  174.5  |  33.62  |  2.156 
   500,000  |    -    |  1,270  |  215.5  |  3,173  |  874.8  |  13.51 
 1,000,000  |    -    |    -    |  1,019  |    -    |    -    |  58.02 

収束速度が遅いにもかかわらず、g2最終的に追い越すのは興味深いことg3です。これは、オペランドが大幅に遅い速度で成長し、長期的には勝つためだと思われます。最速の実装g4_mdg3_ref、500,000桁の実装よりも約235倍高速です。そうは言っても、このように数字をストリーミングすることには依然として大きなオーバーヘッドがあります。Ramanujan 39(python source)を使用してすべての数字を直接計算すると、約10倍高速になります。

なぜチュドノフスキーではないのですか?

Chudnovskyアルゴリズムは完全な精度の平方根を必要としますが、それがどのように機能するのかについては正直にわかりません。ラマヌジャン39は、この点で多少特殊です。ただし、この方法は、y-cruncherで使用されるようなMachinのような式に役立つように思われるため、探索する価値のある方法かもしれません。


TIL IdeoneはPypyをサポートしています。それでは、2番目のプログラムは速度のために構築されていますか?
mbomb007

@ mbomb007 「では、2番目のプログラムは速度を重視して構築されていますか?」そうです。挑戦は最速のコードと同じくらい興味深いものだったと思います
primo

同じ。私は両方を検討しました。別のタグの下での再投稿についての人々の感じ方をIdk。OEIS(このシーケンスを含まない)に追加する場合は、より便利かもしれません
mbomb007

3

Haskell、231バイト

import Data.List
g(q,r,t,k,n,l)|4*q+r-t<n*t=n:g(10*q,10*(r-n*t),t,k,div(10*(3*q+r))t-10*n,l)|0<1=g(q*k,(2*q+r)*l,t*l,k+1,div(q*(7*k+2)+r*l)(t*l),l+2)
p=nubBy(\x y->length x==length y).concatMap inits.group$g(1,0,1,1,3,3) 

これは、2004年のJeremy GibbonsによるPiの桁にUnbounded Spigot Algorithmsを使用していpます。結果はです。技術的には、無限の出力シーケンスをサポートする必要がありますが、それには時間がかかる可能性があります(メモリによって制限されます)。


3

Python 2、298バイト

piを生成するためのコードは、OPの実装から取得されることに注意してください。

def p():
 q,r,t,j=1,180,60,2
 while 1:
  u,y=3*(3*j+1)*(3*j+2),(q*(27*j-12)+5*r)//(5*t)
  yield y
  q,r,t,j=10*q*j*(2*j-1),10*u*(q*(5*j-2)+r-y*t),t*u,j+1
p=p()
c=r=0
d=[0]
while 1:
 t=p.next()
 if t==d[len(d)-1]:d.append(t)
 else:d=[t]
 if len(d)>r:r=len(d);print"".join([`int(x)`for x in d])
 c+=1

Pythonでのゴルフの最初の試み。シーケンスを永久に出力します。


πここで計算する方法を説明していただけますか?もちろん、パイを計算しますよね?
R.ガプス

今はテストできませんが、πそこで永遠に計算していませんか?
Yytsi

@TuukkaXが表示されないので、yield停止するがありますが、私はPythonがあまり得意ではありません
-Downgoat

Downgoatは正しいです- ジェネレーター関数を使用します
メゴ

1
私はすべてのコードを書きました。pパート以外の実装は見ませんでした
acrolith

3

Python 3.5、278 263バイト:

import decimal,re;decimal.getcontext().prec=int(input());D=decimal.Decimal;a=p=1;b,t=1/D(2).sqrt(),1/D(4)
for i in[1]*50:z=(a+b)/2;b=(a*b).sqrt();t-=p*(a-z)**2;a=z;p*=2;pi=(z*2)**2/(4*t);i=0;C=lambda r:re.search(r'(\d)\1{%s}'%r,str(pi))
while C(i):print(C(i));i+=1

これは、nの最初のn桁の入力として取り込まれ、πそれらの最初のn桁のシーケンスのメンバーを出力します。現在、これはPythonの組み込み10進モジュールを使用して、Pythonの浮動小数点の制限を超えてから、ユーザー入力に応じて精度またはイプシロンを設定します。次に、計算するためにπ、これは効率的なGausse-Legendreアルゴリズムを使用して50回の反復を実行します。アルゴリズムは毎回正しい桁数を明らかに2倍にするため、50回の反復で最大の数字を取得2^50または1,125,899,906,842,624修正できます。最後に、計算が行われた後、whileループ内で文字列の書式設定を含む正規表現を使用して検索および印刷しますre ループ内の前回の反復よりも1桁長いすべての連続した繰り返し数字のオブジェクト(私は大丈夫です)に一致します。

このアルゴリズムを使用して、π最大10,000,000(千万)桁の数字を正常かつ正確に計算することができました。これには、完了までに約4時間12分かかりました。以下は最終出力です。

<_sre.SRE_Match object; span=(0, 1), match='3'>
<_sre.SRE_Match object; span=(25, 27), match='33'>
<_sre.SRE_Match object; span=(154, 157), match='111'>
<_sre.SRE_Match object; span=(763, 767), match='9999'>
<_sre.SRE_Match object; span=(763, 768), match='99999'>
<_sre.SRE_Match object; span=(763, 769), match='999999'>
<_sre.SRE_Match object; span=(710101, 710108), match='3333333'> 

したがって、シーケンスの8番目の数字は最初の1,000万桁以内でも発生しないと自信を持って言えます。π1つの乱数です...

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