численно устойчивое скользящее среднее значений с плавающей запятой - PullRequest
1 голос
/ 28 января 2020

с использованием 32-битных значений с плавающей запятой, каков наилучший (численно наиболее точный) способ вычисления среднего значения, если - при запуске вычисления - я пока не знаю, сколько значений у меня будет (в следующих примерах я просто перебираю вектор, чтобы я мог знать coult, но давайте предположим, что я знаю количество элементов только в конце)?

Я мог бы сделать, например,

float result = 0.f;
for(float num: numbers) {
    result += num;
}
num /= numbers.size();

, но в результате становится больше Так же, как и точность. С небольшими значениями в какой-то момент result += num; больше не будет изменять результат.

Я мог бы сделать

float result = numbers[0]
for(int i=1, i<numbers.size(); i++) {
    float frac = (i/float(i+1));
    result = result * frac + numbers[i] * (1.0f-frac);
}

, но, похоже, я бы применил кумулятивную ошибку, чтобы получить таким образом.

Есть ли лучший способ без перехода на 64-битный дабл?

1 Ответ

3 голосов
/ 28 января 2020

Самый известный метод для такого рода проблем - суммирование Кахана. Смотрите здесь: https://en.wikipedia.org/wiki/Kahan_summation_algorithm. Предполагая, что сумма остается представимой в виде числа с плавающей запятой одинарной точности, в конце сделайте прямое деление, чтобы найти среднее.

Также см. Этот ответ для дополнительного обсуждения, которое требует более или менее того же самого: Как вычислить среднее значение удвоений, чтобы суммарная ошибка была минимальной?

...