我有一个解码方程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,这已经足够了。我发现的开销很小,因此解决了我的问题。
答案 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)对于某些输入具有可怕的最坏情况性能。
答案 2 :(得分:0)
它也可能是你的算法。也许改用BFGS而不是Newton的方法会有所帮助。
您没有说明您的收敛标准。也许那些需要调整。