Tipe integer di Chapter sebelumnya tidak bisa menyimpan pecahan seperti 3.14 atau 0.5. Untuk bilangan desimal, C menyediakan tiga tipe floating point: float, double, dan long double. Perbedaan utamanya adalah jumlah byte dan jumlah digit presisi yang bisa dijamin. Pada Chapter ini kita akan memetakan ukuran tiap tipe, cara melakukan konversi dari integer ke floating point, serta kapan memakai masing-masing tipe. Pemilihan tipe yang tepat penting karena tipe float lebih kecil tetapi rentan kehilangan presisi, sementara long double boros memori tetapi akurat untuk komputasi ilmiah.
Tiga Tingkat Presisi #
Standar IEEE 754 mendefinisikan representasi biner untuk bilangan floating point. C mengikuti standar tersebut untuk float (32 bit, presisi tunggal) dan double (64 bit, presisi ganda). long double bersifat implementasi-defined—biasanya 80 bit pada x86_64 GCC atau 128 bit pada platform lain. Makro FLT_DIG, DBL_DIG, dan LDBL_DIG dari header <float.h> menyatakan jumlah digit desimal yang dijamin akurat untuk masing-masing tipe.
#include <stdio.h>
#include <float.h>
int main(void) {
float pi_f = 3.14159f;
double pi_d = 3.141592653589793;
long double pi_ld = 3.14159265358979323846L;
printf("float = %.6f\n", pi_f);
printf("double = %.15f\n", pi_d);
printf("long double = %.18Lf\n", pi_ld);
printf("ukuran float = %zu byte\n", sizeof(float));
printf("ukuran double = %zu byte\n", sizeof(double));
printf("ukuran long double = %zu byte\n", sizeof(long double));
printf("FLT_DIG = %d\n", FLT_DIG);
printf("DBL_DIG = %d\n", DBL_DIG);
printf("LDBL_DIG = %d\n", LDBL_DIG);
return 0;
}Output yang Dihasilkan:
float = 3.141590
double = 3.141592653589793
long double = 3.141592653589793239
ukuran float = 4 byte
ukuran double = 8 byte
ukuran long double = 16 byte
FLT_DIG = 6
DBL_DIG = 15
LDBL_DIG = 18Mari kita telaah baris-baris kode di atas:
- Baris 5 (
float pi_f = 3.14159f;): suffixfmenandakan literal bertipefloat; tanpa suffix, literal desimal selalu bertipedouble. - Baris 6 (
double pi_d = 3.141592653589793;): literal tanpa suffix bertipedouble—15 digit yang ditulis masih bisa direpresentasikan tepat. - Baris 7 (
long double pi_ld = ...L;): suffixLmenandakan literal bertipelong double. - Baris 9-11 (
%.6f,%.15f,%.18Lf): angka di format specifier mengatur jumlah digit setelah titik desimal; specifier untuklong doublememakai%Lf(kapital L). - Baris 13-15 (
sizeof(...)): ukuran aktuallong doubledi GCC x86_64 adalah 16 byte (di-aligned) meskipun presisi efektifnya sekitar 80 bit. - Baris 17-19 (
*_DIG): konstanta darifloat.hyang menyatakan jumlah digit desimal yang dijamin akurat.doublemenjamin 15 digit,floathanya 6.
Konversi dari Integer ke Floating Point #
Saat kita membagi dua int, hasilnya tetap int dan pecahan terbuang. Untuk mendapatkan hasil pecahan, minimal satu operan harus dikonversi ke tipe floating point terlebih dahulu. Konversi bisa dilakukan eksplisit dengan cast (double), atau implisit dengan menulis literal desimal seperti 4.0 atau 2.0. Aturan usual arithmetic conversion di C menyebabkan operan int otomatis dipromosikan ke double jika operan lainnya double.
#include <stdio.h>
int main(void) {
int a = 10;
int b = 4;
/* Pembagian integer: pecahan hilang */
int hasil_int = a / b;
printf("10 / 4 sebagai int = %d\n", hasil_int);
/* Konversi eksplisit (cast) ke double */
double hasil_d = (double)a / (double)b;
printf("10 / 4 sebagai double = %.4f\n", hasil_d);
/* Cukup satu operand double, sisanya dipromosikan otomatis */
double hasil_promo = a / (double)b;
printf("promo 10 / (double)4 = %.4f\n", hasil_promo);
return 0;
}Output yang Dihasilkan:
10 / 4 sebagai int = 2
10 / 4 sebagai double = 2.5000
promo 10 / (double)4 = 2.5000Pada baris 8, ekspresi a / b dihitung dalam aritmetika integer karena kedua operan bertipe int, sehingga 10 / 4 menghasilkan 2 dan pecahan 0.5 terbuang. Pada baris 12, cast (double)a mengubah a menjadi 10.0 sebelum pembagian, sehingga seluruh ekspresi dipromosikan ke double dan menghasilkan 2.5. Pada baris 16, hanya b yang di-cast ke double, tetapi aturan konversi otomatis membuat a ikut dipromosikan—hasilnya sama 2.5.
Literal Floating Point dan Scientific Notation #
Literal floating point bisa ditulis dalam bentuk desimal (3.14) atau scientific notation (1.496e8). Format scientific notation menggunakan huruf e atau E untuk menandakan pangkat 10; 1.496e8 berarti 1.496 × 10^8 = 149.600.000. Notasi ini berguna untuk menulis angka yang sangat besar atau sangat kecil tanpa banyak nol.
#include <stdio.h>
int main(void) {
double harga = 17500.50;
double jumlah = 3;
double total = harga * jumlah;
printf("Harga satuan : Rp%.2f\n", harga);
printf("Jumlah : %.0f\n", jumlah);
printf("Total : Rp%.2f\n", total);
/* Scientific notation */
double jarak_planet = 1.496e8; /* km */
printf("Jarak Bumi-Matahari: %.3e km\n", jarak_planet);
return 0;
}Output yang Dihasilkan:
Harga satuan : Rp17500.50
Jumlah : 3
Total : Rp52501.50
Jarak Bumi-Matahari: 1.496e+08 kmPada baris 11, specifier %.0f mencetak double tanpa angka di belakang koma, sehingga 3.0 ditampilkan sebagai 3. Pada baris 14, literal 1.496e8 diubah compiler menjadi 149600000.0. Pada baris 15, specifier %.3e mencetak angka dalam scientific notation dengan tiga digit setelah titik desimal, menghasilkan 1.496e+08.
Kapan Memakai float vs double #
Sebagai aturan praktis: gunakan double untuk seluruh perhitungan yang melibatkan pecahan, kecuali ada alasan spesifik (memori terbatas pada embedded system, GPU shader, atau network protocol yang spesifik menyatakan float). double hampir selalu sama cepatnya dengan float pada prosesor modern, dan akurasinya jauh lebih tinggi. float biasanya dipakai ketika kita menyimpan array besar yang masif sehingga penghematan 4 byte per elemen menjadi signifikan.
Dengan pemahaman tiga tipe floating point ini, kita siap masuk ke pembahasan modifier signed dan unsigned yang menentukan apakah integer bisa menampung nilai negatif atau tidak.