Sappiamo tutti che
exp( x ) = ∑n = 0∞Xnn != 1 + x + 12X2+ ...
implica che per| x | ≪1, abbiamoexp( x ) ≈ 1 + x. Ciò significa che se dobbiamo valutare in virgola mobileexp( x ) - 1, per| x | ≪1cancellazione catastrofica può verificarsi.
Questo può essere facilmente dimostrato in 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
I valori esatti sono
exp(10−8)−1exp(10−22)−1=0.000000010000000050000000166666667083333334166666668…=0.000000000000000000000100000000000000000000005000000…
In generale, un'implementazione "accurata" di exp
e expm1
dovrebbe essere corretta per non più di 1ULP (cioè un'unità dell'ultimo posto). Tuttavia, poiché il raggiungimento di questa accuratezza comporta un codice "lento", a volte è disponibile un'implementazione rapida e meno accurata. Ad esempio in CUDA abbiamo expf
e expm1f
, dove f
sta veloce. Secondo la guida alla programmazione CUDA C, app. D l' expf
ha un errore di 2ULP.
Se non ti preoccupi degli errori nell'ordine di pochi ULPS, di solito diverse implementazioni della funzione esponenziale sono equivalenti, ma fai attenzione che i bug potrebbero essere nascosti da qualche parte ... (Ricorda il bug Pentium FDIV ?)
expm1
exp(x)−1xxexpm1
>>> exp(200)-1 == exp(200) == expm1(200)
True
1exp(200)
log
log1p
log(1+x)≈x|x|≪1
log1p
ti riferisci (specialmente come è implementato, quindi non dobbiamo indovinare).