Мне нужно вычислить среднее геометрическое для большого набора чисел, значения которых не ограничены априори. Наивный способ был бы
double geometric_mean(std::vector<double> const&data) // failure
{
auto product = 1.0;
for(auto x:data) product *= x;
return std::pow(product,1.0/data.size());
}
Однако это может сильно потерпеть неудачу из-за переполнения или переполнения накопленного product
(примечание: long double
на самом деле не позволяет эту проблему). Итак, следующий вариант заключается в подведении итогов логарифмов:
double geometric_mean(std::vector<double> const&data)
{
auto sumlog = 0.0;
for(auto x:data) sum_log += std::log(x);
return std::exp(sum_log/data.size());
}
Это работает, но вызывает std::log()
для каждого элемента, который потенциально медленный. Можно ли избежать этого? Например, отслеживая (эквивалент) экспонента и мантиссу накопленного product
отдельно?