Menu

Number dan BigInt JavaScript: Float, Presisi, dan Integer Besar

Cara kerja tipe Number JavaScript yang sebenarnya: presisi floating-point, MAX_SAFE_INTEGER, dan kapan sebaiknya beralih ke BigInt.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

Satu Tipe Number untuk Segalanya (Hampir)

Kebanyakan bahasa memberimu tipe terpisah untuk integer dan float. JavaScript, secara historis, hanya memberimu satu: Number. Entah kamu menulis 42, 3.14, atau -0.001, kamu mendapat tipe primitif yang sama, yaitu float double-precision IEEE 754 64-bit.

Itu praktis: tidak perlu konversi antara int dan float, tidak ada overflow di 2^31. Tetapi representasi float punya konsekuensi, dan konsekuensi itu sering menjebak pemula. Tipe numerik kedua, BigInt, ditambahkan pada 2020 untuk menangani kasus-kasus di mana Number tidak memadai.

Kejutan Floating-Point

Jalankan ini:

Baris pertama mencetak 0.30000000000000004. Baris kedua mencetak false. Ini bukan keanehan JavaScript: Python, Java, C, dan bahasa apa pun yang memakai float IEEE 754 berperilaku sama.

Alasannya: 0.1 dan 0.2 tidak bisa direpresentasikan secara tepat dalam biner, sama seperti 1/3 tidak bisa ditulis secara tepat dalam desimal. Yang disimpan adalah pendekatan biner yang paling dekat, dan kesalahan kecil pun menumpuk. Model mentalnya: perlakukan nilai Number yang melibatkan desimal sebagai pendekatan yang kebetulan sangat dekat dengan apa yang kamu tulis.

Untuk uang, jangan simpan $19.99 sebagai 19.99. Simpan sen sebagai integer, yaitu 1999, lalu format saat ditampilkan. Itulah satu kebiasaan terbaik untuk menghindari bug float.

Membandingkan Float dengan Aman

Karena kesamaan tidak bisa diandalkan, bandingkan dengan toleransi saat kamu perlu:

Number.EPSILON adalah selisih terkecil antara 1 dan angka berikutnya yang bisa direpresentasikan, toleransi default yang wajar untuk nilai di sekitar 1. Untuk besaran yang sangat besar atau sangat kecil, kamu butuh toleransi yang menyesuaikan dengan input-nya.

Rentang Integer yang Aman

Integer sampai ukuran tertentu memang tepat dalam float 64-bit. Setelah itu, presisinya mulai hilang sedikit demi sedikit:

2^53 - 1 adalah integer terakhir di mana setiap integer di bawahnya bisa direpresentasikan. Di atasnya, sebagian integer sama sekali tidak ada di tipe Number: nilainya dibulatkan ke tetangga terdekatnya. Itu bug perusakan data diam-diam yang tinggal menunggu waktu kalau kamu mem-parsing ID 64-bit dari database sebagai angka JSON biasa.

Kenalan dengan BigInt

BigInt adalah tipe primitif tersendiri untuk integer dengan presisi tak terbatas. Kamu membuatnya dengan menambahkan n pada literal integer, atau dengan memanggil BigInt(...):

BigInt tidak punya batas atas selain memori yang tersedia. BigInt adalah alat yang tepat untuk:

  • ID database atau snowflake ID Twitter/X yang melebihi 2^53.
  • Perhitungan kriptografi.
  • Aritmetika integer apa pun di mana hasil yang tepat lebih penting daripada kecepatan mentah.

BigInt bukan alat yang tepat untuk counter sehari-hari, index array, atau uang dalam bentuk sen: Number biasa lebih cepat dan bisa bekerja sama dengan setiap API di bahasa ini.

Aritmetika BigInt

Semua operator yang biasa tetap berfungsi, asalkan kedua operand-nya BigInt:

Pembagian dibulatkan ke arah nol: tidak ada BigInt pecahan. Kalau kamu butuh pecahan, kamu kembali ke wilayah Number (atau memakai library desimal).

Jangan Campur Tipe

Aturan yang sering menjebak: kamu tidak bisa mencampur Number dan BigInt dalam ekspresi yang sama.

Perbandingan adalah satu-satunya pengecualian: <, >, == melakukan coercion lintas tipe:

