Di chapter Variables kita sempat menulis hargaCangkir * jumlahCangkir dan hasilnya benar. Namun tagihan nyata jarang selesai dengan satu perkalian: ada item yang dijumlahkan, potongan promo yang dikurangkan, tagihan yang dibagi rata, dan pecahan desimal yang perilakunya tidak selalu sesuai intuisi. JavaScript menyediakan enam operator aritmatika untuk semua kebutuhan itu, dan chapter ini membahasnya satu per satu secara utuh.

Selain enam operator, kita juga menyelidiki tiga temuan lapangan yang sering mengejutkan pemula: pecahan 0.1 + 0.2 yang tidak menghasilkan 0.3 persis, modulo pada bilangan negatif yang tandanya terbalik dari dugaan, dan NaN yang muncul diam-diam dari operasi tidak valid. Semua contoh kita jalankan dengan node, sama seperti chapter-chapter sebelumnya.

Enam Operator Aritmatika #

Operator aritmatika mengambil dua nilai (disebut operand) dan menghasilkan satu nilai baru. Ekspresi 15000 + 8000 dievaluasi menjadi 23000, dan nilai hasil itulah yang bisa disimpan ke variabel atau langsung dicetak. Berikut keenamnya:

OperatorNamaContohHasil
+Penjumlahan15000 + 800023000
-Pengurangan60000 - 530007000
*Perkalian15000 * 345000
/Pembagian62000 / 320666.666666666668
%Modulo (sisa pembagian)62000 % 32
**Pangkat13 ** 2169

Dua baris pada tabel tersebut perlu penekanan. Pertama, / selalu melakukan pembagian biasa: meskipun kedua operand berupa integer, hasilnya boleh pecahan. JavaScript tidak memiliki pembagian bulat otomatis seperti beberapa bahasa lain; 62000 / 3 menghasilkan 20666.666666666668, bukan 20666. Kedua, % bukan tanda persen. Operator % menghitung sisa pembagian: 62000 % 3 bernilai 2 karena 62000 = 3 × 20666 + 2.

Contoh Lengkap: Tagihan Makan Siang #

Berkas berikut menghitung tagihan makan siang Budi bersama dua temannya. Kita sengaja memasukkan keenam operator, presisi pecahan, modulo negatif, dan operasi tidak valid dalam satu berkas agar kelima perilaku di atas terlihat berdampingan:

// operasi-angka.js
// Enam operator aritmatika dalam satu tagihan makan siang.

const hargaMakan = 24000;
const hargaMinum = 12000;

// Perkalian: Budi memesan dua porsi makan.
const totalMakan = hargaMakan * 2;

// Penjumlahan: dua gelas minum ditambahkan ke tagihan.
const subtotal = totalMakan + hargaMinum * 2;

// Pengurangan: potongan promo Rp10.000.
const totalBayar = subtotal - 10000;

console.log("Total bayar:", totalBayar);

// Pembagian: tagihan dibagi rata untuk tiga teman.
const bagianPerOrang = totalBayar / 3;
console.log("Bagian per orang:", bagianPerOrang);

// Modulo: rupiah yang tidak bisa dibagi rata.
console.log("Sisa pembagian:", totalBayar % 3);

// Pangkat: luas ubin bersisi 13 cm.
console.log("Luas ubin:", 13 ** 2);

// Presisi floating point: pecahan desimal tidak selalu eksak.
console.log("Pecahan:", 0.1 + 0.2);

// Modulo pada bilangan negatif: tanda hasil mengikuti nilai pertama.
console.log("Negatif modulo:", -7 % 3);
console.log("Positif modulo:", 7 % -3);

// Operasi yang tidak valid menghasilkan NaN.
console.log("Teks dikali angka:", "dua" * 3);
console.log("Nol dibagi nol:", 0 / 0);

Output yang Dihasilkan:

text
Total bayar: 62000
Bagian per orang: 20666.666666666668
Sisa pembagian: 2
Luas ubin: 169
Pecahan: 0.30000000000000004
Negatif modulo: -1
Positif modulo: 1
Teks dikali angka: NaN
Nol dibagi nol: NaN

Mari kita telaah baris-baris pentingnya:

  1. Baris 4–5 (const hargaMakan = 24000; dst.): dua harga dasar disiapkan. Keduanya tidak berubah selama program berjalan, sehingga const adalah pilihan yang tepat.
  2. Baris 8 (const totalMakan = hargaMakan * 2;): operator * mengalikan 24000 dengan 2, menghasilkan 48000.
  3. Baris 11 (const subtotal = totalMakan + hargaMinum * 2;): di baris ini ada dua operator sekaligus. Engine menghitung hargaMinum * 2 lebih dahulu (perkalian lebih diutamakan daripada penjumlahan), lalu menjumlahkan hasilnya dengan totalMakan, sehingga subtotal bernilai 72000. Aturan urutan ini dibedakan tuntas di chapter Operator Precedence.
  4. Baris 14 (const totalBayar = subtotal - 10000;): potongan promo dikurangkan; totalBayar bernilai 62000.
  5. Baris 19–20 (const bagianPerOrang = totalBayar / 3;): pembagian menghasilkan pecahan 20666.666666666668. Digit 668 di ujung bukan keanehan Node, melainkan bentuk representasi angka pecahan yang paling dekat dengan nilai sebenarnya.
  6. Baris 23 (console.log("Sisa pembagian:", totalBayar % 3);): modulo melengkapi pembagian; sisa 2 berarti dua ribu rupiah tidak bisa dibagi rata untuk tiga orang.
  7. Baris 26 (console.log("Luas ubin:", 13 ** 2);): operator ** menghitung pangkat, 169.
  8. Baris 29 (console.log("Pecahan:", 0.1 + 0.2);): inilah jejak presisi floating point yang kita bedah pada bagian berikutnya.
  9. Baris 32–33 (-7 % 3 dan 7 % -3): dua arah modulo negatif; hasilnya -1 dan 1.
  10. Baris 36–37 ("dua" * 3 dan 0 / 0): dua cara menghasilkan NaN, satu-satunya keluaran di berkas ini yang bukan angka biasa.

