我有一个数值代码,解决方程
运行此程序的机器是CentOS上的AMD64(Opteron 6172),命令很简单:
解决这个问题对我至关重要。有没有人知道是否有任何方法可以避开这种缓慢?
编辑:John指出这是由于denormals引起的。问题是如何解决这个问题?该代码是C++编写的,使用
现在的伪解决方案:对于所有关心此问题的人,下面建议的解决方案对我个人而言都不起作用。我确实需要
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机器上都会出现类似的行为。正如此处所述,这不仅是我的问题(即其他人也很生气),而且仅适用于x
接近1.0
的情况。类似的事情也会发生在exp
中。解决这个问题对我至关重要。有没有人知道是否有任何方法可以避开这种缓慢?
编辑:John指出这是由于denormals引起的。问题是如何解决这个问题?该代码是C++编写的,使用
g++
编译,用于在GNU Octave
中使用。虽然我已经将CXXFLAGS
设置为包括-mtune=native
和-ffast-math
,但似乎没有帮助,代码运行速度仍然很慢。现在的伪解决方案:对于所有关心此问题的人,下面建议的解决方案对我个人而言都不起作用。我确实需要
std::pow()
的通常速度,但在x = 1
附近却不会缓慢。对我个人而言,解决方案是使用以下hack: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,已足够良好。根据我的发现,开销很小,因此这对我来说解决了问题。
__slowpow
)。 - interjay-ffast-math
会破坏 IEEE754 规范。这是否真的很糟糕还是可以接受,取决于您的用例,但如果我是您,我会在启用该标志之前进行进一步的研究以了解它正在做什么。 - us2012