MATLAB menyimpan setiap angka pecahan sebagai floating point standar IEEE 754, bukan sebagai nilai desimal eksak. Akibatnya, 0.1 + 0.2 di MATLAB tidak sama persis dengan 0.3, dan penjumlahan sepuluh ribu angka bisa menyimpang dari hasil teoretisnya walau kodenya benar. Memahami cara angka disimpan membantu kita membaca hasil numerik secara kritis: kapan selisih kecil boleh diabaikan, dan kapan selisih kecil itu menandakan rumus yang keliru. Chapter ini membongkar struktur bit double precision, konstanta batas eps/realmin/realmax, kasus khusus Inf dan NaN, hingga akumulasi galat pada penjumlahan berulang.
Representasi IEEE 754 Double Precision #
Aturannya: setiap angka bertipe double menempati 64 bit yang terbagi menjadi tiga medan — sign (tanda), exponent (eksponen), dan mantissa (pecahan). Mekanisme di balik layar: MATLAB menyimpan angka dalam bentuk biner (-1)^s * 2^(e-1023) * 1.mantissa, sehingga mantissa 52 bit hanya mampu memuat sekitar 15-16 digit desimal signifikan. Angka desimal seperti 0.1 memiliki bentuk biner yang periodik (tak berujung), sehingga MATLAB harus membulatkannya ke double terdekat.
Diagram di atas memperlihatkan tata letak 64 bit: tanda menentukan positif atau negatif, eksponen menggeser titik biner (rentang kira-kira 2^-1022 sampai 2^1023), dan mantissa menyimpan digit signifikan. Fungsi num2hex() menampilkan isi bit tersebut dalam bentuk heksadesimal:
fprintf('num2hex(0.1) = %s\n', num2hex(0.1));
fprintf('num2hex(0.1+0.2) = %s\n', num2hex(0.1 + 0.2));
fprintf('num2hex(0.3) = %s\n', num2hex(0.3));
fprintf('0.1 + 0.2 - 0.3 = %.6e\n', 0.1 + 0.2 - 0.3);Output yang Dihasilkan:
num2hex(0.1) = 3fb999999999999a
num2hex(0.1+0.2) = 3fd3333333333334
num2hex(0.3) = 3fd3333333333333
0.1 + 0.2 - 0.3 = 5.551115e-17Mari kita bedah baris-baris kode di atas:
- Baris 1 (
num2hex(0.1)): pola999...99apada mantissa menandakan0.1memang tidak bisa ditulis eksak dalam biner — nilainya dibulatkan ke double terdekat. - Baris 2 (
num2hex(0.1+0.2)): hasil penjumlahan berakhiran digit...34. - Baris 3 (
num2hex(0.3)): representasi0.3langsung berakhiran...33— berbeda satu langkah pembulatan (1 ulp) dari hasil penjumlahan. - Baris 4 (
0.1 + 0.2 - 0.3): selisih5.55e-17adalah bukti bahwa0.1 + 0.2tidak identik dengan0.3di level bit.
Konstanta Batas: realmin, realmax, dan eps #
MATLAB menyediakan tiga konstanta bawaan yang memetakan batas representasi double. Eksponen 11 bit membatasi rentang bilangan, sedangkan mantissa 52 bit membatasi ketelitian:
fprintf('eps = %.6e\n', eps);
fprintf('realmin = %.6e\n', realmin);
fprintf('realmax = %.6e\n', realmax);
fprintf('eps(1) = %.6e\n', eps(1));
fprintf('eps(2) = %.6e\n', eps(2));
fprintf('eps(16) = %.6e\n', eps(16));Output yang Dihasilkan:
eps = 2.220446e-16
realmin = 2.225074e-308
realmax = 1.797693e+308
eps(1) = 2.220446e-16
eps(2) = 4.440892e-16
eps(16) = 3.552714e-15Mari kita bedah baris-baris kode di atas:
- Baris 1 (
eps): jarak dari1ke double terdekat berikutnya — ukuran pembulatan dasar sekitar 2.22e-16. - Baris 2-3 (
realmin,realmax): bilangan normal positif terkecil dan terbesar yang bisa disimpan. - Baris 4-6 (
eps(x)): jarak antar double pada skalax; setiap kali nilai dua kali lebih besar, jaraknya juga dua kali lebih besar — itulah sebabnyaeps(2)daneps(16)lebih besar daripadaeps(1).
Konsekuensi langsungnya: bilangan bulat hanya eksak sampai 2^53 (sekitar 9e15), karena di atas nilai tersebut jarak antar double melampaui 1.
fprintf('2^53 + 1 - 2^53 = %d\n', 2^53 + 1 - 2^53);
fprintf('2^53 + 2 - 2^53 = %d\n', 2^53 + 2 - 2^53);Output yang Dihasilkan:
2^53 + 1 - 2^53 = 0
2^53 + 2 - 2^53 = 2Pada nilai 2^53, jarak antar bilangan adalah 2. Penambahan 1 dibulatkan kembali ke 2^53 (hasil 0), sedangkan penambahan 2 tersimpan dengan benar.
Denormal, Inf, dan NaN #
Angka di bawah realmin tidak langsung jatuh ke nol. MATLAB memakai bilangan denormal: eksponen diturunkan ke nol dan presisi mantissa berkurang bertahap (gradual underflow) sampai bilangan terkecil realmin * eps = 4.94e-324. Sebaliknya, hasil yang melebihi realmax menjadi Inf (overflow), dan operasi tak terdefinisi menghasilkan NaN:
fprintf('realmin / 2 = %.6e (denormal)\n', realmin / 2);
fprintf('realmin * eps = %.6e (denormal terkecil)\n', realmin * eps);
fprintf('realmin*eps / 2 == 0 -> %d (underflow)\n', realmin * eps / 2 == 0);
fprintf('realmax * 2 = %g (overflow)\n', realmax * 2);
fprintf('1/0 = %g, 0/0 = %g, Inf - Inf = %g\n', 1/0, 0/0, Inf - Inf);
fprintf('NaN == NaN -> %d, NaN ~= NaN -> %d\n', NaN == NaN, NaN ~= NaN);Output yang Dihasilkan:
realmin / 2 = 1.112537e-308 (denormal)
realmin * eps = 4.940656e-324 (denormal terkecil)
realmin*eps / 2 == 0 -> 1 (underflow)
realmax * 2 = Inf (overflow)
1/0 = Inf, 0/0 = NaN, Inf - Inf = NaN
NaN == NaN -> 0, NaN ~= NaN -> 1Mari kita bedah baris-baris kode di atas:
- Baris 1-3: pembagian
realmin/2masih tersimpan sebagai denormal, tetapi setelah melewatirealmin*eps, pembagian dua berikutnya menghasilkan0murni — underflow penuh. - Baris 4-5:
realmax*2meluap menjadiInf; pembagian1/0jugaInf, sedangkan0/0danInf-Inftidak punya nilai yang bermakna sehingga menjadiNaN. - Baris 6: perbandingan
NaN == NaNbernilaifalse—NaNtidak pernah sama dengan apa pun, termasuk dirinya sendiri.
Akumulasi Galat pada Penjumlahan #
Masalah nyatanya: galat pembulatan tidak berhenti di satu operasi — galat menumpuk. Contoh klasiknya, kita menjumlahkan 0.1 sepuluh ribu kali dan membandingkan hasilnya dengan nilai eksak 1000:
total = 0;
for k = 1:10000
total = total + 0.1;
end
fprintf('total = %.10f\n', total);
fprintf('galat = %.3e\n', total - 1000);Output yang Dihasilkan:
total = 1000.0000000002
galat = 1.588e-10Mari kita bedah baris-baris kode di atas:
- Baris 1 (
total = 0): akumulator diinisialisasi sebelum loop — pola yang sama dengan loop penjumlahan di section struktur kontrol. - Baris 2-4 (
forloop): setiap iterasi membulatkantotal + 0.1ke double terdekat; pembulatan kecil yang berulang 10.000 kali menumpuk menjadi simpangan total 1.588e-10. - Baris 5-6 (
fprintf): pencetakan dengan 10 angka desimal menyingkap selisih yang tersembunyi — pada tampilanformat short, kedua nilai tampak identik dengan1000.
Simpangan 1.6e-10 terasa kecil, tetapi galat sejenis bisa membesar pada simulasi jutaan langkah. Kita bedah dampaknya yang lebih dramatis pada chapter Numerical Errors.
Penulisan Ilmiah #
Notasi ilmiah ditulis dengan huruf e: 1.5e3 berarti 1.5 x 10^3, dan 2.5e-4 berarti 2.5 x 10^-4. Bentuk ini bukan sekadar gaya tampilan — 6.02214076e23 adalah cara menulis konstanta fisika yang melebihi digit presisi double sekaligus menjaga keterbacaan:
fprintf('%g %g %g\n', 1.5e3, 2.5e-4, 6.02214076e23);Output yang Dihasilkan:
1500 0.00025 6.02214e+23Berkas contoh.m pada bagian bawah halaman menjalankan seluruh contoh di atas dalam satu script utuh, dari konstanta batas hingga akumulasi galat.
Ringkasan #
Setiap double MATLAB adalah 64 bit IEEE 754: 1 bit tanda, 11 bit eksponen, 52 bit mantissa — sekitar 15-16 digit signifikan. Konstanta eps, realmin, dan realmax memetakan batas presisi dan rentang; eps(x) mengukur jarak antar bilangan pada skala x. Di bawah realmin tersedia denormal hingga 4.94e-324, di atas realmax muncul Inf, dan operasi tak terdefinisi menghasilkan NaN yang tidak pernah sama dengan dirinya sendiri. Karena setiap operasi membulatkan, galat kecil seperti 0.1 + 0.2 - 0.3 wajar terjadi dan menumpuk pada penjumlahan panjang — selalu bandingkan hasil floating point dengan toleransi, bukan ==.