我正在寻找一个简单的log1p可移植实现。我遇到过两个实现。
第一个在这里显示为定理4 http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html,
上述
的实现double log1p(double p)
{
volatile double y = p;
return ( (1 + y) == 1 ) ? y : y * ( log( 1 + y) / ( ( 1 + y) - 1 ) );
}
第二个是GSL http://fossies.org/dox/gsl-1.16/log1p_8c_source.html
double gsl_log1p (const double x)
{
volatile double y, z;
y = 1 + x;
z = y - 1;
return log(y) - (z-x)/y ; /* cancels errors with IEEE arithmetic */
}
是否有理由偏爱另一个?
答案 0 :(得分:2)
我使用log()
实现测试了这两种方法,最大误差为<与多精度算术库相比,0.53 ulps。使用log()
实现作为两个log1p()
变体的构建块,我发现Goldberg的版本的最大错误是&lt; 1.51 ulps,而GSL变体中的最大误差<1。 0.67 ulps。这表明后者更准确。
就特殊情况处理而言,Goldberg变体显示出一个不匹配,因为它为+无穷大的输入返回NaN,而正确的结果是+无穷大。对于具有GSL实现的特殊情况,存在三个不匹配:-1和+无穷大的输入提供NaN,而正确的结果应分别为-infinity和+ infinity。此外,对于-0的输入,此代码返回+0,而正确的结果是-0。
如果不了解投入的分布,很难评估绩效。正如其他人在评论中指出的那样,当许多参数接近零时,Goldberg的版本可能会更快,因为它会跳过对这些参数的昂贵的log()
调用。
答案 1 :(得分:0)
两者之间没有确定的答案。 GNU Scientific Library非常强大,使用良好,并且在所有后期版本的gcc中得到了积极支持。使用它时,你不太可能遇到太多的惊喜。至于你搞砸的任何其他代码,在你验证了它的逻辑并且对它的错误检查级别/方式感到满意之后,绝对没有理由不使用它。 GSL的一个小缺点是,它是您必须随身携带的另一个库,并且取决于您的代码的广泛使用将为其他平台上的其他用户提供更多挑战。这大约是它的大小。
最好的代码是最符合项目要求的代码。