std :: pow()非常慢,基数非常接近1

时间:2013-02-04 13:21:14

标签: c++ performance glibc pow

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

运行这个东西的机器是CentOS上的AMD64(Opteron 6172),命令很简单y = std::pow(x, p);。类似的行为出现在我的所有机器上,全部是x64。记录here,这不仅是我的问题(也就是说,其他人也很生气),只出现在x64上,仅适用于接近x的{​​{1}}。类似的事情发生在1.0

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

编辑:约翰指出这是由于非正规。问题是,如何解决这个问题?代码是C ++,使用exp编译,以便在g++中使用。看来,虽然我已将GNU Octave设置为包含CXXFLAGS-mtune=native,但这并没有帮助,而且代码运行速度也一样慢。

现在的解决方案:对于所有关心此问题的人,下面提出的解决方案对我个人而言并不适用。我真的需要-ffast-math的通常速度,但没有std::pow()周围的迟缓。我个人的解决方案是使用以下hack:

x = 1

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

3 个答案:

答案 0 :(得分:9)

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

问题不是非正规,至少不是直接的;试图计算exp(-2.4980018054066093e-15)遭受同样的减速,而-2.4980018054066093e-15肯定不是正常的。

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

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

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

答案 1 :(得分:1)

64位Linux?

使用FreeBSD的pow()代码。

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

请参阅:http://entropymine.com/imageworsener/slowpow/

答案 2 :(得分:0)

它也可能是你的算法。也许改用BFGS而不是Newton的方法会有所帮助。

您没有说明您的收敛标准。也许那些需要调整。