【问题标题】:Calculating log-sum-exp function in c++在 C++ 中计算 log-sum-exp 函数
【发布时间】:2017-08-29 16:09:47
【问题描述】:

c++ 标准库中是否有计算指数和的对数的函数?如果没有,我应该如何编写自己的?你有什么this wiki article没有提到的建议吗?

我特别关注加法运算下溢的可能性。这是您对绝对值较大的负数求幂的情况。我正在使用 c++11。

【问题讨论】:

  • 标准库中没有针对特定应用程序的东西,但Boost.Multiprecision 提供了具有非常全面的超越和特殊功能支持的任意精度算术。
  • 如果你想自己写,那你为什么要问库支持?我没有任何实施建议,没有。

标签: c++ c++11 exp underflow


【解决方案1】:

(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::expstd::log,除非值类型有自己的重载。

要对下溢非常健壮,即使对于未知的数字类型,对值进行排序可能也会有好处。如果对输入进行排序,第一个值将是max_elem,因此sum 的第一项将是exp(VT{0},大概是VT{1}。这显然没有下溢。

【讨论】:

    【解决方案2】:

    如果你想要更小的代码,这个实现可以完成这项工作:

    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) 上看到更强大的实现(或者,请参阅 in English, via Google Translate)。

    【讨论】:

    • log(exp(x1)+exp(x2)+...+exp(xn))=log(exp(xmax)exp(x1-xmax)+exp(xmax)exp(x2 -xmax)+...+exp(xmax)exp(xn-xmax))=log(exp(xmax)*(exp(x1-xmax)+exp(x2-xmax)+...+exp(xn- xmax))) = xmax + log(exp(x1-xmax)+exp(x2-xmax)+...+exp(xn-xmax))。 - 如果我没记错的话,没有计数乘以 maxVal。
    猜你喜欢
    • 2014-07-27
    • 2013-02-22
    • 1970-01-01
    • 1970-01-01
    • 2016-02-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多