4

サイズがほぼ 1000 の 2 つの整数ベクトルがあり、これから行うことは、これら 2 つのベクトルの平方整数の合計が同じかどうかを確認することです。したがって、次のコードを記述します。

std::vector<int> array1;
std::vector<int> array2;
... // initialize array1 and array2, and in the experiment all elements
    // in the two vectors are the same but the sequence of elements may be different.
    // For example: array1={1001, 2002, 3003, ....} 
   //               array2={2002, 3003, 1001, ....}
assert(array1.size() == array2.size());
float sum_array1 = 0;
float sum_array2 = 0;
for(int i=0; i<array1.size(); i++)
       sum_array1 +=array1[i]*array1[i];
for(int i=0; i<array2.size(); i++)
       sum_array2 +=array2[i]*array2[i];

sum_array1私はそれが と等しいはずだと思っていsum_array2ますが、実際、私のアプリケーションでは、それらが異なることがわかりましsum_array1 = 1.2868639e+009sum_array2 = 1.2868655e+009。次に行ったことは、次のコードが示すように、の型を double 型に変更することですsum_array1sum_array2

 double sum_array1 = 0;
    double sum_array2 = 0;
    for(int i=0; i<array1.size(); i++)
           sum_array1 +=array1[i]*array1[i];
    for(int i=0; i<array2.size(); i++)
           sum_array2 +=array2[i]*array2[i];

この時間 sum_array1は に等しいsum_array2 sum_array1=sum_array2=1286862225.0000000です。私の質問は、なぜそれが起こり得るかです。ありがとう。

4

4 に答える 4

5

浮動小数点値のサイズは有限であるため、有限の精度を持つ実数値のみを表すことができます。これにより、格納できる精度よりも高い精度が必要な場合に丸め誤差が発生します。

特に、小さい数値 (合計する数値など) をはるかに大きい数値 (アキュムレータなど) に加算する場合、小さい数値に比べて精度の損失が非常に大きくなり、重大なエラーが発生する可能性があります。エラーは順序によって異なります。

通常、float精度は 24 ビットで、小数点以下約 7 桁に相当します。アキュムレータには小数点以下 10 桁 (約 30 ビット) が必要なため、この精度の低下が発生します。通常doubleは 53 ビット (小数点以下約 16 桁) であるため、結果を正確に表すことができます。

すべての入力が整数であるため、ここでは 64 ビット整数が最適なオプションです。整数を使用すると、精度の低下を回避できますが、入力が多すぎたり大きすぎたりすると、オーバーフローの危険性が生じます。

十分な幅のアキュムレータを使用できない場合にエラーを最小限に抑えるには、最小値が最初に累積されるように入力を並べ替えることができます。または、 Kahan summationなどのより複雑な方法を使用できます。

于 2013-09-06T16:00:54.630 に答える
4

2 つのループでは、同じ番号を異なる順序で追加しています。合計が a で正確に表現できる整数値を超えるとすぐに、float精度が低下し始め、合計がわずかに異なる場合があります。

あなたが試す実験:

float n = 0;
while (n != n + 1)
    n = n + 1;
//Will this terminate? If so, what is n now?

これを実行すると、ループが実際に終了することがわかります。これは完全に直感に反するように見えますが、IEEE単精度浮動小数点演算の定義によると正しい動作です。

に置き換えfloatて、同じ実験を試すことができdoubleます。同じ奇妙な動作が見られますが、IEEEの倍精度浮動小数点数を使用すると精度が大幅に向上するため、今回nは がはるかに大きくなるとループが終了します。

于 2013-09-06T15:56:14.370 に答える
2

Adoubleはより多くのビットを持っているため、より多くの情報を保持しますfloat。float に値を追加すると、sum_array1 と sum_array2 の異なる時間に情報が丸められます。

入力値によっては、double を float として使用するときに同じ問題が発生する可能性があります (値が十分に大きい場合)。

「浮動小数点数について知っておくべきことすべて」を Web 検索すると、制限の概要と、それらに対処する最善の方法が得られます。

于 2013-09-06T15:52:28.357 に答える