Mengapa komputer tidak menyimpan angka desimal sebagai angka bulat kedua?

24

Komputer memiliki masalah dalam menyimpan bilangan pecahan di mana penyebutnya adalah sesuatu selain solusi untuk 2 ^ x. Ini karena digit pertama setelah desimal bernilai 1/2, 1/4 kedua (atau 1 / (2 ^ 1) dan 1 / (2 ^ 2)) dll.

Mengapa berurusan dengan segala macam kesalahan pembulatan ketika komputer bisa saja menyimpan bagian desimal dari angka tersebut sebagai bilangan bulat lainnya (yang karenanya akurat?)

Satu-satunya hal yang dapat saya pikirkan adalah berurusan dengan desimal berulang (dalam basis 10), tetapi mungkin ada solusi tepi untuk itu (seperti yang kita miliki sekarang dengan infinity).

Anak kucing
sumber
8
Anda harus melihat bagaimana tipe desimal disimpan, berbeda dengan tipe float / double.
Oded
9
Tidak tahu bagaimana itu lebih akurat. Digit pertama setelah desimal adalah 1/10 yang kedua 1/100 dll. Bagaimana itu lebih akurat Anda masih mendapatkan masalah pembulatan (bagaimana Anda mewakili 1/3)? Satu-satunya perbedaan adalah nilai mana yang dapat direpresentasikan secara tepat.
Martin York
17
Titik mengambang desimal (yang Anda maksudkan dua, hanya dalam representasi yang lebih canggung) tidak lebih tidak akurat daripada titik mengambang biner. Satu-satunya perbedaan adalah nilai mana yang tidak dapat direpresentasikan, dan karena kita terbiasa dengan sistem desimal, kita tidak melihat kesalahan dari versi desimal. Dan tidak, tidak ada yang bisa mewakili semua angka rasional dan irasional.
1
Pada akhirnya, itu bermuara pada efisiensi. Komputer adalah biner dan sirkuit untuk bekerja dengan representasi biner ini jauh lebih kompleks. Pentingnya hal ini mungkin agak berkurang hari ini, tetapi itu adalah masa ketika ini sangat signifikan. Juga setiap representasi yang Anda pilih untuk menyimpan nomor Anda (dalam ruang terbatas) di komputer akan memiliki serangkaian nilai terbatas yang dapat diwakilinya dan semuanya akan menunjukkan kesalahan pembulatan dengan beberapa input. Format floating point khas dengan Mantissa dan Exponent menawarkan rentang yang jauh lebih besar maka akan mungkin menggunakan dua bilangan bulat.
Mr.Mindor
1
Saya akan sangat merekomendasikan membaca beberapa artikel yang dirujuk dalam jawaban saya untuk pertanyaan Apa yang menyebabkan kesalahan pembulatan floating point? yang baru saja saya perbarui dengan rincian artikel terakhir dalam seri referensi. Secara khusus, lihat Mengapa Fixed Point Tidak Akan Menyembuhkan Blues Floating Point Anda .
Mark Booth

Jawaban:

35

Sebenarnya ada mode angka yang melakukan itu.

Aritmatika kode biner desimal (BCD) memiliki kerja komputer di basis 10. Alasan Anda jarang menggunakan ini adalah karena ia menghabiskan ruang: setiap digit angka membutuhkan minimal empat bit, sedangkan komputer dapat menyimpan hingga 16 nilai dalam ruang itu. (Ini juga bisa lebih lambat, tetapi dimungkinkan untuk memiliki BCD matematika yang dipercepat perangkat keras yang berfungsi dengan baik.). Faktanya, inilah yang dilakukan sebagian besar kalkulator, itulah sebabnya ada beberapa kelas masalah pembulatan tertentu yang tidak akan pernah Anda dapatkan dengan Casio $ 5 yang akan memakan makan siang Anda di komputer desktop.

Rute lain yang dapat Anda ambil adalah dengan menggunakan angka rasional - yaitu, pembilang dan penyebut, disimpan sebagai bilangan bulat. Ini sebenarnya tersedia di hampir semua bahasa, tepat, dan memungkinkan Anda untuk menyimpan semuanya dalam format biner asli. Masalahnya adalah, pada akhirnya, pengguna mungkin tidak ingin melihat pecahan seperti 463/13, atau bahkan 35 dan 8/13. Mereka ingin melihat 35.615 ..., dan saat Anda sampai di sana, Anda menghadapi semua masalah yang khas. Tambahkan bahwa format ini membutuhkan lebih banyak ruang, dan dapat secara signifikan lebih lambat daripada aritmatika floating point, dan Anda tidak akan menemukan komputer yang menggunakan format ini secara default.

