Log1p ve expm1 ne zaman kullanılmalıdır?


30

Google’a gerçekten zor olan basit bir sorum var (kanuni yanı sıra, Her Bir Bilgisayar Bilim Adamının Kayan Nokta Aritmetik makalesi hakkında bilmesi gerekenler ).

Gibi fonksiyonlar ne zaman log1pya da expm1yerine kullanılabilir logve exp? Ne zaman kullanılmamalıdır? Bu işlevlerin farklı uygulamaları kullanımları açısından nasıl farklılık gösterir?


2
Scicomp.SE'ye Hoşgeldiniz! Bu çok makul bir sorudur, ancak atıfta bulunduğunuz bir kısmı açıklarsanız cevaplamak daha kolay olacaktır log1p(özellikle nasıl uygulandığı, yani tahmin etmemize gerek yoktur).
Christian Clason

4
Gerçek değerli argümanlar için, log1p ve expm1 ( x ) , x küçük olduğunda, örneğin, kayan nokta hassasiyetinde 1 + x = 1 olduğunda kullanılmalıdır . Örneğin, docs.scipy.org/doc/numpy/reference/generated/numpy.expm1.html ve docs.scipy.org/doc/numpy/reference/generated/numpy.log1p.html adresini ziyaret edin . (x)(x)x1+x=1
GoHokies 02:15 '

@ChristianClason teşekkürler, çoğunlukla C ++ std veya R'ye atıfta bulunuyorum, ancak siz sorduğunuzda uygulamalardaki farklılıklar hakkında öğrenmenin de çok ilginç olacağını düşünmeye başladım.
Tim


1
@ user2186862 " küçük olduğunda " doğrudur, ancak yalnızca " kayan nokta hassasiyetinde 1 + x = 1 olduğunda" ( normal çift duyarlık aritmetiğindeki x 10 - 16 için olur ). Bağladığınız dokümantasyon sayfaları , örneğin x 10 - 10 için zaten faydalı olduklarını gösteriyor . x1+x=1x1016x1010
Federico Poloni

Yanıtlar:


25

exp(x)=n=0xnn!=1+x+12x2+
|x|1exp(x)1+xexp(x)1|x|1

Bu kolayca python ile gösterilebilir:

>>> 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

Genel olarak "doğru" bir uygulama en fazla 1ULP'dan (yani son yerin bir birimi) uygulanmasından ibarettir expve expm1doğru olmalıdır. Bununla birlikte, bu doğruluğa ulaşmak "yavaş" kodla sonuçlandığından, bazen hızlı, daha az doğru bir uygulama mevcuttur. Örneğin, CUDA’da biz expfve hızlı expm1fnerede duruyoruz f. Göre CUDA C, app kılavuzu programlama. Dexpf 2ULP bir hata vardır.

Birkaç ULPS sırasındaki hataları umursamıyorsanız, genellikle üstel fonksiyonun farklı uygulamaları eşdeğerdir, ancak böceklerin bir yere gizlenebileceğine dikkat edin ... ( Pentium FDIV hatasını hatırlayın ?)

expm1exp(x)1xxexpm1

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

1exp(200)

loglog1plog(1+x)x|x|1


1
Bu cevap OP sorusundaki yorumlarda zaten vardı. Bununla birlikte, bazı okuyucular için faydalı olacağını umarak, daha açık (daha temel olmasına rağmen) bir hesap vermek için kendimi faydalı hissettim.
Stefano M

Tamam, ama sonra basitçe bir sonuca varabiliriz "böylece her zaman exp yerine expm1 kullanabilirim" ...
Tim

1
@tim sonucunuz yanlış: expm1(x)bunun yerine her zaman kullanabilirsiniz exp(x)-1. Tabii ki exp(x) == exp(x) - 1genel değil.
Stefano M

x1

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

1

Arasındaki farka genişletmek için logve log1po logaritma eğer grafik hatırlamak yardımcı olabilir:

logaritma

logx0ln(x)x0ln(x)ln(1e)=1ln(1e10)=10

x0ln(x+1)0ln(1+1e)0.31ln(1+1e10)0.000045log1p

1log01log1p

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.