Jadi == menganggap keduanya sama, === tidak. Kalau kamu sudah memakai === di mana-mana (dan memang sebaiknya begitu), anggap perbandingan numerik antara kedua tipe ini sebagai tanda desain yang bermasalah: pilih satu sisi dan lakukan konversi.

Konversi di Antara Keduanya

Dua konversi, dua jebakan:

Konversi Number → BigInt itu ketat: desimal dan NaN memunculkan error. Konversi BigInt → Number lebih longgar tetapi bisa kehilangan data: apa pun di atas MAX_SAFE_INTEGER akan dibulatkan. Kalau kamu mengonversi BigInt yang kamu terima dari server, tanyakan pada dirimu apakah kamu benar-benar perlu melakukannya.

Nilai Number Khusus

Sekalian di sini, ada tiga nilai di tipe Number yang bukan angka dalam arti matematis:

Infinity dan -Infinity muncul saat kamu membagi dengan nol atau melampaui rentang float. NaN ("not a number") muncul saat operasi aritmetika tidak menghasilkan hasil yang bermakna.

NaN terkenal tidak sama dengan dirinya sendiri. Itu bagian dari spesifikasi IEEE 754, bukan bug JS. Pakai Number.isNaN(x) untuk mengeceknya. isNaN global yang lebih lama mengubah argumennya terlebih dulu, sehingga memberi jawaban yang salah (isNaN("hello") mengembalikan true). Selalu utamakan versi Number.isNaN.

Mem-parsing Angka dari String

Input pengguna dan angka JSON sering datang sebagai string. Ada tiga cara untuk mengonversinya:

Number() itu ketat: apa pun yang bukan angka menghasilkan NaN, kecuali string kosong dan spasi, yang menghasilkan 0. parseInt dan parseFloat lebih pemaaf: keduanya membaca sejauh mungkin lalu berhenti. Pilih yang sesuai dengan maksudmu, dan cek NaN sebelum memakai hasilnya.

Untuk mem-parsing BigInt dari string, pakai BigInt("123"): ketat dan memunculkan error untuk input yang buruk.

Buku Aturan Singkat

  • Untuk counter, matematika, koordinat, dan sebagian besar angka sehari-hari: pakai Number.
  • Untuk uang: ubah ke sen dalam bentuk integer dan pakai Number, atau gunakan library desimal.
  • Untuk integer yang lebih besar dari 2^53 (ID database, kripto, kombinatorika): pakai BigInt dengan akhiran n.
  • Bandingkan float dengan toleransi, bukan ===.
  • Cek hasil yang tidak valid dengan Number.isNaN dan Number.isFinite, bukan versi globalnya.
  • Jangan campur Number dan BigInt dalam ekspresi yang sama: lakukan konversi secara eksplisit.

Berikutnya: null vs undefined

JavaScript punya dua cara untuk mengatakan "tidak ada nilai", yaitu null dan undefined, dan keduanya tidak bisa saling menggantikan. Berikutnya: arti masing-masing, perbedaannya, dan kapan memakai yang mana.

Pertanyaan yang sering diajukan

Mengapa 0.1 + 0.2 tidak sama dengan 0.3 di JavaScript?

Karena tipe Number di JavaScript adalah float IEEE 754 64-bit, dan 0.1 serta 0.2 tidak bisa direpresentasikan secara tepat dalam biner. Hasilnya 0.30000000000000004. Ini bukan bug JavaScript: hal yang sama terjadi di Python, Java, dan bahasa lain yang memakai format float yang sama. Untuk uang, ubah ke integer (sen) atau pakai library desimal.

Apa itu BigInt di JavaScript dan kapan sebaiknya memakainya?

BigInt adalah tipe primitif numerik tersendiri untuk integer yang melebihi Number.MAX_SAFE_INTEGER (2^53 - 1). Buat dengan akhiran n, seperti 9007199254740993n, atau dengan BigInt(value). Pakai untuk ID database 64-bit, kriptografi, atau perhitungan integer apa pun di mana presisi lebih penting daripada kecepatan.

Bisakah aku mencampur Number dan BigInt di JavaScript?

Tidak bisa. 1n + 1 memunculkan TypeError: Cannot mix BigInt and other types. Ubah secara eksplisit dengan BigInt(n) atau Number(b). Operator perbandingan seperti < dan == memang berfungsi di antara keduanya, tetapi === mengembalikan false karena tipenya berbeda.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai