对于非常接近1的基数,std::pow()非常慢
Very slow std::pow() for bases very close to 1
我有一个求解方程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。如本文所述,这不仅是我的问题(即,其他人也很生气),仅出现在x64上,并且仅适用于接近1.0
的x
。类似的事情也发生在exp
上。
解决这个问题对我来说至关重要。有人知道是否有办法绕过这种缓慢吗?
编辑:约翰指出,这是由于非标准化。那么问题是,如何解决这个问题呢?代码是C++,使用g++
编译以在GNU Octave
中使用。看起来,尽管我已经将CXXFLAGS
设置为包括-mtune=native
和-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,这已经足够好了。从我的发现来看,开销是最小的,因此这为我解决了问题。
显而易见的解决方法是注意,在reals中,a ** b == exp(log(a) * b)
并使用该形式。你需要检查它是否会对你的结果的准确性产生不利影响。编辑:正如所讨论的,这也在很大程度上受到了经济放缓的影响。
问题不在于非规范化,至少不是直接的;尝试计算exp(-2.4980018054066093e-15)
会遇到同样的减速,并且-2.4980018054066093e-15肯定不是非正规的。
如果你不在乎结果的准确性,那么缩放exponend或指数应该会让你走出慢区:
sqrt(pow(a, b * 2))
pow(a * 2, b) / pow(2, b)
...
glibc维护人员知道这个错误:http://sourceware.org/bugzilla/show_bug.cgi?id=13932-如果你正在寻找一个解决方案,而不是一个变通方案,你会想聘请一位具有开源经验的浮点数学专家。
64位Linux?
使用来自FreeBSD的pow()代码。
对于某些输入,Linux C库(glibc)在最坏的情况下具有糟糕的性能。
请参阅:http://entropymine.com/imageworsener/slowpow/
这也可能是您的算法。也许改用BFGS方法而不是牛顿方法会有所帮助。
你没有提及你的收敛标准。也许这些也需要调整。
- 使用std::multimap迭代器创建std::list
- C++中std::resize(n)和std::shrink_to_fit之间的区别
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 如何导出包含具有"std::unique_ptr"值的"std::map"属性的
- 为什么std::互斥需要很长的、非常不规则的时间来共享
- 我的自定义使用 std::unordered_map 的性能非常慢
- std::initializer_list私有构造函数是否从编译器那里得到非常特殊的处理
- 为什么std::cout打印非常小的科学符号值,而不是四舍五入到零
- 非常奇怪的弦乐和std :: getline行为
- std::tan()在更新glibc后速度非常慢
- C++使用std::sort为非常小的std::vector抛出std::bad_alloc异常
- std::与VS2013相比,GCC 4.7.2中的MAP实现效率非常低
- std::sort给出了非常奇怪的结果
- std::istream 提取运算符(双精度或浮点数)在 VS 2012 中非常慢
- 为什么这个非常简单的返回 std::move(线程句柄)失败
- std::iota非常有限
- std::fclose()有一个非常奇怪的问题
- 对于非常接近1的基数,std::pow()非常慢
- 非常慢的std::cout使用MS编译器