Hampir semua keluaran perhitungan numerik adalah floating point, dan seperti telah kita lihat pada Chapter Floating Point Comparison, membandingkannya dengan == hampir selalu keliru. Untuk pengujian otomatis, NumPy menyediakan np.testing.assert_allclose(actual, desired) — asersi yang membandingkan array dengan toleransi relatif dan absolut sekaligus, lalu melaporkan selisih terbesar bila melebihi batas.
Bab ini membedah dua parameter intinya, rtol dan atol, beserta rumus penggabungannya; menunjukkan cara memilih toleransi untuk data keuangan dan data ilmiah; serta perilaku bawaannya yang memperlakukan nan sebagai nilai yang sah. Nilai bawaannya berbeda dari np.isclose: di sini rtol=1e-07 dan atol=0.
Toleransi Bawaan rtol=1e-07, atol=0 #
Dengan pengaturan bawaan, assert_allclose mengizinkan selisih relatif sekitar tujuh digit signifikan. Cara tercepat merasakannya adalah menguji dua nilai yang selisihnya makin besar:
import numpy as np
from numpy.testing import assert_allclose
try:
assert_allclose(np.array([100.000001]), np.array([100.0]))
print("selisih 1e-6: lulus")
except AssertionError:
print("selisih 1e-6: tidak lulus")
try:
assert_allclose(np.array([100.0001]), np.array([100.0]))
print("selisih 1e-4: lulus")
except AssertionError as e:
print("selisih 1e-4: tidak lulus")
print(e)Output yang Dihasilkan:
selisih 1e-6: lulus
selisih 1e-4: tidak lulus
Not equal to tolerance rtol=1e-07, atol=0
Mismatched elements: 1 / 1 (100%)
Max absolute difference among violations: 0.0001
Max relative difference among violations: 1.e-06
ACTUAL: array([100.0001])
DESIRED: array([100.])Mari kita bedah:
- Baris 5-8: selisih
1e-6pada nilai100.0berarti galat relatif1e-8— di bawahrtol=1e-07dikalikan100.0yang bernilai1e-5— sehingga pengujian lulus dalam keheningan. - Baris 9-14: selisih
1e-4melampaui batas dan memunculkanAssertionError. Pesannya langsung menampilkan pengaturan yang dipakai:Not equal to tolerance rtol=1e-07, atol=0. - Laporan kesalahan:
Max absolute differencedanMax relative differencemenunjukkan seberapa jauh nilai meleset pada dua ukuran sekaligus — informasi yang memudahkan memutuskan toleransi mana yang harus dilonggarkan.
Rumus Penggabungan atol dan rtol #
Kedua toleransi tidak dipilih salah satu, melainkan dijumlahkan. Pengujian lulus ketika |actual - desired| <= atol + rtol * |desired|. Sifat ini paling terasa saat membandingkan nilai dengan nol, karena suku relatifnya otomatis nol:
import numpy as np
from numpy.testing import assert_allclose
try:
assert_allclose(np.array([1e-7]), np.array([0.0]))
print("default: lulus")
except AssertionError:
print("default: tidak lulus")
try:
assert_allclose(np.array([1e-7]), np.array([0.0]), atol=1e-6)
print("atol=1e-6: lulus")
except AssertionError:
print("atol=1e-6: tidak lulus")
selisih = abs(1e-7 - 0.0)
print("|a-b| =", selisih, "<= atol + rtol*|b| =", 0.0 + 1e-7 * 0.0)Output yang Dihasilkan:
default: tidak lulus
atol=1e-6: lulus
|a-b| = 1e-07 <= atol + rtol*|b| = 0.0Penjelasan tiap bagian:
- Baris 4-8: dengan
atol=0, selisih sekecil apa pun terhadap nol ditolak — toleransi relatifrtol * |0.0|tidak pernah memberi longgar. - Baris 9-13: menetapkan
atol=1e-6memberi jendela absolut±1e-6di sekitar nol, dan nilai1e-7kini diterima. - Baris 15-16: baris terakhir menampilkan evaluasi rumus secara langsung:
|a-b| = 1e-07jelas lebih besar dariatol + rtol*|b| = 0.0, persis alasan kasus bawaan ditolak.
Memilih Toleransi: Keuangan vs Ilmiah #
Toleransi yang tepat ditentukan oleh makna data, bukan selera. Untuk harga dalam rupiah, longgar yang bermakna adalah nilai uang terkecil — misalnya lima sen — sehingga atol yang memimpin. Untuk hasil pengukuran ilmiah, kesalahan biasanya dinilai relatif terhadap besaran yang diukur:
import numpy as np
from numpy.testing import assert_allclose
harga = np.array([14999.99, 21999.95, 8000.00])
target = np.array([15000.00, 22000.00, 8000.00])
try:
assert_allclose(harga, target, atol=0.05, rtol=0)
print("atol=0.05: lulus")
except AssertionError:
print("atol=0.05: tidak lulus")
try:
assert_allclose(harga, target)
print("default: lulus")
except AssertionError:
print("default: tidak lulus")
ukur = np.array([9.81])
teori = np.array([9.80665])
try:
assert_allclose(ukur, teori)
print("rtol default: lulus")
except AssertionError:
print("rtol default: tidak lulus")
try:
assert_allclose(ukur, teori, rtol=1e-3)
print("rtol=1e-3 : lulus")
except AssertionError:
print("rtol=1e-3 : tidak lulus")Output yang Dihasilkan:
atol=0.05: lulus
default: tidak lulus
rtol default: tidak lulus
rtol=1e-3 : lulusBedah kedua kasus:
- Kasus harga, baris 6-14: selisih terbesar hanya
0.05rupiah, jadiatol=0.05denganrtol=0meluluskannya. Pengaturan bawaan justru menolak — galat relatif3.3e-6terhadap15000melebihirtol=1e-07— bukti bahwa toleransi relatif saja kurang pas untuk data uang. - Kasus pengukuran, baris 16-24: pengukuran
9.81melawan nilai acuan9.80665meleset sekitar0.03%;rtol=1e-3menerima tingkat ketidakpastian itu, sedangkanrtol=1e-07terlalu ketat untuk pengukuran eksperimen.
Kedua parameter menerima array juga scalar, sehingga toleransi per elemen bisa ditetapkan bila akurasi tiap kolom berbeda — misalnya atol kecil untuk kolom rasio dan besar untuk kolom jumlah uang.
Perbandingan yang Sadar NaN #
Seperti fungsi numpy.testing lainnya, assert_allclose memperlakukan nan pada posisi yang sama sebagai kesamaan. Perilaku ini diatur parameter equal_nan yang secara bawaan bernilai True:
import numpy as np
from numpy.testing import assert_allclose
a = np.array([np.nan, 1.0, 250.0000005])
b = np.array([np.nan, 1.0, 250.0])
try:
assert_allclose(a, b, rtol=1e-7, atol=1e-6)
print("default equal_nan: lulus")
except AssertionError:
print("default equal_nan: tidak lulus")
try:
assert_allclose(a, b, rtol=1e-7, atol=1e-6, equal_nan=False)
print("equal_nan=False: lulus")
except AssertionError:
print("equal_nan=False: tidak lulus")Output yang Dihasilkan:
default equal_nan: lulus
equal_nan=False: tidak lulusMari kita baca:
- Baris 6-10: elemen
nandi posisi pertama dianggap cocok, dan elemen ketiga lulus karena selisih5e-7berada di dalam jendelaatol=1e-6— pengujian lulus tanpa perlu filter terlebih dahulu. - Baris 11-15:
equal_nan=Falsemengembalikan semantik murninan, dan pengujian tidak lulus pada elemen pertama. Opsi ini berguna ketika kehadirannanjustru harus terdeteksi sebagai keluaran yang salah.
Tabel ringkas parameter assert_allclose sebagai penutup:
| Parameter | Bawaan | Peran |
|---|---|---|
actual | wajib | hasil perhitungan yang sedang diuji |
desired | wajib | nilai acuan; suku rtol dihitung terhadap ` |
rtol | 1e-07 | longgar relatif untuk nilai besar |
atol | 0 | longgar absolut untuk wilayah dekat nol |
equal_nan | True | nan dianggap cocok dengan nan pada posisi sama |
Dengan assert_allclose dalam genggaman, kita sudah punya alat utama pengujian numerik. Bab berikutnya menyusunnya menjadi rangkaian kasus uji yang utuh — lengkap dengan kasus batas seperti array kosong dan input yang membuat hasil meluap.