5

我有一个解方程的数字代码,f(x) = 0我必须在其中提高xp。我用一堆东西来解决它,但最后我有牛顿的方法。解决方案恰好等于x = 1,因此是我的问题的原因。例如,当迭代解决方案接近 时1x = 1 + 1e-13计算所需的时间std::pow(x, p)会大大增加,很容易增加 100 倍,使我的代码无法使用。

运行这个东西的机器是CentOS上的AMD64(Opteron 6172),命令很简单y = std::pow(x, p);。类似的行为出现在我所有的机器上,都是 x64。如此处所述,这不仅是我的问题(即,其他人也很生气),仅出现在 x64 上且仅用于x接近1.0. 类似的事情也发生在exp

解决这个问题对我来说至关重要。有谁知道是否有办法绕过这种缓慢?

编辑:约翰指出这是由于非规范化。那么问题来了,如何解决这个问题?代码是 C++,编译后g++用于GNU Octave. 看来,尽管我已设置CXXFLAGS包含-mtune=nativeand -ffast-math,但这并没有帮助,代码运行速度也一样慢。

现在的伪解决方案:对于所有关心这个问题的人,下面建议的解决方案对我个人来说并不适用。我真的需要平时的速度std::pow(),但没有周围的呆滞x = 1。我个人的解决方案是使用以下技巧:

inline double mpow(double x, double p) __attribute__ ((const));

inline double mpow(double x, double p)
{
    double y(x - 1.0);
    return (std::abs(y) > 1e-4) ? (std::pow(x, p)) : (1.0 + p * y * (1.0 + (p - 1.0) * y * (0.5 + (1.0 / 6.0) * (p - 2.0) * y)));
}

界限可以改变,但对于 -40 < p < 40,误差小于大约 1e-11,这已经足够了。与我发现的相比,开销很小,因此为我解决了这个问题。

4

3 回答 3

9

显而易见的解决方法是在实数中注明,a ** b == exp(log(a) * b)并改用该形式。您需要检查它是否不会对结果的准确性产生不利影响。编辑:正如所讨论的,这也受到了几乎同样程度的放缓的影响。

问题不在于异常,至少不是直接的;尝试计算exp(-2.4980018054066093e-15)会遇到同样的减速,并且 -2.4980018054066093e-15 肯定不是异常的。

如果您不关心结果的准确性,那么缩放指数或指数应该会让您超出慢速区域:

sqrt(pow(a, b * 2))
pow(a * 2, b) / pow(2, b)
...

glibc 维护人员知道此错误:http: //sourceware.org/bugzilla/show_bug.cgi ?id=13932 - 如果您正在寻找修复而不是解决方法,您需要委托浮点数学专家具有开源经验。

于 2013-02-04T13:40:08.283 回答
1

64位Linux?

使用来自 FreeBSD 的 pow() 代码。

Linux C 库 (glibc) 对于某些输入具有可怕的最坏情况性能。

见:http ://entropymine.com/imageworsener/slowpow/

于 2015-10-16T03:26:42.577 回答
0

It could be your algorithm, too. Perhaps switching to something like BFGS instead of Newton's method will help.

You don't say anything about your convergence criteria. Maybe those need adjusting as well.

于 2013-02-04T13:26:05.590 回答