【问题标题】:c power calculation, compiler optimizationc幂计算,编译器优化
【发布时间】:2013-10-20 13:08:33
【问题描述】:

所以我最近一直在研究订单统计的一些概率分布。在那个领域,很常见的是从实数区间 [0, 1] 中看到许多具有高数幂的公式。

考虑数字 a ~ b ~ 0,都是正数。我想计算类似 a^n / b^m 其中 n, m 是巨大的数字。

我的问题如下: 如果我使用像

这样的 C 代码
double f(double a, double b, long m, long n)
{
    return( pow(a, n) / pow(b, m) );
}

这会稳定吗?规则应该是首先评估 a^n,然后是 b^m,然后除,但是如果 a^n 或 b^m 足够小,它将为零或 NaN。相反,我可以做类似的事情

double g(double a, double b, long m, long n)
{
    double res;
    long i;
    res = 1;
    for (i = 0; i < min(m, n); ++i)
    {
        res = res * a / b;
    }
    if ( n > m )
    {
        res = res * pow(a, n - m);
    } else {
       res = res / pow(b, m - n);
    }
    return( res );
}

您知道 1) 在这种情况下是否需要优化?如果没有,如何处理此类情况以进行快速稳定的评估?

【问题讨论】:

  • 为了避免这种情况,在日志域中计算是否可行?即result = exp(n*log(a) - m*log(b))。 (免责声明:我绝对不是数字专家。)
  • 您需要第二种形式。但不要使用for 循环。使用pow(a/b, min(m, n)) 减少操作次数。 (假设mn 必须是非负数。)
  • 好的,谢谢!我想使用 sum() 和 log(a)-log(b) 结合这两种方法没有问题:)
  • 在您的a ~ b ~ 0 中,~ 应该表示近似相等吗?

标签: c optimization numerical stability


【解决方案1】:

如果您问pow() 是否通过重复乘法实现幂运算,答案是否定的。您可以假设它已经过优化,因此通过检查零分子可能实现的任何节省可能都可以忽略不计。你绝对不想用for()循环来实现这个,它遍历大量的浮点计算。

另一方面,最好避免除以零。

我会这样实现你的功能:

double f(double a, double b, long m, long n) {
  if (b == 0) {
    // return error or infinity.
  }
  if (m >= n)
    return pow(a / b, n) * pow(a, m - n);
  else 
    return pow(a / b, m) / pow(b, n - m);
  }
}

【讨论】:

  • else return pow(a / b, m) * pow(b, m - n);会不会好一点?
  • 也许;我不知道现代浮点处理器。这就是分析器的用途。 :-)
猜你喜欢
  • 2014-02-21
  • 1970-01-01
  • 2012-02-09
  • 1970-01-01
  • 1970-01-01
  • 2012-10-05
  • 2010-12-13
  • 2012-04-11
相关资源
最近更新 更多