Presisi Floating Point #

Angka 0.1 + 0.2 seharusnya 0.3, tetapi engine menghasilkan 0.30000000000000004. Ini bukan bug JavaScript. Semua number non-integer mengikuti standar IEEE-754 (sudah kita kenal di section Values dan Types): nilai disimpan sebagai pecahan biner, dan 0.1 tidak memiliki representasi biner yang eksak — mirip seperti 1/3 tidak bisa ditulis persis dalam desimal. Kelebihan pembulatan yang tersisa itulah yang muncul di keluaran. Sebaliknya, 0.5 + 0.25 menghasilkan 0.75 persis karena kedua nilai memang eksak dalam biner.

Untuk tampilan ke pengguna, pecahan boleh dibulatkan dengan metode toFixed:

js
const hasil = 0.1 + 0.2;
console.log(hasil.toFixed(2));
console.log(0.5 + 0.25);

Output yang Dihasilkan:

text
0.30
0.75

toFixed(2) memformat angka menjadi teks dengan dua angka di belakang koma — perhatikan keluarannya 0.30, bukan 0.3. Metode ini cocok untuk menampilkan harga, tetapi nilainya tetap string; perhitungan lanjutan sebaiknya memakai angka aslinya.

Modulo dan Bilangan Negatif #

Hasil % pada JavaScript mengikuti tanda operand pertama, bukan selalu positif seperti sisa pembagian dalam matematika sekolah:

js
console.log(-7 % 3);
console.log(7 % -3);
console.log(150 % 60);

Output yang Dihasilkan:

text
-1
1
30

-7 % 3 menghasilkan -1 karena -7 = 3 × (-3) + (-1): sisa pembagiannya menempel pada tanda -7. Kegunaan % paling sering adalah menguji kelipatan — nilai % 2 === 0 berarti genap — dan memotong nilai berulang, seperti 150 % 60 yang menyisakan 30 menit setelah dua jam penuh.

NaN: Hasil Operasi yang Tidak Valid #

Operasi aritmatika yang tidak bermakna tidak menghentikan program. Engine justru menghasilkan nilai khusus bernama NaN (Not a Number) — nilai bertipe number yang menandai kegagalan:

js
console.log("dua" * 3);
console.log(0 / 0);
console.log(Number.isNaN(0 / 0));
console.log(Number.isNaN(12));

Output yang Dihasilkan:

text
NaN
NaN
true
false

Teks "dua" tidak bisa dikonversi menjadi angka, dan 0 / 0 tidak terdefinisi; keduanya menghasilkan NaN. Sifatnya menular: operasi apa pun yang menyentuh NaN juga menghasilkan NaN, sehingga satu nilai bocor bisa merusak seluruh rantai perhitungan. Cara baku memeriksanya adalah Number.isNaN() — fungsi ini menghasilkan true hanya untuk NaN, seperti pada baris ketiga dan keempat keluaran di atas. Perilaku aneh lain dari NaN (ia tidak sama dengan dirinya sendiri) kita buktikan di chapter terakhir section ini.

Setelah berhitung, langkah logis berikutnya adalah membandingkan hasilnya — nilai mana yang lebih besar, mana yang mencapai ambang batas. Topik itulah yang kita bahas di chapter Comparison Operators.

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

operasi-angka.js

Unduh berkas
javascript
// operasi-angka.js
// Enam operator aritmatika dalam satu tagihan makan siang.

const hargaMakan = 24000;
const hargaMinum = 12000;

// Perkalian: Budi memesan dua porsi makan.
const totalMakan = hargaMakan * 2;

// Penjumlahan: dua gelas minum ditambahkan ke tagihan.
const subtotal = totalMakan + hargaMinum * 2;

// Pengurangan: potongan promo Rp10.000.
const totalBayar = subtotal - 10000;

console.log("Total bayar:", totalBayar);

// Pembagian: tagihan dibagi rata untuk tiga teman.
const bagianPerOrang = totalBayar / 3;
console.log("Bagian per orang:", bagianPerOrang);

// Modulo: rupiah yang tidak bisa dibagi rata.
console.log("Sisa pembagian:", totalBayar % 3);

// Pangkat: luas ubin bersisi 13 cm.
console.log("Luas ubin:", 13 ** 2);

// Presisi floating point: pecahan desimal tidak selalu eksak.
console.log("Pecahan:", 0.1 + 0.2);

// Modulo pada bilangan negatif: tanda hasil mengikuti nilai pertama.
console.log("Negatif modulo:", -7 % 3);
console.log("Positif modulo:", 7 % -3);

// Operasi yang tidak valid menghasilkan NaN.
console.log("Teks dikali angka:", "dua" * 3);
console.log("Nol dibagi nol:", 0 / 0);