在 C++ 中计算 log-sum-exp 函数
Calculating log-sum-exp function in c++
c++标准库中有计算指数和对数的函数吗?如果没有,我应该如何着手编写自己的?您有什么this wiki article中没有提到的建议吗?
我特别担心被加数 下溢 的可能性。在这种情况下,您要对绝对值较大的负数取幂。我正在使用 c++11.
如果您想要更小的代码,此实现可以胜任:
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's blog (Japanese) (or, see it in English, via Google Translate) 上看到更强大的实现。
(shuvro 代码的 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}
。这显然没有下溢。
c++标准库中有计算指数和对数的函数吗?如果没有,我应该如何着手编写自己的?您有什么this wiki article中没有提到的建议吗?
我特别担心被加数 下溢 的可能性。在这种情况下,您要对绝对值较大的负数取幂。我正在使用 c++11.
如果您想要更小的代码,此实现可以胜任:
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's blog (Japanese) (or, see it in English, via Google Translate) 上看到更强大的实现。
(shuvro 代码的 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}
。这显然没有下溢。