9

要するにa+b、切り捨てによる精度の低下がゼロに向かうのではなく、ゼロから離れるように実行するにはどうすればよいでしょうか?

長い物語

セットのサンプル平均と分散を計算する目的で、長い一連の浮動小数点値の合計を計算しています。Var(X) = E(X 2 ) - E(X) 2であるため、すべての数値の実行中のカウント、これまでのすべての数値の合計、およびこれまでのすべての数値の 2 乗の合計を維持するだけで十分です。

ここまでは順調ですね。

ただし、 E(X 2 ) > E(X) 2であることが絶対に必要であり、浮動小数点の精度が原因で常にそうとは限りません。疑似コードでは、問題は次のとおりです。

int count;
double sum, sumOfSquares;
...
double value = <current-value>;
double sqrVal = value*value; 

count++;
sum += value; //slightly rounded down since value is truncated to fit into sum
sumOfSquares += sqrVal; //rounded down MORE since the order-of-magnitude 
//difference between sqrVal and sumOfSquares is twice that between value and sum;

変数シーケンスの場合、これは大きな問題ではありません。分散をわずかに過小評価することになりますが、多くの場合、大きな問題にはなりません。ただし、ゼロ以外の平均値を持つ定数またはほぼ定数のセットの場合、 E(X 2 ) < E(X) 2を意味する可能性があり、その結果、計算された分散が負になり、コードを消費するという期待に反します。

今、私は魅力的なソリューションではないカハン総和について知っています。第一に、コードが最適化の気まぐれの影響を受けやすくなります (最適化フラグに応じて、コードはこの問題を示す場合と示さない場合があります)。第二に、問題は実際には精度によるものではありません。これで十分です。ゼロに向かってエラー。行を実行できれば

sumOfSquares += sqrVal;

sqrVal が sumOfSquares の精度に丸められるのではなく、切り上げられるようにするには、数値的に妥当な解決策が必要です。しかし、どうすればそれを達成できますか?

編集:完成した質問 - タグフィールドのドロップダウンリストでEnterキーを押すと、とにかく質問が送信されるのはなぜですか?

4

3 に答える 3

6

計算を少し再配置する別のシングルパスアルゴリズムがあります。擬似コード:

n = 0
mean = 0
M2 = 0

for x in data:
    n = n + 1
    delta = x - mean
    mean = mean + delta/n
    M2 = M2 + delta*(x - mean)  # This expression uses the new value of mean

variance_n = M2/n         # Sample variance
variance = M2/(n - 1)     # Unbiased estimate of population variance

(出典: http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance )

これは、通常のアルゴリズムで指摘した問題に関しては、より適切に動作するようです。

于 2009-08-10T08:38:23.617 に答える
6

IEEE は 4 つの丸めモード (-inf 方向、+inf 方向、0 方向、tonearest) を提供します。+inf に向かっては、あなたが望むようです。C90 または C++ には標準コントロールはありません。C99 では<fenv.h>、一部の C90 および C++ 実装の拡張機能としても存在するヘッダーが追加されました。C99 標準を尊重するには、次のように記述する必要があります。

#include <fenv.h>
#pragma STDC FENV_ACCESS ON

int old_round_mode = fegetround();
int set_round_ok = fesetround(FE_UPWARD);
assert(set_round_ok == 0);
...
int set_round_ok = fesetround(old_round_mode);
assert(set_round_ok == 0);

使用しているアルゴリズムが数値的に不安定で、精度の問題があることはよく知られています。データに対して 2 つのパスを実行する方が、精度が向上します。

于 2009-08-10T08:33:45.387 に答える
2

精度については気にせず、負の分散についてだけ気にする場合は、単純に実行してみませんか。V(x) = Max(0, E(X^2) - E(X)^2)

于 2009-08-10T09:18:10.040 に答える