Representasi Bilangan Desimal di Komputer

Dalam dunia komputer, biasanya kita menggunakan representasi floating point untuk menyimpan bilangan desimal. Namun itu bukan satu-satunya representasi yang ada. Ada beberapa representasi lain yang berupa fixed point, misalnya BCD (binary coded decimal), Chen-Ho, dan DCD (Densely Coded Decimal). Jika diperlukan Anda pun bisa membuat representasi sendiri, sesuai yang Anda mau.

Metode penyimpanan yang ada tersebut dibuat dengan tujuan yang berbeda-beda, misalnya tujuan utama representasi floating point adalah dapat menampung angka dalam range yang besar, tapi dengan presisi yang berkurang/terbatas. Floating point juga biasanya basis 2, sehingga lebih cepat dieksekusi di komputer yang memakai binary logic (perlu dicatat, tidak semua komputer memakai binary logic).

Representasi desimal yang lain bertujuan agar dapat merepresentasikan bilangan secara eksak, namun rangenya terbatas. Variasi representasi dibuat untuk berbagai tujuan, misalnya DCD dibuat agar memori yang diperlukan lebih sedikit.

Floating Point dan Fixed Point

Dalam desimal, kita bisa menyatakan 1234.5 sebagai 1.2345 x (10 3). Jadi ada bagian fraction (1.2345), ada bagian basis (10), dan ada bagian exponent (3). Dalam representasi floating point, ketiga bagian tersebut ada, tapi basis yang dipakai biasanya adalah basis 2. Standar IEEE 754 menyatakan berapa bit untuk bagian fraction, berapa bit untuk bagian exponent.

Perhatikan bahwa kita bisa merepresentasikan sebuah bilangan dengan berbagai cara: 1.234 x 102 sama dengan 12.34 x 10 1. Posisi titik bisa berubah-ubah (floating), dan ini penting untuk bisa merepresentasikan range yang besar. Contohnya perkalian 0.12 × 0.12 = 0.0144 dalam floating point akan dilakukan seperti ini: (1.2 × 10−1) × (1.2 × 10−1) = (1.44 × 10−2).

Representasi desimal lain adalah fixed point. Ada sejumlah bit yang disiapkan untuk bagian sebelum dan sesudah titik desimal (radix point). Misalnya kita hanya punya representasi 2 digit sebelum dan sesudah titik desimal, maka perkalian 0.12 x 0.12 dilakukan seperti ini: 00.12 × 00.12 = 00.01. Range fixed point terbatas sampai jumlah titik di belakang koma yang diharapkan.

Anda pasti sudah tahu bahwa 1/3 tidak bisa dinyatakan dalam bentuk desimal, karena ekspansinya tidak berhenti (0.3333…). Dalam basis 2, hanya bilangan yang bisa dinyatakan dalam a/(2 pangkat b), yang akan memiliki ekspansi yang berhenti. Bilangan seperti 0.1, dan 1/3 tidak bisa direpresentasikan secara tepat dalam floating point berbasis 2, berapapun jumlah bit yang dipakai.

Jika kita menggunakan floating point basis 10, maka 0.1 bisa direpresentasikan dengan tepat. Dalam fixed point, 0.1 dapat dengan mudah direpresentasikan dengan jumlah bit yang sangat sedikit. Kita tetap tidak bisa direpresentasikan 1/3 dalam basis 2 atau 10, kita hanya bisa melakukannya memakai basis 3 atau kelipatannya.

Jumlah presisi digit desimal untuk suatu representasi binary floating point bergantung pada bagian fractionnya. Misalnya dalam representasi single precision (32 bit), IEEE menyatakan jumlah fractionnya 24 bit, jadi presisi desimalnya adalah 24*log(2)/log(10) yang nilainya mendekati 7. Untuk tipe double (64 bit, dengan 53 bit fraction), presisinya dalah 15 digit (hampir 16), untuk tipe quadruple (128 bit, dengan 112 bit fraction), presisinya adalah 34 digit.

Semakin besar jumlah bit untuk fraction, presisinya semakin tinggi.

Jumlah presisi yang diperlukan tergantung aplikasi yang akan kita buat. Misalnya untuk menggambar grafik 3D di layar, Anda perlu banyak komputasi floating point, namun hasil akhir dibatasi oleh resolusi layar. Dalam banyak kasus, penggunakan tipe single precision sudah cukup, bahkan di game lama, penggunaan fixed point sudah cukup. Namun kita juga perlu memperhatikan hardware dalam memilih presisi floating point, jika komputer ternyata memiliki hardware khusus untuk melakukan komputasi floating, dan hardware tersebut lebih cepat dalam memproses double (dan memiliki memori yang cukup), maka memakai double mungkin adalah pilihan yang lebih baik.