Jadi: komputer dapat melakukan apa yang Anda inginkan, tetapi lambat dan itu membuang-buang ruang, jadi mereka hanya melakukannya ketika mereka benar-benar harus. Sisa waktu, penghematan ruang dan kecepatan floating point lebih baik.

Benjamin Pollack
sumber
Bukankah maksud Anda empat bit (bukan byte) dalam paragraf BCD?
3
Pilihan lainnya adalah aritmatika titik tetap, di mana bilangan bulat mewakili fraksi desimal jika angka - misalnya, Menyimpan nilai uang (tanpa perhitungan yang melibatkan desimal atau persentase) di mana 1 mewakili $ 0,01.
mattnz
1
@ mattnz: Benar — titik tetap adalah kasus khusus rasional.
Jon Purdy
Luar biasa, tidak tahu kalkulator melakukannya.
SomeKittens
3
Ada opsi ketiga. Floating point dengan eksponen desimal, seperti bagaimana C # decimaldiimplementasikan: stackoverflow.com/a/5019178/174335 Ini bukan BCD karena tidak ada representasi individu dari angka desimal, dan itu bukan titik tetap.
Joren
38

Ada banyak cara untuk menyimpan bilangan pecahan, dan masing-masing memiliki kelebihan dan kekurangan.

Sejauh ini, Floating-point adalah format yang paling populer. Ia bekerja dengan mengkodekan tanda, mantissa, dan basis-2 eksponen yang ditandatangani ke dalam bilangan bulat, dan mengemasnya menjadi banyak bit. Misalnya, Anda bisa memiliki mantissa 32-bit dari 0.5(dikodekan sebagai 0x88888888) dan eksponen ditandatangani 32-bit dari +3( 0x00000003), yang akan diterjemahkan ke 4.0(0.5 * 2 ^ 3). Angka floating-point cepat, karena diimplementasikan dalam perangkat keras, dan skala ketepatannya dengan ukuran absolut, yaitu, semakin kecil angkanya, semakin baik presisi absolut Anda, sehingga kesalahan pembulatan relatif tetap konstan dengan ukuran absolut. Mengapung sangat bagus untuk nilai sampel dari domain kontinu, seperti panjang, tingkat tekanan suara, tingkat cahaya, dll. Dan karena itu, mereka biasanya digunakan dalam pemrosesan audio dan gambar, serta analisis statistik dan simulasi fisika. Kelemahan terbesar mereka adalah bahwa mereka tidak tepat, yaitu, mereka rentan terhadap kesalahan pembulatan, dan mereka tidak dapat secara akurat mewakili semua pecahan desimal. Semua bahasa pemrograman arus utama memiliki semacam float point.

Titik pastibekerja dengan menggunakan bilangan bulat yang cukup besar dan secara implisit memesan bagian dari bit mereka untuk bagian fraksional. Misalnya, angka tetap-titik 24,8 bit cadangan 24 bit untuk bagian integer (termasuk tanda), dan 8 bit untuk bagian fraksional. Menggeser kanan angka tersebut dengan 8 bit memberi kita bagian integer. Nomor fixed-point dulu populer ketika unit floating-point perangkat keras tidak umum atau setidaknya jauh lebih lambat daripada rekan-rekan integer mereka. Sementara angka titik tetap agak lebih mudah untuk ditangani dalam hal ketepatan (jika hanya karena mereka lebih mudah untuk dipikirkan), mereka lebih rendah daripada mengapung di hampir semua hal lainnya - mereka memiliki presisi kurang, jangkauan yang lebih kecil, dan karena tambahan operasi diperlukan untuk memperbaiki perhitungan untuk pergeseran implisit, matematika fixed-point saat ini sering lebih lambat daripada matematika floating-point.

