Существуют ли какие-либо функции в стандартной библиотеке c ++, которые вычисляют лог суммы экспонент? Если нет, то как мне написать свой собственный? Есть ли у вас какие-либо предложения, не упомянутые в эта статья вики?
Меня особенно беспокоит возможность того, что слагаемые опустошения. Это ситуация, когда вы возводите в степень отрицательные числа, которые имеют большое абсолютное значение. Я использую C ++ 11.
(C ++ 11 вариант кода Шувро с использованием стандартной библиотеки в соответствии с вопросом.)
template <typename Iter>
std::iterator_traits<Iter>::value_type
log_sum_exp(Iter begin, Iter end)
{
using VT = std::iterator_traits<Iter>::value_type{};
if (begin==end) return VT{};
using std::exp;
using std::log;
auto max_elem = *std::max_element(begin, end);
auto sum = std::accumulate(begin, end, VT{},
[max_elem](VT a, VT b) { return a + exp(b - max_elem); });
return max_elem + log(sum);
}
Эта версия является более общей — она будет работать с любым типом значения, в любом типе контейнера, если она имеет соответствующие операторы. В частности, он будет использовать std::exp
а также std::log
если тип значения не имеет своих собственных перегрузок.
Чтобы быть действительно устойчивым к недопущению, даже для неизвестных числовых типов, вероятно, было бы полезно отсортировать значения. Если вы сортируете входные данные, самое первое значение будет max_elem
Итак, первый срок sum
будет exp(VT{0}
который предположительно VT{1}
, Это явно без недостатка.
Если вы хотите меньший код, эта реализация может сделать работу:
double log_sum_exp(double arr[], int count)
{
if(count > 0 ){
double maxVal = arr[0];
double sum = 0;
for (int i = 1 ; i < count ; i++){
if (arr[i] > maxVal){
maxVal = arr[i];
}
}
for (int i = 0; i < count ; i++){
sum += exp(arr[i] - maxVal);
}
return log(sum) + maxVal;
}
else
{
return 0.0;
}
}
Вы можете увидеть более надежную реализацию на Блог Takeda 25 (японский) (или посмотри на английском, через Google Translate).