Beberapa aplikasi mungkin butuh presisi yang lebih tinggi, tapi biasanya ada batasan untuk masing-masing bidang. Jadi kita hampir tidak pernah membutuhkan ketelitian yang tidak terbatas. Kita bisa melihat hal-hal terkecil di alam ini memiliki presisi terbatas, dalam bidang fisika kuantum misalnya, presisi untuk bisa merepresentasikan konstanta planck dalam SI adalah 34 digit desimal di belakang koma. Menurut wikipedia: The Planck constant is (with one or two exceptions) the fundamental physical constant which is known to the lowest level of precision, with a relative uncertainty ur of 5.0 × 10−8.
Jika kita ingin menghitung waktu sampai batasan fisik yang terkecil, maka hanya perlu bisa merepresentasikan waktu planck yang presisinya 44 digit desimal (butuh 147 bit fraction).

Dalam banyak aplikasi, presisi dibatasi oleh batasan pengukuran, misalnya untuk timbangan yang presisinya hanya 1 kilogram, menampilkan hasil dalam 0,5 kilogram dapat menyesatkan (istilahnya false precision).

Kadang-kadang ada perhitungan lain yang membutuhkan presisi yang lebih besar, misalnya untuk mengakumulasi bilangan yang kecil berulang kali. Jika hal tersebut diperlukan, maka representasi lain bisa dipakai (contohnya representasi BigDecimal di Java yang memakai jumlah bit yang variabel). Namun secara umum dengan jumlah bit fraction yang cukup besar, maka perhitungan yang “eksak” (sesuai batasan presisi yang diinginkan) dapat dilakukan dengan representasi binary floating point.

Memahami floating point dalam program

Sekarang mari kita coba melihat aplikasi pengetahuan kita dalam program. Representasi 0.1 dalam 32 bit single precision jika dikalikan dengan bilangan 1 milyar (10 pangkat 9) akan menghasilkan 100000001.490116, tapi jika kita memakai representasi double, maka hasilnya akan benar (100000000.0). Coba saja sendiri membuat program dalam bahasa C, dengan a adalah float (dengan nilai 0.1), dan b adalah double (dengan nilai 1000000000.0), lalu coba ganti tipe a menjadi double, dan bandingkan hasilnya. Menambah jumlah bit, akan membuat perhitungan menjadi lebih eksak (sampai batas di mana kita peduli/sampai batasan pengukuran yang mungkin).

#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
   float a = 0.1;
   double b = 1000000000;
   printf("result = %f\n", a*b);
   return 0;
}

hasilnya (prosessor AMD 64 bit, compiler GCC):

result = 100000001.490116

Jika kita mengganti float a dengan double a, hasilnya menjadi:result = 100000000.000000
Perhatikan bahwa tipe float hanya memiliki presisi sampai 7 digit (tepatnya sedikit lebih dari 7, dalam kasus ini kebetulan 8 digit pertama benar), sehingga sisanya tidak tepat lagi. Sekarang kasus yang lebih rumit:Apakah output program ini?

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
int main()
{
  float a = 0.1;
  float b = 0.1;
  int i;
  for (i=0; i<9; i++) {
      b += a;
  }
  printf("a=%lf b=%lf a==b? %s\n", a*10.0, b, 
		b==(a*10.0)?"yes":"no");
  return 0;
}
a=1.000000 b=1.000000 a==b? no

Meski output a dan b terlihat sama, tapi representasi internalnya berbeda. Dan apakah output program ini?:

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
int main()
{
  long double a = 0.1;
  long double b = 0.1;
  int i;
  for (i=0; i<9; i++) {
    b += a;
 }
printf("a=%Lf b=%Lf a==b? %s\n", a*10.0L, b, 
		b==(a*10.0L)?"yes":"no");
return 0;
}

outputnya adalah:


a=1.000000 b=1.000000 a==b? yes

Perhitungan yang di luar presisi akan dibulatkan, sesuai dengan mode operasi saat itu (apakah mode pembulatan ke atas, ke bawah, terdekat, atau dipotong). Karena representasi floating point tidak eksak, maka kesalahan akan terus terakumulasi dalam sebuah loop.

Seperti diperlihatkan dalam contoh (0.12 x 0.12), ketika melakukan perkalian posisi radix point bisa digeser, tapi dalam penjumlahan berulang, pergeseran ini tidak langsung dilakukan. Dalam pembuatan aplikasi yang memerlukan presisi tinggi, kita harus memahami masalah ini. Biasanya pelajaran mengenai numerical analysis diberikan dalam kuliah Metode Numerik.

Bacaan lebih lanjut: What Every Computer Scientist Should Know About Floating-Point Arithmetic

Leave a Reply

Your email address will not be published. Required fields are marked *