3

フロートでかなりの精度を失っているようです。

たとえば、行列を解く必要があります。

4.0x -2.0y 1.0z =11.0
1.0x +5.0y -3.0z =-6.0
2.0x +2.0y +5.0z =7.0

これは、テキストファイルからマトリックスをインポートするために使用するコードです。

f = open('gauss.dat')
lines =  f.readlines()
f.close()

j=0
for line in lines:
    bits = string.split(line, ',')
    s=[]
    for i in range(len(bits)):
        if (i!= len(bits)-1):
            s.append(float(bits[i]))
            #print s[i]
    b.append(s)
    y.append(float(bits[len(bits)-1]))

ガウス・ザイデルを使用して解く必要があるため、x、y、zの方程式を再配置する必要があります。

x=(11+2y-1z)/4
y=(-6-x+3z)/5
z=(7-2x-2y)/7

これが私が方程式を再配置するために使用するコードです。bは係数の行列であり、yは答えベクトルです。

def equations(b,y):
    i=0
    eqn=[]
    row=[]
    while(i<len(b)):
        j=0
        row=[]
        while(j<len(b)):
            if(i==j):
                row.append(y[i]/b[i][i])
            else:
                row.append(-b[i][j]/b[i][i])
            j=j+1
        eqn.append(row)
        i=i+1
    return eqn

しかし、私が返す答えは小数点以下の桁数まで正確ではありません。

たとえば、上から2番目の方程式を並べ替えると、次のようになります。

y=-1.2-.2x+.6z

私が得るものは:

y=-1.2-0.20000000000000001x+0.59999999999999998z

これは大きな問題ではないように思われるかもしれませんが、数値を非常に高い累乗に上げると、エラーは非常に大きくなります。これを回避する方法はありますか?クラスを試しましたDecimalが、パワー(つまり)ではうまく機能しませんDecimal(x)**2

何か案は?

4

6 に答える 6

14

IEEE 浮動小数点は、10 進数ではなく 2 進数です。正確に 0.1 またはその倍数である固定長のバイナリ小数はありません。これは、10 進数の 1/3 のような繰り返しの分数です。

すべてのコンピュータ科学者が浮動小数点演算について知っておくべきことをお読みください

Decimal クラス以外のオプションは次のとおりです。

于 2008-11-13T02:11:58.567 に答える
12

私はあなたを助けるのに十分なDecimalクラスに精通していませんが、あなたの問題は、10進数の分数がバイナリで正確に表現できないことが多いという事実によるものです。したがって、表示されているのは可能な限り最も近い近似値です。特別なクラス(おそらくDecimalなど)を使用せずにこの問題を回避する方法はありません。

EDIT:10進数クラスが正しく機能していないのはどうですか?フロートではなくストリングから始める限り、パワーはうまく機能しているようです。

>>> import decimal
>>> print(decimal.Decimal("1.2") ** 2)
1.44

モジュールのドキュメントでは、その必要性と使用法がdecimal.Decimal非常に明確に説明されています。まだ確認していない場合は、確認する必要があります。

于 2008-11-13T02:09:08.667 に答える
4

まず、入力を大幅に簡素化できます。ファイルを読み取って解析する必要はありません。Python 記法でオブジェクトを宣言するだけです。ファイルを評価します。

b = [
    [4.0, -2.0,  1.0],
    [1.0, +5.0, -3.0],
    [2.0, +2.0, +5.0],
]
y = [ 11.0, -6.0, 7.0 ]

次に、y=-1.2-0.20000000000000001x+0.5999999999999998z は珍しいことではありません。0.2 または 0.6 のバイナリ表記には正確な表現はありません。したがって、表示される値は元の正確な表現ではなく、10 進数の近似値です。これらは、存在するほぼすべての種類の浮動小数点プロセッサに当てはまります。

Python 2.6 の分数モジュールを試すことができます。役立つかもしれない古い合理的なパッケージがあります。

はい、浮動小数点数を累乗するとエラーが増加します。したがって、浮動小数点数の最も右側の位置を使用しないようにする必要があります。これらのビットはほとんどがノイズであるためです。

浮動小数点数を表示するときは、ノイズ ビットが表示されないように適切に丸める必要があります。

>>> a
0.20000000000000001
>>> "%.4f" % (a,)
'0.2000'
于 2008-11-13T02:49:01.113 に答える
4

このようなタスクには decimal モジュールを使用しないように注意してください。その目的は実際には、正確な精度の計算を実行するのではなく、有限の精度で現実世界の 10 進数を処理することです (たとえば、人間の簿記の慣行に一致させる)。2 進数と同じように 10 進数でも正確に表現できない数値があり、10 進数で演算を実行するのも代替手段よりもはるかに遅くなります。

代わりに、正確な結果が必要な場合は、有理数演算を使用する必要があります。これらは数値を分子/分母のペアとして表すため、すべての有理数を正確に表すことができます。無理数になる可能性のある平方根などの演算ではなく、乗算と除算のみを使用している場合は、精度が失われることはありません。

他の人が述べたように、python 2.6 には有理型が組み込まれていますが、これは実際には高性能な実装ではないことに注意してください。速度のためには、gmpyなどのライブラリを使用することをお勧めします。float() の呼び出しを gmpy.mpq() に置き換えるだけで、コードは正確な結果を返すはずです (ただし、表示目的で結果を float としてフォーマットすることもできます)。

以下は、代わりに gmpy 有理数を使用する行列をロードするコードの少し整理されたバージョンです。

def read_matrix(f):
    b,y = [], []
    for line in f:
        bits = line.split(",")
        b.append( map(gmpy.mpq, bits[:-1]) )
        y.append(gmpy.mpq(bits[-1]))
    return b,y
于 2008-11-13T14:30:33.843 に答える
2

それはあなたの質問への回答ではありませんが、関連しています:

#!/usr/bin/env python
from numpy import abs, dot, loadtxt, max
from numpy.linalg import solve

data = loadtxt('gauss.dat', delimiter=',')
a, b = data[:,:-1], data[:,-1:]
x = solve(a, b) # here you may use any method you like instead of `solve`
print(x)
print(max(abs((dot(a, x) - b) / b))) # check solution

例:

$ cat gauss.dat
4.0, 2.0, 1.0, 11.0
1.0, 5.0, 3.0, 6.0 
2.0, 2.0, 5.0, 7.0

$ python loadtxt_example.py
[[ 2.4]
 [ 0.6]
 [ 0.2]]
0.0
于 2008-11-25T12:28:41.757 に答える
0

また、いくつかの回答がある SOの What is a simple example of floating point errorも参照してください。私が与えるものは、実際にサンプル言語としてpythonを使用しています...

于 2008-11-13T02:49:57.320 に答える