到目前为止,我所确定的最佳方法是根据较大源操作数除以较小源操作数的商来区分三种情况。这个比率告诉我们操作数之间的距离。如果它太大,超过了本机精度的最大可表示数,则必须使用商规则,并将结果计算为
log(a) - log(b)
. 如果比值接近一,则计算应利用该函数。
log1p()
为了提高精度,计算结果为
log1p ((a - b) / b)
. 这个
Sterbenz Lemma
建议
2.0
这是一个很好的转换点,因为
a-b
如果比率为2,将精确计算。对于所有其他情况,直接计算
log (a/b)
可以使用。
下面,我展示了一个接受函数的设计的实现
float
参数。使用
浮动
这样可以更容易地评估准确性,因为这样可以对可能的测试用例进行更密集的采样。显然,总体的准确性将取决于实施的质量
logf()
和
logpf()
在数学图书馆。使用具有几乎正确四舍五入的函数的数学库(在
Logf()
<0.524 ulp,最大误差
log1pf()
<0.506 ulp),在
log_quotient()
是1.5 ulps。使用不同的库,并对函数进行精确的四舍五入实现(在
Logf()
<0.851 ulp,最大误差
日志1pf()
<0.874 ulp),在
对数商()
是1.7 ulps。
#include <float.h>
#include <math.h>
/* Compute log (a/b) for a, b â (0, â) accurately and robustly, i.e. avoiding
underflow and overflow in intermediate computations. Using a math library
that provides log1pf() and logf() with a maximum error close to 0.5 ulps,
the maximum observed error was 1.49351 ulp.
*/
float log_quotient (float a, float b)
{
float ratio = fmaxf (a, b) / fminf (a, b);
if (ratio > FLT_MAX) {
return logf (a) - logf (b);
} else if (ratio > 2.0f) {
return logf (a / b);
} else {
return log1pf ((a - b) / b);
}
}