Kita semua tahu bahwa
exp(x)=∑n=0∞xnn!=1+x+12x2+…
menyiratkan bahwa untuk|x|≪1, kami memilikiexp(x)≈1+x. Ini berarti bahwa jika kita harus mengevaluasi dalam floating pointexp(x)−1, untuk|x|≪1pembatalan katastropik dapat terjadi.
Ini dapat dengan mudah ditunjukkan dengan 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
Nilai yang tepat adalah
exp(10−8)−1exp(10−22)−1=0.000000010000000050000000166666667083333334166666668…=0.000000000000000000000100000000000000000000005000000…
Secara umum implementasi "akurat" dari expdan expm1harus benar tidak lebih dari 1ULP (yaitu satu unit tempat terakhir). Namun, karena mencapai akurasi ini menghasilkan kode "lambat", terkadang implementasi yang cepat dan kurang akurat tersedia. Misalnya dalam CUDA yang kita miliki expfdan expm1f, di mana fsingkatan dari fast. Menurut panduan pemrograman CUDA C, aplikasi. D yang expfmemiliki kesalahan dari 2ULP.
Jika Anda tidak peduli tentang kesalahan dalam urutan beberapa ULPS, biasanya implementasi yang berbeda dari fungsi eksponensial adalah setara, tetapi berhati-hatilah bahwa bug mungkin disembunyikan di suatu tempat ... (Ingat bug Pentium FDIV ?)
Jadi cukup jelas bahwa expm1harus digunakan untuk menghitung exp(x)−1 untuk x kecil . Menggunakannya untuk x umum tidak berbahaya, karena expm1diharapkan akurat pada kisaran lengkapnya:
>>> exp(200)-1 == exp(200) == expm1(200)
True
(Dalam contoh di atas 1 jauh di bawah 1ULP exp(200) , jadi ketiga ekspresi mengembalikan angka floating point yang persis sama.)
Diskusi serupa berlaku untuk fungsi terbalik logdan log1pkarena log(1+x)≈x untuk |x|≪1 .
log1pAnda maksud (terutama bagaimana penerapannya, jadi kami tidak perlu menebak).