4

Gauss-Legendreアルゴリズムを使用して円周率を計算するPythonスクリプトを使用すると、このエラーが発生します。これを取得する前に使用できるのは、最大1024回の反復のみです。

    C:\Users\myUsernameHere>python Desktop/piWriter.py
    End iteration: 1025
    Traceback (most recent call last):
      File "Desktop/piWriter.py", line 15, in <module>
        vars()['t' + str(sub)] = vars()['t' + str(i)] - vars()['p' + str(i)] * math.
    pow((vars()['a' + str(i)] - vars()['a' + str(sub)]), 2)
    OverflowError: long int too large to convert to float

これが私のコードです:

import math

a0 = 1
b0 = 1/math.sqrt(2)
t0 = .25
p0 = 1

finalIter = input('End iteration: ')
finalIter = int(finalIter)

for i in range(0, finalIter):
        sub = i + 1
        vars()['a' + str(sub)] = (vars()['a' + str(i)] + vars()['b' + str(i)])/ 2
        vars()['b' + str(sub)] = math.sqrt((vars()['a' + str(i)] * vars()['b' + str(i)]))
        vars()['t' + str(sub)] = vars()['t' + str(i)] - vars()['p' + str(i)] * math.pow((vars()['a' + str(i)] - vars()['a' + str(sub)]), 2)
        vars()['p' + str(sub)] = 2 * vars()['p' + str(i)]
        n = i

pi = math.pow((vars()['a' + str(n)] + vars()['b' + str(n)]), 2) / (4 * vars()['t' + str(n)])
print(pi)

理想的には、反復値として非常に多くの数値をプラグインし、しばらくしてから戻って結果を確認できるようにしたいと思います。

助けていただければ幸いです。ありがとう!

4

4 に答える 4

4

フロートは、sys.float_info.maxまたは1.7976931348623157e+308までの数値のみを表すことができます。308桁(またはそれ以上)を超えるintを取得すると、スタックします。p1024が309桁の場合、反復は失敗します。

179769313486231590772930519078902473361797697894230657273430081157732675805500963132708477322407536021120113879871393357658789768814416622492847430639474124377767893424865485276302219601246094119453082952085005768838150682342462881473913110540827237163350510684586298239947245938479716304835356329624224137216L

円周率には、このような大きな値を必要としない別のアルゴリズムを見つける必要があります。

実際には、フロートは近似値にすぎないため、フロート全体に注意する必要があります。piの連続近似を出力するようにプログラムを変更すると、次のようになります。

2.914213562373094923430016933707520365715026855468750000000000
3.140579250522168575088244324433617293834686279296875000000000
3.141592646213542838751209274050779640674591064453125000000000
3.141592653589794004176383168669417500495910644531250000000000
3.141592653589794004176383168669417500495910644531250000000000
3.141592653589794004176383168669417500495910644531250000000000
3.141592653589794004176383168669417500495910644531250000000000

言い換えると、たった4回の反復の後、近似は改善されなくなりました。これは、おそらく。で始まる、使用しているフロートの不正確さが原因です1/math.sqrt(2)。円周率の多くの桁を計算するには、数値表現を非常に注意深く理解する必要があります。

于 2012-12-20T19:06:24.467 に答える
1

前の回答で述べたように、floatタイプには数値サイズの上限があります。一般的な実装では、sys.float_info.maxは1.7976931348623157e + 308です。これは、64ビット浮動小数点数の指数フィールドに10ビットのプラス記号を使用したことを反映しています。(1024 * math.log(2)/math.log(10)は約308.2547155599であることに注意してください。)

10進数タイプを使用すると、指数サイズにさらに5ダースを追加できます。次に例を示します(ipythonインタープリターセッションから抜粋):

In [48]: import decimal, math    
In [49]: g=decimal.Decimal('1e12345')    
In [50]: g.sqrt()
Out[50]: Decimal('3.162277660168379331998893544E+6172')
In [51]: math.sqrt(g)
Out[51]: inf

これは、decimalのsqrt()関数が。よりも大きい数値で正しく機能することを示していmath.sqrt()ます。

于 2012-12-20T19:26:07.493 に答える
0

上で述べたように、たくさんの数字を取得するのは難しいでしょうが、それらすべてを見るとvars私の目を傷つけます。varsしたがって、(1)の使用を辞書に置き換え、(2)**数学関数の代わりに使用した後のコードのバージョンは次のとおりです。

a, b, t, p = {}, {}, {}, {}
a[0] = 1
b[0] = 2**-0.5
t[0] = 0.25
p[0] = 1

finalIter = 4

for i in range(finalIter):
    sub = i + 1
    a[sub] = (a[i] + b[i]) / 2
    b[sub] = (a[i] * b[i])**0.5
    t[sub] = t[i] - p[i] * (a[i] - a[sub])**2
    p[sub] = 2 * p[i]
    n = i

pi_approx = (a[n] + b[n])**2 / (4 * t[n])

でゲームをプレイする代わりに、辞書varsを使用して値(公式のPythonチュートリアルへのリンク)を保存しました。これにより、コードがはるかに読みやすくなります。あなたはおそらく今でも最適化を1つか2つ見ることができます。

コメントに記載されているように、実際にはすべての値を保存する必要はなく、最後の値だけを保存する必要がありますが、変数を動的に作成せずに物事を行う方法を理解することがより重要だと思います。の代わりに、dict単に値をに追加することもできますがlist、リストは常にゼロインデックスであり、簡単に「スキップ」して任意のインデックスに値を設定することはできません。アルゴリズムを操作するときに混乱することがあるので、簡単に始めましょう。

とにかく、上記は私に与えます

>>> print(pi_approx)
3.141592653589794
>>> print(pi_approx-math.pi)
8.881784197001252e-16
于 2012-12-20T21:25:21.250 に答える
0

mpmath簡単な解決策は、Python 3をサポートする任意精度モジュールをインストールして使用することです。ただし、vars()変数をオンザフライで作成するために使用することは、アルゴリズムを実装するための望ましくない方法であるというDSMに完全に同意するため、あなたのコードの彼の書き直しについての私の答えmpmathは、計算を行うために利用するためにそれを[自明に]修正しました。

を使用することを主張する場合vars()は、おそらく同様のことを行うことができます。ただし、それはより困難であり、結果を読み、理解し、変更するのは間違いなく難しいと思います。

from mpmath import mpf  # arbitrary-precision float type

a, b, t, p = {}, {}, {}, {}
a[0] = mpf(1)
b[0] = mpf(2**-0.5)
t[0] = mpf(0.25)
p[0] = mpf(1)

finalIter = 10000

for i in range(finalIter):
    sub = i + 1
    a[sub] = (a[i] + b[i]) / 2
    b[sub] = (a[i] * b[i])**0.5
    t[sub] = t[i] - p[i] * (a[i] - a[sub])**2
    p[sub] = 2 * p[i]
    n = i

pi_approx = (a[n] + b[n])**2 / (4 * t[n])
print(pi_approx)  # 3.14159265358979
于 2013-09-25T18:11:19.310 に答える