Tipe desimal bekerja seperti float atau angka titik tetap, tetapi mereka menganggap sistem desimal, yaitu eksponen mereka (tersirat atau eksplisit) mengkodekan kekuatan-of-10, bukan kekuatan-of-2. Bilangan desimal dapat, misalnya, menyandikan mantissa 23456dan eksponen -2, dan ini akan meluas ke234.56. Desimal, karena aritmatika tidak terprogram ke dalam CPU, lebih lambat daripada float, tetapi mereka ideal untuk apa pun yang melibatkan angka desimal dan membutuhkan angka-angka itu dengan tepat, dengan pembulatan terjadi di tempat-tempat yang ditentukan dengan baik - perhitungan keuangan, scoreboards, dll. Beberapa bahasa pemrograman memiliki tipe desimal yang dibangun di dalamnya (misalnya C #), yang lain membutuhkan perpustakaan untuk mengimplementasikannya. Perhatikan bahwa sementara desimal dapat secara akurat mewakili pecahan desimal yang tidak berulang, ketepatannya tidak lebih baik daripada bilangan floating-point; memilih desimal hanya berarti Anda mendapatkan representasi angka yang tepat yang dapat direpresentasikan dengan tepat dalam sistem desimal (seperti float dapat mewakili fraksi biner).

Bilangan rasional menyimpan pembilang dan penyebut, biasanya menggunakan beberapa jenis tipe bignum integer (tipe numerik yang dapat tumbuh sebesar yang diizinkan oleh batasan memori komputer). Ini adalah satu-satunya tipe data dari kumpulan yang dapat secara akurat memodelkan angka seperti 1/3atau 3/17, serta operasi pada mereka - rasional, tidak seperti tipe data lainnya, akan menghasilkan hasil yang benar untuk hal-hal seperti3 * 1/3. Perhitungannya cukup mudah, meskipun menghasilkan algoritma anjak piutang yang efisien agak sulit. Beberapa bahasa pemrograman memiliki tipe rasional yang dibangun di dalamnya (misalnya Common Lisp). Kelemahan dari rasional termasuk bahwa mereka lambat (banyak operasi membutuhkan pengurangan fraksi dan memfaktorkan komponen mereka), dan bahwa banyak operasi umum sulit atau tidak mungkin untuk dilaksanakan, dan sebagian besar implementasi akan menurunkan rasional ke float ketika ini terjadi (misalnya ketika Anda menelepon sin()secara rasional).

BCD (Binary Coded Decimal) menggunakan "nibbles" (kelompok 4 bit) untuk mengkodekan masing-masing digit; karena nibble dapat menampung 16 nilai yang berbeda, tetapi angka desimal hanya membutuhkan 10, ada 6 nilai "ilegal" per nibble. Seperti desimal, angka BCD adalah tepat desimal, yaitu, perhitungan yang dilakukan pada angka desimal bekerja seperti yang akan mereka lakukan jika Anda melakukannya dengan menggunakan pena dan kertas. Aturan aritmatika untuk BCD agak kikuk, tetapi sisi baiknya adalah mengubahnya menjadi string lebih mudah daripada dengan beberapa format lain, yang sangat menarik untuk lingkungan sumber daya rendah seperti sistem embedded.

String , ya, string lama polos, juga dapat digunakan untuk mewakili angka fraksional. Secara teknis, ini sangat mirip dengan BCD, hanya saja ada titik desimal eksplisit, dan Anda menggunakan satu byte penuh per digit desimal. Karena itu, formatnya boros (hanya 11 dari 256 nilai yang mungkin digunakan), tetapi lebih mudah untuk menguraikan dan menghasilkan daripada BCD. Selain itu, karena semua nilai yang digunakan adalah angka "tidak mencurigakan", tidak berbahaya, dan platform-netral, string-encoded dapat melakukan perjalanan melalui jaringan tanpa masalah. Jarang menemukan aritmatika dilakukan pada string secara langsung, tetapi itu mungkin, dan ketika Anda melakukannya, mereka hanya sama persis dengan desimal seperti format desimal lainnya (desimal dan BCD).

tammmer
sumber
Tentunya titik tetap 32-bit memiliki presisi lebih dari titik mengambang 32-bit, karena representasi titik tetap tidak termasuk mantissa.
Han
4
@han: Tergantung pada ukuran nomor yang ingin Anda simpan. Mengapung akan (secara kasar) memberi Anda presisi yang sama tidak peduli seberapa besar atau kecil angka sementara titik tetap hanya akan memberi Anda presisi penuh jika angka yang ingin Anda simpan cocok dengan sempurna ke dalam kisarannya.
Leo
@han Tidak harus, keduanya masih bisa mewakili 2 ^ 32 nilai yang berbeda. Jumlah informasi yang dibawa adalah identik, terlepas dari presentasi. Rentang dan presisi berjalan beriringan, sehingga dalam hal itu aritmatika titik tetap bisa lebih akurat dalam rentang tertentu. Dan hindari masalah pembulatan acak yang tidak menyenangkan, jika Anda tahu batas di mana Anda dapat bekerja dengannya.
zxcdw
@han: mereka memiliki presisi yang sama (atau hampir). Perbedaannya adalah bahwa untuk bilangan titik tetap, presisi (seperti dalam ukuran langkah terpisah dari satu angka ke penggantinya) adalah konstan, sama seperti dengan bilangan bulat, sedangkan dengan pelampung, ia tumbuh kira-kira linear dengan nilai absolut - pelampung angka 1.0 lebih presisi daripada angka 10.000.000,0 (satu juta kali lebih banyak, kira-kira).
tdammers
6

Angka floating point mewakili sejumlah besar nilai, yang sangat berguna ketika Anda tidak tahu sebelumnya apa nilai-nilai itu, tetapi itu kompromi. Mewakili 1/10 ^ 100 dengan integer kedua tidak akan berfungsi.

Beberapa bahasa (dan beberapa perpustakaan) memiliki karakteristik lain. Lisp secara tradisional memiliki bilangan bulat presisi tanpa batas. Cobol memiliki perhitungan dengan angka desimal titik tetap.

Anda harus memilih representasi nomor Anda yang sesuai dengan domain masalah.

ddyer
sumber
1

Sepertinya Anda menggambarkan angka titik tetap .

Ingatlah bahwa menyimpan bagian fraksional dari angka di lokasi yang terpisah persis identik dengan menciptakan ruang tunggal, dua kali lebih panjang, dan menyimpan seluruh bagian fraksional dalam dua bagian yang terpisah. Dengan kata lain, ini identik dengan menyimpan angka sebagai bilangan bulat tetapi hanya mengasumsikan jumlah ruang desimal tetap.

Biasanya angka floating-point disimpan menggunakan variasi biner pada notasi ilmiah karena yang biasanya penting adalah angka signifikan. Banyak metode lain ada. Angka desimal titik tetap biasanya digunakan misalnya untuk menyimpan nilai mata uang, di mana akurasi sangat penting hingga sejumlah tempat desimal tertentu tetapi jumlah angka desimal yang diperlukan tidak pernah berubah.

tylerl
sumber
1

Itu akan disebut BCD, saya pikir Anda masih bisa menggunakannya jika Anda benar-benar ingin. Namun itu tidak benar-benar layak sebagai:

  1. Anda akan sangat jarang mengalami kesalahan pembulatan dengan floating point 64 bit
  2. Itu membuat aritmatika kompleks dan tidak efisien
  3. Itu membuang 6 nilai setiap 4 bit
Llama terbalik
sumber
BCD matematika banyak digunakan pada sistem mikroprosesor 8-bit awal; memang, pada satu mikroprosesor populer (6502), penambahan dan pengurangan dengan BCD sama cepatnya dengan byte seperti halnya dengan biner. Video game sering menggunakan matematika BCD untuk menjaga skor. Tidak ada penanganan khusus untuk pembungkusan skor pada 1.000.000 poin. Sebaliknya, menambahkan 1 hingga "99 99 99" menghasilkan "00 00 00" dengan carry yang diabaikan. Overhead tambahan untuk menambahkan skor pada BCD sangat kecil dibandingkan dengan biaya konversi nilai biner ke format yang dapat ditampilkan.
supercat
1

Jawaban singkatnya adalah floating point dirancang untuk perhitungan ilmiah. Ia dapat menyimpan angka dengan (hingga) sejumlah digit signifikan, yang cocok dengan bagaimana presisi diukur dalam sebagian besar perhitungan ilmiah.

Itu cenderung didukung dalam perangkat keras terutama karena perhitungan ilmiah cenderung menjadi orang yang paling diuntungkan dari dukungan perangkat keras. Sebagai contoh, perhitungan keuangan sering dilakukan dengan format lain - tetapi perangkat lunak keuangan biasanya melakukan sedikit perhitungan nyata sehingga walaupun format yang diperlukan hanya didukung dalam perangkat lunak, kinerja tetap sangat memadai untuk sebagian besar perangkat lunak keuangan.

Jerry Coffin
sumber