kodingup.camp

Beranda/JavaScript Mastery: Fundamentals

Konsep Representasi Angka

Modul 5 dari 164 menit bacaNumerical representation concepts

Isi modul

    Kenapa ini penting

    Angka ada di mana-mana dalam program: harga, jumlah stok, koordinat, warna, waktu. Kamu akan sering bertemu tiga sistem bilangan: desimal (yang kita pakai sehari-hari), biner (bahasa asli komputer), dan heksadesimal (cara ringkas menulis biner, misalnya warna CSS #FF5733). Kamu juga perlu tahu bahwa komputer menyimpan angka pecahan dengan cara yang tidak selalu presisi. Kalau tidak tahu, kamu bisa kaget melihat 0.1 + 0.2 menghasilkan 0.30000000000000004, padahal ini bukan bug JavaScript, melainkan sifat cara komputer menyimpan pecahan. Programmer yang membuat aplikasi kasir atau keuangan wajib paham soal ini.

    Konsep inti

    Sistem bilangan dan nilai tempat

    Semua sistem bilangan bekerja dengan nilai tempat. Yang berbeda hanya basis (berapa simbol yang dipakai).

    Sistem Basis Simbol Contoh Awalan di JavaScript
    Desimal 10 0-9 255 (tanpa awalan)
    Biner 2 0-1 11111111 0b
    Oktal 8 0-7 377 0o
    Heksadesimal 16 0-9, A-F FF 0x

    Di desimal, 352 artinya 3×100 + 5×10 + 2×1. Nilai tempatnya kelipatan 10. Di biner kelipatannya 2 (1, 2, 4, 8, ...), dan di heksadesimal kelipatannya 16 (1, 16, 256, ...).

    Di heksadesimal, setelah 9 kita butuh simbol tambahan: A=10, B=11, C=12, D=13, E=14, F=15.

    Konversi desimal ke biner (cara bagi 2)

    Bagi terus dengan 2, catat sisanya, lalu baca sisanya dari bawah ke atas. Contoh untuk 13:

    13 ÷ 2 = 6 sisa 1
     6 ÷ 2 = 3 sisa 0
     3 ÷ 2 = 1 sisa 1
     1 ÷ 2 = 0 sisa 1
    Baca dari bawah: 1101
    

    Cek balik: 1×8 + 1×4 + 0×2 + 1×1 = 13. Benar.

    Konversi biner ↔ heksadesimal

    Ini alasan heksadesimal populer: 1 digit heksa = tepat 4 bit. Jadi 1 byte (8 bit) selalu bisa ditulis dengan 2 digit heksa.

    Biner:  1111 1111   →  F F   →  0xFF  = 255
    Biner:  0010 1010   →  2 A   →  0x2A  = 42
    

    Itulah kenapa warna CSS #FF5733 sebenarnya tiga byte: merah FF (255), hijau 57 (87), biru 33 (51).

    Integer dan floating point

    JavaScript menyimpan hampir semua angka sebagai satu tipe, Number, dengan format IEEE 754 double precision (64 bit). Formatnya mirip notasi ilmiah: ada tanda (+/−), angka penting (mantissa), dan pangkat (exponent). Contohnya 6,02 × 10²³ tapi dalam basis 2.

    Konsekuensinya:

    1. Bilangan bulat aman hanya sampai Number.MAX_SAFE_INTEGER = 9.007.199.254.740.991. Di atas itu, angka bisa tidak akurat. Untuk angka bulat sangat besar, gunakan tipe BigInt (123n).
    2. Pecahan tertentu tidak bisa disimpan persis. Sama seperti 1/3 di desimal menjadi 0,3333... tanpa akhir, angka 0,1 di biner menjadi 0.0001100110011... yang berulang tanpa akhir. Komputer harus memotongnya di 64 bit, sehingga ada selisih super kecil.

    Kasus terkenal: 0.1 + 0.2

    Karena 0,1 dan 0,2 sama-sama tersimpan sedikit meleset, hasil penjumlahannya juga meleset: 0.30000000000000004. Ini terjadi di semua bahasa yang memakai IEEE 754 (Python, Java, C juga sama), bukan hanya JavaScript.

    Cara menanganinya:

    Nilai khusus Number

    Contoh kode

    // Menulis angka dalam berbagai basis
    console.log(0b1101);  // → 13  (biner)
    console.log(0o17);    // → 15  (oktal)
    console.log(0xff);    // → 255 (heksadesimal)
    
    // Desimal → basis lain: toString(basis)
    const n = 255;
    console.log(n.toString(2));   // → 11111111
    console.log(n.toString(16));  // → ff
    console.log(n.toString(16).toUpperCase()); // → FF
    
    // Basis lain → desimal: parseInt(teks, basis)
    console.log(parseInt("1101", 2)); // → 13
    console.log(parseInt("2A", 16));  // → 42
    
    // Membaca warna CSS heksa menjadi RGB
    const warna = "#FF5733";
    const r = parseInt(warna.slice(1, 3), 16);
    const g = parseInt(warna.slice(3, 5), 16);
    const b = parseInt(warna.slice(5, 7), 16);
    console.log(`rgb(${r}, ${g}, ${b})`); // → rgb(255, 87, 51)
    

    Floating point dan cara aman menghadapinya:

    console.log(0.1 + 0.2);            // → 0.30000000000000004
    console.log(0.1 + 0.2 === 0.3);    // → false
    
    // 1) Bulatkan untuk tampilan (hasilnya STRING)
    console.log((0.1 + 0.2).toFixed(2)); // → 0.30
    
    // 2) Bandingkan dengan toleransi
    const hampirSama = (a, b) => Math.abs(a - b) < Number.EPSILON;
    console.log(hampirSama(0.1 + 0.2, 0.3)); // → true
    
    // 3) Uang: hitung dalam satuan terkecil (bilangan bulat)
    const hargaSen = 1990;              // $19,90 disimpan sebagai 1990 sen
    const totalSen = hargaSen * 3;       // 5970
    console.log((totalSen / 100).toFixed(2)); // → 59.70
    
    // Batas bilangan bulat aman
    console.log(Number.MAX_SAFE_INTEGER);       // → 9007199254740991
    console.log(9007199254740992 + 1);          // → 9007199254740992 (tidak akurat!)
    console.log(9007199254740992n + 1n);        // → 9007199254740993n (BigInt akurat)
    
    // Nilai khusus
    console.log(1 / 0);                 // → Infinity
    console.log("abc" * 2);             // → NaN
    console.log(NaN === NaN);           // → false
    console.log(Number.isNaN("abc" * 2)); // → true
    

    Kesalahan umum

    1. Membandingkan pecahan dengan ===. 0.1 + 0.2 === 0.3 bernilai false. Pakai toleransi atau bulatkan dulu.
    2. Lupa bahwa toFixed menghasilkan string. (1.5).toFixed(2) + 1 hasilnya "1.501", bukan 2.5. Ubah balik dengan Number(...) kalau masih mau dihitung.
    3. Menghitung uang dengan pecahan desimal. Simpan dalam satuan terkecil sebagai bilangan bulat untuk menghindari selisih pembulatan yang menumpuk.
    4. Lupa basis di parseInt. Selalu tulis basisnya, misalnya parseInt("08", 10) atau parseInt("ff", 16), supaya maksudmu jelas.
    5. Mengecek NaN dengan === NaN. Selalu false. Gunakan Number.isNaN(x).

    Latihan

    1. Mudah, Ubah angka 10, 64, dan 200 ke biner dan heksadesimal memakai toString.
    2. Sedang, Buat function heksKeRgb("#1E90FF") yang mengembalikan teks "rgb(30, 144, 255)".
    3. Menantang, Hitung total belanja 3 barang seharga $0,10, $0,20, dan $0,30 sehingga hasilnya tampil persis "0.60" dan perbandingannya dengan 0,6 bernilai true. Gunakan teknik satuan terkecil (sen).
    Lihat solusi

    1.

    for (const n of [10, 64, 200]) {
      console.log(n, n.toString(2), n.toString(16));
    }
    // → 10 1010 a
    // → 64 1000000 40
    // → 200 11001000 c8
    

    2.

    function heksKeRgb(heks) {
      const r = parseInt(heks.slice(1, 3), 16);
      const g = parseInt(heks.slice(3, 5), 16);
      const b = parseInt(heks.slice(5, 7), 16);
      return `rgb(${r}, ${g}, ${b})`;
    }
    console.log(heksKeRgb("#1E90FF")); // → rgb(30, 144, 255)
    

    3.

    const hargaSen = [10, 20, 30];      // semua dalam sen, bilangan bulat
    let totalSen = 0;
    for (const h of hargaSen) totalSen += h;
    
    console.log(totalSen);                     // → 60
    console.log((totalSen / 100).toFixed(2));  // → 0.60
    console.log(totalSen === 60);              // → true (bandingkan dalam sen)
    
    // Bandingkan dengan cara naif:
    console.log(0.1 + 0.2 + 0.3);              // → 0.6000000000000001
    

    Ringkasan

    Kuis pemahaman

    Pilih satu jawaban per soal. Penjelasan muncul setelah kamu menjawab.