入力として複数の浮動小数点値(単一または二重)を受け取り、何らかの計算を行い、出力浮動小数点値(単一または二重)を生成する関数があるとします。私は主にMSVC 2008で作業していますが、MinGW / GCCでも作業する予定です。私はC ++でプログラミングしています。
結果に含まれるエラーの量をプログラムで測定する一般的な方法は何ですか?私は任意精度ライブラリを使用する必要があると仮定します:速度を気にしない場合、そのような最適なライブラリは何ですか?
入力として複数の浮動小数点値(単一または二重)を受け取り、何らかの計算を行い、出力浮動小数点値(単一または二重)を生成する関数があるとします。私は主にMSVC 2008で作業していますが、MinGW / GCCでも作業する予定です。私はC ++でプログラミングしています。
結果に含まれるエラーの量をプログラムで測定する一般的な方法は何ですか?私は任意精度ライブラリを使用する必要があると仮定します:速度を気にしない場合、そのような最適なライブラリは何ですか?
回答:
丸め誤差の適切な範囲を探している場合、必ずしもaribtrary-precisionライブラリは必要ありません。代わりに、実行中のエラー分析を使用できます。
優れたオンラインリファレンスを見つけることができませんでしたが、Nick Highamの本「数値アルゴリズムの精度と安定性」のセクション3.3ですべて説明されています。アイデアは非常に簡単です。
x
、定数が割り当てられたx_err
ときにゼロに初期化される変数を作成しますx
。z = x * y
、z_err
浮動小数点演算の標準モデルと結果のz
エラーx_err
および実行中のエラーを使用して変数を更新しますy_err
。_err
値も添付されている必要があります。これは、総丸め誤差のデータ依存の限界です。難しい部分はステップ3です。最も単純な算術演算では、次の規則を使用できます。
z = x + y
-> z_err = u*abs(z) + x_err + y_err
z = x - y
-> z_err = u*abs(z) + x_err + y_err
z = x * y
-> z_err = u*abs(z) + x_err*abs(y) + y_err*abs(x)
z = x / y
-> z_err = u*abs(z) + (x_err*abs(y) + y_err*abs(x))/y^2
z = sqrt(x)
-> z_err = u*abs(z) + x_err/(2*abs(z))
u = eps/2
単位の丸めはどこですか。はい、のルール+
とルール-
は同じです。にop(x)
適用される結果のテイラー級数展開を使用して、他の操作のルールを簡単に抽出できますop(x + x_err)
。または、グーグルで試すことができます。または、Nick Highamの本を使用します。
例として、ホーナースキームを使用a
してポイントで係数の多項式を評価する次のMatlab / Octaveコードを考えますx
。
function s = horner ( a , x )
s = a(end);
for k=length(a)-1:-1:1
s = a(k) + x*s;
end
最初のステップでは、次の2つの操作を分割しs = a(k) + x*s
ます。
function s = horner ( a , x )
s = a(end);
for k=length(a)-1:-1:1
z = x*s;
s = a(k) + z;
end
次に、_err
変数を紹介します。入力a
とx
は正確であると想定されていることに注意してください。しかし、a_err
とに対応する値を渡すようにユーザーに要求することもできますx_err
。
function [ s , s_err ] = horner ( a , x )
s = a(end);
s_err = 0;
for k=length(a)-1:-1:1
z = x*s;
z_err = ...;
s = a(k) + z;
s_err = ...;
end
最後に、上記のルールを適用してエラー条件を取得します。
function [ s , s_err ] = horner ( a , x )
u = eps/2;
s = a(end);
s_err = 0;
for k=length(a)-1:-1:1
z = x*s;
z_err = u*abs(z) + s_err*abs(x);
s = a(k) + z;
s_err = u*abs(s) + z_err;
end
a_err
or がないためx_err
、たとえばゼロであると想定されるため、それぞれの項はエラー式で単純に無視されます。
ほら!結果に加えて、データ依存のエラー推定値(注:これはエラーの上限)を返すHornerスキームがあります。
補足として、C ++を使用しているため、浮動小数点値用の独自のクラスを作成して_err
用語を実行し、すべての算術演算をオーバーロードしてこれらの値を上記のように更新することを検討できます。大きなコードの場合、これは計算上効率的ではありませんが、より簡単なルートです。そうは言っても、そのようなクラスをオンラインで見つけることができるかもしれません。簡単なGoogle検索でこのリンクが表示されました。
任意精度の浮動小数点演算(およびその他の多く)に対応する、移植性の高いオープンソースライブラリは、Victor ShoupのNTLであり、C ++ソース形式で入手できます。
下位レベルには、GNU Multiple Precision(GMP)Bignum Libraryがあり、これもオープンソースパッケージです。
NTLはGMPで使用できますが、高速なパフォーマンスが必要ですが、NTLには独自の基本ルーチンがあり、「速度を気にしない」場合に確実に使用できます。GMPは「最速のbignumライブラリ」であると主張しています。GMPは主にCで書かれていますが、C ++インターフェイスを備えています。
追加:区間演算は自動化された方法で正確な答えに上限と下限を与えることができますが、これは「標準」精度計算でエラーを正確に測定しません。絶対エラーセンス)。
丸め誤差または離散化エラーなどのエラーサイズを見つける一般的な方法は、追加の精度値を計算し、それを「標準」精度値と比較することです。誤差の大きさ自体を妥当な精度で決定するには、控えめな精度のみが必要です。これは、丸め誤差だけが、余分な精度の計算よりも「標準」精度が大幅に大きいためです。
ポイントは、単精度計算と倍精度計算を比較することで説明できます。C ++では、中間式は常に(少なくとも)倍精度で計算されるため、「純粋な」単精度での計算がどのようなものかを説明する場合は、中間値を単精度で保存する必要があります。
Cコードスニペット
float fa,fb;
double da,db,err;
fa = 4.0;
fb = 3.0;
fa = fa/fb;
fa -= 1.0;
da = 4.0;
db = 3.0;
da = da/db;
da -= 1.0;
err = fa - da;
printf("Single precision error wrt double precision value\n");
printf("Error in getting 1/3rd is %e\n",err);
return 0;
上記の出力(Cygwin / MinGW32 GCCツールチェーン):
Single precision error wrt double precision value
Error in getting 1/3rd is 3.973643e-08
したがって、エラーは、1/3を単精度に丸める際に予想されるものです。エラーの測定は正確さではなく大きさのためであるため、エラー修正で小数点以下数桁以上を取得することは気にしません(私は疑います)。
GMP(GNU Multiple Precision Library)は、私が知っている最高の任意精度ライブラリです。
任意の浮動小数点関数の結果のエラーを測定するプログラム的な方法は知りません。試行できることの1つは、区間演算を使用して関数の区間拡張を計算することです。C ++では、インターバル拡張を計算するために何らかのライブラリを使用する必要があります。そのようなライブラリの1つが、ブースト間隔演算ライブラリです。。基本的に、エラーを測定するには、関数の間隔に引数として2倍の単位の丸めの幅(大まかに)を指定し、目的の値を中心にすると、出力は間隔のコレクションになります。エラーの控えめな見積もりが得られます。この方法の難点は、この方法で使用される区間演算がかなりの量の誤差を過大評価する可能性があることですが、この方法は私が考えることができる最も「プログラム的な」方法です。
間隔分析により、厳密で自動のエラー推定を実現できます。数値ではなく間隔を使用します。追加の例:
[a,b] + [c,d] = [min(a+c, a+d, b+c, b+d), max (a+c, a+d, b+c, b+d)] = [a+c, b+d]
四捨五入も厳密に処理できます。「四捨五入間隔演算」を参照してください。
入力が狭い間隔で構成されている限り、推定値は問題なく、計算コストは安くなります。残念ながら、エラーはしばしば過大評価されます。依存関係の問題を参照してください。
任意の精度の区間演算ライブラリーは知りません。
間隔計算がニーズを満たすかどうかは、手元の問題に依存します。
GNU MPFRライブラリは、その主なフォーカスポイントの一つとして、(同じくらい簡単に聞こえるようではないすべての操作のために、特に、正しい丸め)高い精度を有する任意精度浮動小数点ライブラリです。内部でGNU MPを使用します。間隔演算を行うMPFIと呼ばれる拡張機能があり、Geoffの答えが示唆するように、検証の目的で役立ちます。結果の間隔が小さい範囲内になるまで作業精度を上げ続けます。
ただし、これは常に機能するとは限りません。特に、すべてのステップが丸め問題とは無関係に「エラー」を伴う数値積分のようなものを実行している場合、必ずしも効果的ではありません。その場合、COZY infinityなどの特殊なパッケージを試してみてください。これは、特定のアルゴリズムを使用して積分誤差を制限する(および間隔ではなくいわゆるTaylorモデルを使用する)ことで非常にうまく機能します。
Visual Studioを使用している場合、MPIRは優れたライブラリであると言われています。