Pertumbuhan bunga berbunga, peluruhan panas, dan pertambahan populasi mengikuti pola eksponensial, sedangkan skala desibel, pH, dan perbedaan orde magnitudo diukur dengan logaritma. NumPy menyediakan kedua kelompok fungsi ini sebagai ufunc: np.exp untuk eksponensial dan np.log beserta variannya untuk logaritma. Keduanya bekerja elemen-per-elemen pada array, sehingga perhitungan untuk ribuan titik data sekaligus tetap satu baris kode.

Bab ini membahas:

  • np.exp dan contoh pertumbuhan majemuk.
  • np.expm1 dan np.log1p untuk nilai input yang sangat kecil.
  • np.log, np.log2, dan np.log10 beserta perilakunya pada input nol dan negatif.

np.exp dan Pertumbuhan Majemuk #

Fungsi np.exp(x) menghitung e^x untuk setiap elemen, dengan e ≈ 2.718281828. Bentuk ini menjadi dasar rumus pertumbuhan majemuk kontinu V = V0 * e^(r * t), dengan r laju pertumbuhan per periode dan t waktu. Kita coba pada investasi Rp10.000.000 dengan laju 8% per tahun selama lima tahun:

python
import numpy as np

modal = 10_000_000
tahun = np.arange(0, 6)
nilai = modal * np.exp(0.08 * tahun)
for t, v in zip(tahun, nilai):
    print(f"Tahun {t}: Rp{v:,.0f}")

Output yang Dihasilkan:

text
Tahun 0: Rp10,000,000
Tahun 1: Rp10,832,871
Tahun 2: Rp11,735,109
Tahun 3: Rp12,712,492
Tahun 4: Rp13,771,278
Tahun 5: Rp14,918,247

Mari kita bedah:

  1. Baris 3 (modal = 10_000_000): pemisah garis bawah hanya memperjelas pembacaan angka; nilai tersimpan tetap 10000000.
  2. Baris 4 (tahun = np.arange(0, 6)): interpreter membuat array [0, 1, 2, 3, 4, 5] sebagai sumbu waktu.
  3. Baris 5 (nilai = modal * np.exp(...)): np.exp(0.08 * tahun) menghitung e^(0,08t) untuk keenam titik waktu sekaligus, lalu hasilnya dikalikan modal.
  4. Baris 6-7 (loop for): zip memasangkan tahun dengan nilainya, dan format {:,.0f} menampilkan pemisah ribuan tanpa angka desimal.

Bentuk dasarnya sendiri sederhana:

python
import numpy as np

x = np.array([0.0, 1.0, 2.0, 5.0])
print(np.exp(x))

Output yang Dihasilkan:

text
[  1.           2.71828183   7.3890561  148.4131591 ]

expm1 dan log1p untuk Nilai Input Kecil #

Menghitung exp(x) - 1 dengan cara biasa memicu pembatalan presisi (catastrophic cancellation) ketika x sangat kecil: np.exp(1e-10) bernilai hampir sama persis dengan 1, sehingga pengurangan dengan 1.0 membuang sebagian besar angka signifikan. NumPy menyediakan np.expm1 yang menghitung e^x - 1 langsung tanpa melalui nilai mendekati 1. Pasangannya adalah np.log1p, versi akurat untuk log(1 + x):

python
import numpy as np

x = 1e-10
print(np.expm1(x))
print(np.exp(x) - 1.0)
print(np.log1p(x))
print(np.log(1.0 + x))

Output yang Dihasilkan:

text
1.00000000005e-10
1.000000082740371e-10
9.999999999500001e-11
1.000000082690371e-10

Nilai teoretis yang benar untuk expm1(1e-10) adalah 1e-10 + 5e-21, yang tampil sebagai 1.00000000005e-10. Hasil np.exp(1e-10) - 1.0 meleset sekitar 8x10^-8 secara relatif — kesalahan kecil bagi mata manusia, tetapi cukup besar saat hasilnya dipakai untuk perhitungan lanjutan. Pola yang sama terlihat pada log1p(1e-10) yang menghasilkan 9.999999999500001e-11, sedangkan np.log(1.0 + 1e-10) memberi nilai yang meleset lebih jauh.

Logaritma: log, log2, dan log10 #

np.log menghitung logaritma natural (basis e), np.log2 basis 2, dan np.log10 basis 10. Ketiganya adalah invers dari np.exp, np.exp2, dan 10 ** x:

python
import numpy as np

x = np.array([1.0, np.e, 8.0, 100.0])
print(np.log(x))
print(np.log2(np.array([8.0, 1024.0])))
print(np.log10(np.array([100.0, 1_000_000.0])))

Output yang Dihasilkan:

text
[0.         1.         2.07944154 4.60517019]
[ 3. 10.]
[2. 6.]

Setiap logaritma berpasangan dengan satu eksponensial sebagai inversnya, dan pemilihan basis menyesuaikan domain data:

Fungsi eksponensialInvers logaritmanyaContoh pasangan
np.expnp.loglog(e^3) = 3.0
np.exp2np.log2log2(1024) = 10
10 ** xnp.log10log10(1_000_000) = 6

Logaritma natural lazim untuk pertumbuhan dan peluruhan, log2 untuk kecerdasan buatan dan teori informasi (ukuran bit), sedangkan log10 untuk skala seperti desibel dan besaran orde magnitudo.

Perilaku pada input tidak valid berbeda untuk nol dan bilangan negatif: log(0) menghasilkan -inf, sedangkan log(bilangan negatif) menghasilkan nan. NumPy mencetak runtime warning ketika operasi ini terjadi; bungkus pemanggilan dengan np.errstate agar output program tetap bersih:

python
import numpy as np

x = np.array([1.0, 0.0, -4.0])
with np.errstate(divide="ignore", invalid="ignore"):
    print(np.log(x))

Output yang Dihasilkan:

text
[  0. -inf  nan]