Topik ini membahas dua tipe bilangan PHP, yaitu int untuk bilangan bulat dan float untuk bilangan pecahan. Materi yang dibahas meliputi batas nilai dan penulisan literal bilangan bulat, perilaku operator pembagian dan modulo, serta jebakan floating-point yang membuat perbandingan pecahan berakhir tidak sesuai harapan. Setelah topik ini dibaca, pemilihan antara pembagian biasa, intdiv, dan modulo sudah didasarkan pada mekanismenya.
Tipe int#
Tipe int menyimpan bilangan bulat dengan lebar 64 bit pada platform modern, sehingga rentangnya berkisar dari PHP_INT_MIN sampai PHP_INT_MAX. Kedua konstanta itu tersedia langsung dan nilainya tercetak bila diperiksa dengan var_dump. PHP tidak menyediakan tipe bilangan bulat dengan lebar lain, sehingga kebutuhan bilangan lebih besar dari rentang ini diarahkan ke ekstensi khusus seperti BCMath.
Literal bilangan bulat dapat ditulis dalam empat notasi. Notasi desimal ditulis seperti biasa, notasi oktal diawali angka nol, notasi heksadesimal diawali 0x, dan notasi biner diawali 0b. Sejak PHP 7.4, garis bawah boleh disisipkan sebagai pemisah agar angka panjang mudah dibaca.
<?php
var_dump(2026);
var_dump(010);
var_dump(0x1A);
var_dump(0b1010);
var_dump(1_000_000);int(2026)
int(8)
int(26)
int(10)
int(1000000)Baris kedua memperlihatkan jebakan notasi oktal. Nilai 010 terbaca sebagai delapan, bukan sepuluh, karena angka nol di depan mengubah notasinya. Kebiasaan menambahkan nol di depan untuk merapikan tampilan dapat mengubah nilai tanpa terlihat, sehingga nol di depan hanya ditulis ketika notasi oktal memang diinginkan.
Batas atas tipe int juga menentukan perilaku penjumlahan. Ketika hasil operasi melewati PHP_INT_MAX, PHP mengonversi hasilnya menjadi float tanpa peringatan apa pun.
<?php
echo PHP_INT_MAX . PHP_EOL;
var_dump(PHP_INT_MAX + 1);9223372036854775807
float(9.223372036854776E+18)Tipe float#
Tipe float menyimpan bilangan pecahan dengan presisi ganda (double precision) sesuai standar IEEE 754. Literalnya ditulis dengan tanda titik desimal, notasi ilmiah dengan huruf e, atau keduanya. Nilai 1.5e3 berarti satu koma lima dikalikan sepuluh pangkat tiga.
<?php
var_dump(2.5);
var_dump(7.0);
var_dump(1.5e3);float(2.5)
float(7)
float(1500)Dua hal penting terlihat pada keluaran di atas. Bilangan bulat yang ditulis dengan titik desimal tetap bertipe float meskipun nilainya bulat, karena PHP membedakan tipe berdasarkan penulisannya. Sebaliknya, var_dump menampilkan nilai float yang bernilai bulat tanpa angka di belakang titik. Selain itu, tipe float menyediakan nilai khusus INF untuk tak hingga dan NAN untuk hasil aritmetika yang tidak terdefinisi, misalnya akar kuadrat dari bilangan negatif.
Presisi ganda menyimpan bilangan pecahan sebagai perkiraan biner, bukan desimal. Sifat inilah yang menjadi akar seluruh jebakan yang dibahas pada bagian berikutnya, sehingga pecahan sebaiknya selalu diperlakukan sebagai perkiraan.
Pembagian, modulo, dan intdiv#
Operator pembagian / mengembalikan float kecuali kedua operannya bilangan bulat yang habis dibagi. Ketika pembagian tidak habis, hasilnya tetap float tanpa pembulatan apa pun, sedangkan pemotongan ke arah nol tersedia melalui fungsi intdiv. Operator modulo % mengembalikan sisa pembagian bilangan bulat, dan tandanya mengikuti bilangan yang dibagi.
<?php
var_dump(10 / 3);
var_dump(10 / 2);
var_dump(intdiv(10, 3));
var_dump(10 % 3);
var_dump(-7 % 3);
try {
intdiv(10, 0);
} catch (DivisionByZeroError $e) {
echo $e->getMessage() . PHP_EOL;
}float(3.3333333333333335)
int(5)
int(3)
int(1)
int(-1)
Division by zeroKeluaran di atas merangkum empat perilaku. Pembagian 10 / 3 menghasilkan float karena tidak habis, sedangkan 10 / 2 menghasilkan int karena habis dibagi. Fungsi intdiv memotong hasil ke arah nol, sehingga intdiv(-7, 2) menghasilkan -3 dan bukan -4. Pembagian dengan nol tidak menghasilkan nilai khusus, melainkan melempar DivisionByZeroError yang bisa ditangkap.
Operator modulo paling sering digunakan untuk memeriksa keterbagian, misalnya $nomor % 2 === 0 untuk menguji apakah sebuah bilangan genap. Karena tandanya mengikuti bilangan yang dibagi, -7 % 3 menghasilkan -1, sehingga perbandingan hasil modulo terhadap bilangan positif perlu memperhatikan tanda operan pertama.
Jebakan floating-point#
Bilangan pecahan desimal seperti 0.1 tidak dapat dinyatakan tepat dalam biner dengan jumlah bit terbatas, sehingga tersimpan sebagai perkiraan terdekat. Selama perhitungan berlanjut, selisih kecil ini menumpuk dan akhirnya terlihat pada perbandingan.
<?php
printf("%.17f\n", 0.1 + 0.2);
var_dump(0.1 + 0.2 == 0.3);
$selisih = abs(0.1 + 0.2 - 0.3);
var_dump($selisih < PHP_FLOAT_EPSILON);0.30000000000000004
bool(false)
bool(true)Baris pertama membuktikan bahwa 0.1 + 0.2 tersimpan sebagai 0.30000000000000004, sedangkan baris kedua menunjukkan perbandingan == terhadap 0.3 bernilai false. Baris ketiga memperlihatkan pola perbandingan yang benar, yaitu menghitung selisih absolut dan membandingkannya dengan PHP_FLOAT_EPSILON, yaitu selisih terkecil yang masih dapat dibedakan pada presisi ganda. Pola semacam ini disebut perbandingan dengan toleransi, dan toleransinya dapat diperbesar sesuai kebutuhan aplikasi.
Kesalahan umum#
Tiga kesalahan berikut paling sering muncul saat bekerja dengan bilangan.
- Membandingkan hasil perhitungan pecahan dengan
==atau===. Perbandingan bernilai false meskipun secara matematis hasilnya sama. Perbaikannya adalah membandingkan selisih absolut dengan toleransi sebagaimana contoh pada bagian sebelumnya. - Mengharapkan operator
/menghasilkan bilangan bulat. Hasilnya bertipefloatpada pembagian yang tidak habis, dan pemotongan hanya terjadi padaintdiv. Perbaikannya adalah memilihintdivbila hasil yang diinginkan berupa bilangan bulat yang dipotong ke arah nol. - Menambahkan angka nol di depan literal dengan asumsi nilai tetap sama. Notasi tersebut berubah menjadi oktal, sehingga
010bernilai 8. Perbaikannya adalah menuliskan literal desimal tanpa nol di depan.
Ringkasan#
- Tipe
intberlebar 64 bit dengan batasPHP_INT_MAXdanPHP_INT_MIN, dan hasil operasi yang melewati batas berubah menjadifloattanpa peringatan. - Literal dengan nol di depan dibaca sebagai oktal, sedangkan notasi
0xdan0bmasing-masing menyatakan heksadesimal dan biner. - Operator
/menghasilkanfloatpada pembagian yang tidak habis,intdivmemotong hasil ke arah nol, modulo mengikuti tanda operan pertama, dan pembagian dengan nol melemparDivisionByZeroError. - Bilangan pecahan tersimpan sebagai perkiraan biner, sehingga perbandingannya dilakukan dengan toleransi melalui
PHP_FLOAT_EPSILON, dan nilai uang tidak disimpan sebagai float.
Referensi#
- Integers — PHP Manual — Batas nilai, notasi literal, dan perilaku luapan tipe int.
- Floating point numbers — PHP Manual — Presisi float beserta peringatan resmi tentang perbandingan dan representasi desimal.
- intdiv — PHP Manual — Dokumentasi pembagian bilangan bulat dengan pemotongan ke arah nol.
- Arithmetic Operators — PHP Manual
— Tabel perilaku operator
/dan%beserta penanganan pembagian nol. - BCMath — PHP Manual — Ekstensi aritmetika desimal presisi bebas untuk kebutuhan perhitungan uang.