什么时候应该使用log1p和expm1?


30

我有一个简单的问题,对于Google来说真的很难(除了每位计算机科学家应该知道的有关浮点算术的规范论文之外)。

什么时候应该使用诸如log1p或的功能expm1代替logexp?什么时候不应该使用它们?这些功能的不同实现在用法上有何不同?


2
欢迎来到Scicomp.SE!这是一个非常合理的问题,但如果你解释了一下会更容易回答 log1p你指的是(它尤其是如何实现的,所以我们不必去猜测)。
克里斯蒂安·克拉森2015年

4
对于实值参数,当较小时(例如,浮点精度为时应使用log1p和expm1。参见,例如docs.scipy.org/doc/numpy/reference/produced/numpy.expm1.htmldocs.scipy.org/doc/numpy/reference/produced/numpy.log1p.html(x)(x)x1+x=1
GoHokies 2015年

@ChristianClason谢谢,我主要指的是C ++ std或R,但是正如您所问的那样,我开始认为了解实现方面的差异也将非常有趣。
蒂姆(Tim)


1
@ user2186862“当小时”是正确的,但不仅是“当浮点精度为时”(在在通常的双精度算法中会发生)。您链接的文档页面显示,它们已经例如对有用。x1+x=1x1016x1010
Federico Poloni 2015年

Answers:


25

我们都知道,

exp(x)=n=0xnn!=1+x+12x2+
意味着,对于|x|1,我们有exp(x)1+x。这意味着如果必须在浮点exp(x)1中求值,则|x|1可能发生1次灾难性的取消。

这可以在python中轻松演示:

>>> from math import (exp, expm1)

>>> x = 1e-8
>>> exp(x) - 1
9.99999993922529e-09
>>> expm1(x)
1.0000000050000001e-08

>>> x = 1e-22
>>> exp(x) - 1
0.0
>>> expm1(x)
1e-22

精确值为

exp(108)1=0.000000010000000050000000166666667083333334166666668exp(1022)1=0.000000000000000000000100000000000000000000005000000

通常,“准确”的实现,exp并且expm1应正确不超过1ULP(即最后一个单元)。但是,由于达到此精度会导致代码“缓慢”,因此有时可以使用快速,精度较低的实现。例如在CUDA中,我们有expfand expm1f,其中f代表快速。根据CUDA C编程指南,app。Dexpf错误为2ULP。

如果您不在乎几个ULPS顺序的错误,通常指数函数的不同实现是等效的,但是请注意,错误可能隐藏在某处...(还记得Pentium FDIV错误吗?)

所以这是很清楚,expm1应该被用来计算exp(x)1为小型x。将其用于一般x并无害处,因为expm1可以预期它在整个范围内都是准确的:

>>> exp(200)-1 == exp(200) == expm1(200)
True

(在上面的示例中1远低于exp(200) 1ULP ,因此所有三个表达式都返回完全相同的浮点数。)

类似的讨论适用于逆函数loglog1plog(1+x)x|x|1


1
该回答已经包含在对OP问题的评论中。但是,我觉得给出一个更长的(尽管是基本的)解释只是为了清楚起见,希望对一些读者有用。
Stefano M

是的,但是然后可以简单地得出结论:“所以我可以始终使用expm1而不是exp” ...
蒂姆

1
@tim您的结论是错误的:您可以始终使用expm1(x)代替exp(x)-1。当然exp(x) == exp(x) - 1一般不成立。
Stefano M

好,很清楚。以及是否有任何明确的标准x1
蒂姆(Tim)

1
expm1(x)0x1exp(x) - 1x1x<ϵϵ

1

为了扩大两者之间的差异,如果对数loglog1p则可能有助于调出图形:

Logarithm

logx0ln(x)x0ln(x) is potentially a large negative number. For example ln(1e)=1 and ln(1e10)=10 and so on. This can be useful, but it can also distort your data towards large negative numbers, especially if your dataset also contains numbers much larger than zero.

On the other hand, as x approaches 0, the value of ln(x+1) approaches 0 from the positive direction. For example ln(1+1e)0.31 and ln(1+1e10)0.000045. So log1p produces only positive values and removes the 'danger' of large negative numbers. This generally insures a more homogeneous distribution when a dataset contains numbers close to zero.

In short, if the dataset is all greater than 1, then log is usually fine. But, if the dataset has numbers between 0 and 1, then log1p is usually better.

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.