Apa yang bisa dilakukan untuk bahasa pemrograman untuk menghindari jebakan floating point?

28

Kesalahpahaman aritmatika titik apung dan kedatangan singkatnya adalah penyebab utama kejutan dan kebingungan dalam pemrograman (pertimbangkan jumlah pertanyaan pada Stack Overflow yang berkaitan dengan "angka tidak ditambahkan dengan benar"). Mengingat banyak programmer belum memahami implikasinya, ia memiliki potensi untuk memperkenalkan banyak bug halus (terutama ke dalam perangkat lunak keuangan). Apa yang bisa bahasa pemrograman lakukan untuk menghindari perangkap bagi mereka yang tidak terbiasa dengan konsep, sementara masih menawarkan kecepatan ketika akurasi tidak penting bagi mereka yang melakukan memahami konsep?

Adam Paynter
sumber
26
Satu-satunya hal yang dapat dilakukan oleh bahasa pemrograman untuk menghindari perangkap pemrosesan floating-point adalah melarangnya. Perhatikan bahwa ini termasuk base-10 floating-point juga, yang sama tidak akuratnya secara umum, kecuali bahwa aplikasi keuangan sudah disesuaikan sebelumnya.
David Thornley
4
Untuk itulah "Analisis Numerik" diperuntukkan. Pelajari cara meminimalkan kehilangan presisi - alias perangkap titik apung.
Sebuah contoh yang bagus dari masalah floating point: stackoverflow.com/questions/10303762/0-0-0-0-0
Austin Henley

Jawaban:

47

Anda mengatakan "terutama untuk perangkat lunak keuangan", yang memunculkan salah satu kencing kesayangan saya: uang bukan pelampung, ini int .

Tentu, itu terlihat seperti pelampung. Ia memiliki titik desimal di sana. Tapi itu hanya karena Anda terbiasa dengan unit yang membingungkan masalah. Uang selalu datang dalam jumlah bilangan bulat. Di Amerika, itu sen. (Dalam konteks tertentu saya pikir ini bisa jadi pabrik , tapi abaikan saja untuk saat ini.)

Jadi ketika Anda mengatakan $ 1,23, itu benar-benar 123 sen. Selalu, selalu, selalu lakukan perhitungan Anda dengan istilah itu, dan Anda akan baik-baik saja. Untuk informasi lebih lanjut, lihat:

Menjawab pertanyaan secara langsung, bahasa pemrograman seharusnya hanya memasukkan jenis Uang sebagai primitif yang masuk akal.

memperbarui

Ok, saya seharusnya hanya mengatakan "selalu" dua kali, bukan tiga kali. Uang memang selalu int; mereka yang berpikir sebaliknya dipersilakan untuk mencoba mengirim saya 0,3 sen dan menunjukkan kepada saya hasilnya pada laporan bank Anda. Tetapi seperti yang ditunjukkan komentator, ada pengecualian langka ketika Anda perlu melakukan matematika floating point pada angka seperti uang. Misalnya, jenis harga tertentu atau perhitungan bunga. Bahkan kemudian, itu harus diperlakukan seperti pengecualian. Uang masuk dan keluar sebagai jumlah bilangan bulat, sehingga semakin dekat sistem Anda dengan itu, semakin waras itu.

William Pietri
sumber
20
@ JoelFan: Anda salah mengira konsep untuk implementasi platform spesifik.
whatsisname
12
Tidak sesederhana itu. Perhitungan bunga, antara lain, menghasilkan sen pecahan, dan harus dibulatkan pada titik tertentu sesuai dengan metode yang ditentukan.
kevin cline
24
Fiksi -1, karena saya tidak memiliki perwakilan untuk downvote :) ... Ini mungkin benar untuk apa pun yang ada di dompet Anda, tetapi ada banyak situasi akuntansi di mana Anda bisa berurusan dengan sepersepuluh sen, atau fraksi yang lebih kecil. Decimaladalah satu-satunya sistem yang waras untuk menangani hal ini, dan komentar Anda "abaikan itu untuk saat ini" adalah pertanda malapetaka bagi para programmer di mana pun: P
detly
9
@kevin cline: Ada sen pecahan dalam perhitungan, tetapi ada konvensi tentang cara menanganinya. Tujuan perhitungan finansial bukanlah kebenaran matematis, tetapi mendapatkan hasil yang sama persis dengan yang akan dilakukan oleh seorang bankir dengan kalkulator.
David Thornley
6
Semuanya akan sempurna dengan mengganti kata "integer" dengan "rasional" -
Emilio Garavaglia
15

Memberikan dukungan untuk tipe Desimal membantu dalam banyak kasus. Banyak bahasa memiliki tipe desimal, tetapi mereka kurang dimanfaatkan.

Memahami perkiraan yang terjadi ketika bekerja dengan representasi bilangan real adalah penting. Menggunakan tipe desimal dan floating point 9 * (1/9) != 1adalah pernyataan yang benar. Ketika konstanta pengoptimal dapat mengoptimalkan perhitungan sehingga itu benar.

Memberikan operator perkiraan akan membantu. Namun, perbandingan seperti itu bermasalah. Perhatikan bahwa 0,9999 triliun dolar kira-kira sama dengan 1 triliun dolar. Bisakah Anda menyimpan perbedaan di rekening bank saya?

BillThor
sumber
2
0.9999... triliun dolar sebenarnya sama dengan 1 triliun dolar sebenarnya.
HANYA SAYA PENDAPAT benar
5
@ HANYA: Ya tapi saya belum menemukan komputer dengan register yang akan menampung 0.99999.... Mereka semua terpotong di beberapa titik yang menghasilkan ketimpangan. 0.9999cukup setara untuk teknik. Untuk tujuan finansial bukan.
BillThor
2
Tetapi sistem seperti apa yang menggunakan triliunan dolar sebagai unit dasar alih-alih dolar?
Brad
@Brad Coba hitung (1 Triliun / 3) * 3 pada kalkulator Anda. Nilai apa yang Anda dapatkan?
BillThor
8

Kami diberitahu apa yang harus dilakukan pada kuliah tahun pertama (tingkat dua) dalam ilmu komputer ketika saya pergi ke universitas, (kursus ini merupakan prasyarat untuk sebagian besar kursus sains juga)

Saya ingat dosen itu berkata, "Angka titik apung adalah perkiraan. Gunakan tipe integer untuk uang. Gunakan FORTRAN atau bahasa lain dengan nomor BCD untuk perhitungan yang akurat." (dan kemudian dia menunjukkan perkiraannya, menggunakan contoh klasik 0,2 yang tidak mungkin untuk mewakili secara akurat dalam floating point biner). Ini juga muncul minggu itu di latihan laboratorium.

Kuliah yang sama: "Jika Anda harus mendapatkan akurasi lebih dari titik mengambang, urutkan istilah Anda. Tambahkan angka kecil bersama-sama, bukan ke angka besar." Itu melekat di pikiran saya.

Beberapa tahun yang lalu saya memiliki beberapa geometri bola yang perlu sangat akurat, dan masih cepat. 80 bit ganda pada PC tidak memotongnya, jadi saya menambahkan beberapa jenis ke program yang mengurutkan istilah sebelum melakukan operasi komutatif. Masalah terpecahkan.

Sebelum Anda mengeluh tentang kualitas gitar, belajarlah bermain.

Saya memiliki rekan kerja empat tahun lalu yang pernah bekerja untuk JPL. Dia menyatakan tidak percaya bahwa kami menggunakan FORTRAN untuk beberapa hal. (Kami membutuhkan simulasi numerik super akurat yang dihitung secara offline.) "Kami mengganti semua FORTRAN itu dengan C ++," katanya bangga. Saya berhenti bertanya-tanya mengapa mereka merindukan sebuah planet.

Tim Williscroft
sumber
2
Memberi +1 pada alat yang tepat untuk pekerjaan yang tepat. Meskipun saya tidak benar-benar menggunakan FORTRAN. Untungnya saya juga tidak bekerja pada sistem keuangan kita di tempat kerja.
James Khoury
"Jika kamu harus mendapatkan akurasi lebih dari titik mengambang, urutkan persyaratanmu. Tambahkan angka kecil bersama-sama, bukan ke angka besar." Adakah sampel untuk ini?
mamcx
@ mamcx Bayangkan angka floating point desimal hanya memiliki satu digit precisi. Perhitungan 1.0 + 0.1 + ... + 0.1(diulang 10 kali) kembali 1.0karena setiap hasil antara dibulatkan. Melakukannya babak cara lain, Anda mendapatkan hasil antara dari 0.2, 0.3, ..., 1.0dan akhirnya 2.0. Ini adalah contoh ekstrem, tetapi dengan angka floating point realistis, masalah serupa terjadi. Ide dasarnya adalah bahwa menambahkan angka dengan ukuran yang sama menyebabkan kesalahan terkecil. Mulailah dengan angka terkecil karena jumlah mereka lebih besar dan oleh karena itu lebih cocok untuk penambahan ke jumlah yang lebih besar.
maaartinus
Floating point stuff di Fortran dan C ++ sebagian besar identik. Keduanya akurat dan offline, dan saya cukup yakin Fortran tidak memiliki real BCD asli ...
Mark
8

Peringatan: Sistem tipe floating-point. Ganda tidak memiliki presisi untuk pengujian kesetaraan langsung.

double x = CalculateX();
if (x == 0.1)
{
    // ............
}

Saya tidak percaya apa pun bisa atau harus dilakukan pada tingkat bahasa.

ChaosPandion
sumber
1
Saya belum pernah menggunakan float atau double dalam waktu lama, jadi saya ingin tahu. Apakah itu peringatan kompiler yang ada saat ini, atau hanya yang ingin Anda lihat?
Karl Bielefeldt
1
@Karl - Secara pribadi saya belum melihatnya atau membutuhkannya tapi saya bayangkan itu bisa berguna untuk pengembang yang berdedikasi tetapi ramah lingkungan.
ChaosPandion
1
Tipe-tipe floating point biner tidak lebih baik atau lebih buruk secara kualitatif daripada Decimalketika menyangkut pengujian kesetaraan. Perbedaan antara 1.0m/7.0m*7.0mdan 1.0mmungkin banyak urutan besarnya kurang dari perbedaan antara 1.0/7.0*7.0, tetapi itu bukan nol.
supercat
1
@ Patrick - Saya tidak yakin apa yang Anda maksud. Ada perbedaan besar antara sesuatu yang benar untuk satu kasus dan benar untuk semua kasus.
ChaosPandion
1
@ChaosPandion Masalah dengan contoh dalam posting ini bukan perbandingan kesetaraan, itu adalah floating-point literal. Tidak ada float dengan nilai tepat 1.0 / 10. Matematika floating point menghasilkan hasil yang akurat 100% saat komputasi dengan bilangan integer yang pas dalam mantissa.
Patrick
7

Secara default, bahasa harus menggunakan rasional presisi arbitrer untuk angka yang bukan bilangan bulat.

Mereka yang perlu mengoptimalkan selalu dapat meminta mengapung. Menggunakannya sebagai default masuk akal dalam bahasa pemrograman sistem C dan lainnya, tetapi tidak dalam kebanyakan bahasa populer saat ini.

Waquo
sumber
1
Bagaimana Anda menangani bilangan irasional?
dsimcha
3
Anda melakukannya dengan cara yang sama seperti dengan mengapung: aproksimasi.
Waquo
1
Saya harus mengatakan saya pikir ini masuk akal, kebanyakan orang yang membutuhkan angka pasti membutuhkan rasional bukan rasional (sains dan teknik dapat menggunakan irasional tetapi Anda kemudian kembali ke bidang perkiraan lagi, atau Anda melakukan beberapa matematika murni yang cukup khusus)
jk.
1
Komputasi dengan rasional presisi arbitrer akan sering menjadi perintah dengan magnitudo lebih lambat (mungkin banyak perintah dengan magnitudo lebih lambat) daripada perhitungan dengan dukungan perangkat keras double. Jika suatu perhitungan perlu akurat untuk satu bagian per juta, lebih baik menghabiskan satu mikrodetik menghitungnya dalam beberapa bagian per miliar, daripada menghabiskan satu detik menghitungnya dengan sangat tepat.
supercat
5
@supercat: Apa yang Anda sarankan hanyalah poster-anak dari optimasi prematur. Situasi saat ini adalah bahwa sebagian besar programmer tidak memerlukan apapun untuk matematika cepat, dan kemudian digigit oleh sulit untuk memahami perilaku floating-point (mis), sehingga sejumlah kecil programmer yang membutuhkan matematika cepat mendapatkannya tanpa harus untuk mengetik satu karakter ekstra. Ini masuk akal pada tahun tujuh puluhan, sekarang hanya omong kosong. Defaultnya harus aman. Mereka yang membutuhkan puasa harus memintanya.
Waquo
4

Dua masalah terbesar yang melibatkan angka floating point adalah:

  • unit tidak konsisten yang diterapkan pada perhitungan (perhatikan ini juga mempengaruhi bilangan bulat aritmatika dengan cara yang sama)
  • kegagalan untuk memahami bahwa angka FP adalah perkiraan dan bagaimana menangani pembulatan secara cerdas.

Jenis kegagalan pertama hanya dapat diatasi dengan menyediakan jenis komposit yang mencakup nilai dan informasi unit. Misalnya, nilai lengthatau areayang menggabungkan unit (meter atau meter persegi atau kaki dan kaki persegi masing-masing). Kalau tidak, Anda harus rajin selalu bekerja dengan satu jenis unit pengukuran dan hanya mengkonversi ke yang lain ketika kami membagikan jawabannya dengan manusia.

Jenis kegagalan kedua adalah kegagalan konseptual. Kegagalan memanifestasikan diri ketika orang menganggapnya sebagai angka absolut . Ini mempengaruhi operasi kesetaraan, kesalahan pembulatan kumulatif, dll. Misalnya, mungkin benar bahwa untuk satu sistem dua pengukuran setara dalam margin kesalahan tertentu. Yaitu .999 dan 1.001 kira-kira sama dengan 1.0 ketika Anda tidak peduli tentang perbedaan yang lebih kecil dari +/- .1. Namun, tidak semua sistem toleran.

Jika ada fasilitas tingkat bahasa yang dibutuhkan, maka saya akan menyebutnya presisi kesetaraan . Di NUnit, JUnit, dan kerangka pengujian yang dibuat serupa Anda dapat mengontrol presisi yang dianggap benar. Sebagai contoh:

Assert.That(.999, Is.EqualTo(1.001).Within(10).Percent);
// -- or --
Assert.That(.999, Is.EqualTo(1.001).Within(.1));

Jika, misalnya, C # atau Java diubah untuk menyertakan operator presisi, mungkin terlihat seperti ini:

if(.999 == 1.001 within .1) { /* do something */ }

Namun, jika Anda menyediakan fitur seperti itu, Anda juga harus mempertimbangkan kasus di mana kesetaraan baik jika sisi +/- tidak sama. Misalnya, +1 / -10 akan mempertimbangkan dua angka yang setara jika salah satu dari mereka berada dalam 1 lebih, atau 10 kurang dari angka pertama. Untuk menangani kasus ini, Anda mungkin perlu menambahkan rangekata kunci juga:

if(.999 == 1.001 within range(.001, -.1)) { /* do something */ }
Berin Loritsch
sumber
2
Saya akan beralih pesanan. Masalah konseptual meresap. Masalah konversi unit relatif kecil jika dibandingkan.
S.Lott
Saya suka konsep operator presisi tetapi seperti yang Anda sebutkan lebih lanjut tentang itu pasti perlu dipikirkan dengan baik. Secara pribadi saya akan lebih cenderung melihatnya sebagai konstruksi sintaksis lengkap sendiri.
ChaosPandion
Bisa juga dengan mudah dilakukan di perpustakaan.
Michael K
1
@ dan04: Saya berpikir lebih dalam hal "semua perhitungan akurat hingga dalam satu persen" atau sejenisnya. Saya telah melihat tar-pit yang merupakan unit penanganan ukuran dan saya tinggal jauh.
TMN
1
Sekitar 25 tahun yang lalu, saya melihat paket numerik yang menampilkan tipe yang terdiri dari sepasang angka floating-point yang mewakili nilai maksimum dan minimum yang mungkin untuk suatu kuantitas. Ketika angka melewati perhitungan, perbedaan antara maksimum dan minimum akan tumbuh. Secara efektif, ini menyediakan sarana untuk mengetahui berapa banyak presisi nyata hadir dalam nilai yang dihitung.
supercat
3

Apa yang bisa dilakukan oleh bahasa pemrograman? Tidak tahu apakah ada satu jawaban untuk pertanyaan itu, karena apa pun yang dilakukan kompiler / penerjemah atas nama programmer untuk membuat hidupnya lebih mudah biasanya bekerja melawan kinerja, kejelasan, dan keterbacaan. Saya pikir kedua cara C ++ (hanya membayar untuk apa yang Anda butuhkan) dan cara Perl (prinsip kejutan terkecil) keduanya valid, tetapi itu tergantung pada aplikasi.

Pemrogram masih perlu bekerja dengan bahasa dan memahami bagaimana ia menangani floating point, karena jika tidak, mereka akan membuat asumsi, dan suatu hari perilaku yang ditentukan tidak akan cocok dengan asumsi mereka.

Pandangan saya tentang apa yang perlu diketahui oleh programmer:

  • Apa tipe floating-point yang tersedia pada sistem dan dalam bahasa
  • Jenis apa yang dibutuhkan
  • Bagaimana cara mengekspresikan niat jenis apa yang dibutuhkan dalam kode
  • Cara memanfaatkan dengan benar setiap jenis promosi otomatis untuk menyeimbangkan kejelasan dan efisiensi sambil mempertahankan kebenaran
John
sumber
3

Apa yang dapat dilakukan bahasa pemrograman untuk menghindari jebakan [titik mengambang] ...?

Gunakan default yang masuk akal, misalnya dukungan bawaan untuk decmial.

Groovy melakukan ini dengan cukup baik, meskipun dengan sedikit usaha Anda masih bisa menulis kode untuk memperkenalkan ketidaktepatan floating point.

Armand
sumber
3

Saya setuju tidak ada yang bisa dilakukan di tingkat bahasa. Pemrogram harus memahami bahwa komputer itu terpisah dan terbatas, dan bahwa banyak konsep matematika yang diwakili di dalamnya hanyalah perkiraan.

Jangankan floating point. Kita harus memahami bahwa setengah dari pola bit digunakan untuk bilangan negatif dan bahwa 2 ^ 64 sebenarnya cukup kecil untuk menghindari masalah tipikal dengan aritmatika integer.

Apalala
sumber
tidak setuju, sebagian besar bahasa saat ini memberikan terlalu banyak dukungan untuk tipe floating point biner (mengapa == bahkan didefinisikan untuk mengapung?) dan tidak cukup dukungan untuk rasional atau desimal
jk.
@ jk: Sekalipun hasil perhitungan apa pun tidak akan pernah dijamin sama dengan hasil perhitungan lain, perbandingan kesetaraan akan tetap berguna untuk kasus di mana nilai yang sama diberikan ke dua variabel (meskipun aturan kesetaraan yang umum diterapkan mungkin terlalu longgar, karena x== ytidak menyiratkan bahwa melakukan perhitungan pada xakan menghasilkan hasil yang sama dengan melakukan perhitungan yang sama pada y).
supercat
@supercat Anda masih perlu perbandingan, tetapi saya lebih suka bahasanya mengharuskan saya untuk menentukan toleransi untuk setiap perbandingan floating point, saya masih bisa kembali ke kesetaraan dengan memilih toleransi = 0, tapi saya setidaknya dipaksa untuk membuatnya pilihan
jk.
3

Satu hal yang bisa dilakukan oleh bahasa - menghapus perbandingan kesetaraan dari tipe floating point selain dari perbandingan langsung dengan nilai NAN.

Pengujian kesetaraan hanya akan ada sebagai pemanggilan fungsi yang mengambil dua nilai dan delta, atau untuk bahasa seperti C # yang memungkinkan tipe memiliki metode EqualsTo yang mengambil nilai lain dan delta.

Loren Pechtel
sumber
3

Saya merasa aneh bahwa tidak ada yang menunjukkan trik nomor rasional keluarga Lisp.

Serius, buka sbcl, dan lakukan ini: (+ 1 3)dan Anda mendapat 4. Jika *( 3 2)Anda mendapatkan 6. Sekarang coba (/ 5 3)dan Anda dapatkan 5/3, atau 5 pertiga.

Itu seharusnya agak membantu dalam beberapa situasi, bukan?

Haakon Løtveit
sumber
Saya ingin tahu, apakah mungkin untuk mengetahui apakah suatu hasil perlu direpresentasikan sebagai 1/3 atau dapat berupa desimal yang tepat?
mamcx
saran yang bagus
Peter Porfy
3

Satu hal yang saya ingin melihat akan menjadi pengakuan bahwa doubleuntuk floatharus dianggap sebagai konversi pelebaran, sementara floatuntuk doubleadalah penyempitan (*). Itu mungkin tampak kontra-intuisi, tetapi pertimbangkan apa arti sebenarnya tipe-tipe ini:

  • 0,1f berarti "13.421.773,5 / 134.217.728, plus atau minus 1 / 268.435.456 atau lebih".
  • 0,1 benar-benar berarti 3,602.879.701.896.397 / 36.028.797.018.963.968, plus atau minus 1 / 72.057.594.037.927.936 atau lebih "

Jika seseorang memiliki doubleyang memegang representasi terbaik dari kuantitas "sepersepuluh" dan mengubahnya menjadi float, hasilnya akan menjadi "13.421.773,5 / 134.217.728, plus atau minus 1 / 268.435.456 atau lebih", yang merupakan deskripsi nilai yang benar.

Sebaliknya, jika seseorang memiliki floatyang memegang representasi terbaik dari kuantitas "sepersepuluh" dan mengubahnya menjadi double, hasilnya akan menjadi "13.421.773,5 / 134.217.728, plus atau minus 1 / 72.057.594.037.927.936 atau lebih" - tingkat akurasi yang tersirat yang salah dengan faktor lebih dari 53 juta.

Meskipun standar IEEE-744 mensyaratkan bahwa matematika titik-mengambang dilakukan seolah-olah setiap angka titik-mengambang mewakili kuantitas numerik tepat tepat di pusat jangkauannya, yang tidak boleh dianggap menyiratkan bahwa nilai-nilai titik-mengambang sebenarnya mewakili yang tepat jumlah numerik. Sebaliknya, persyaratan bahwa nilai-nilai diasumsikan berada di pusat rentang mereka berasal dari tiga fakta: (1) perhitungan harus dilakukan seolah-olah operan memiliki beberapa nilai tepat tertentu; (2) asumsi yang konsisten dan terdokumentasi lebih bermanfaat daripada yang tidak konsisten atau tidak berdokumen; (3) jika seseorang akan membuat asumsi konsisten, tidak ada asumsi konsisten lain yang cenderung lebih baik daripada mengasumsikan kuantitas mewakili pusat kisarannya.

Kebetulan, saya ingat sekitar 25 tahun yang lalu, seseorang datang dengan paket numerik untuk C yang menggunakan "berbagai jenis", masing-masing terdiri dari sepasang pelampung 128-bit; semua perhitungan akan dilakukan sedemikian rupa untuk menghitung nilai minimum dan maksimum yang mungkin untuk setiap hasil. Jika seseorang melakukan perhitungan berulang yang panjang dan muncul dengan nilai [12.53401391134 12.53902812673], orang dapat yakin bahwa sementara banyak digit presisi hilang dari kesalahan pembulatan, hasilnya masih bisa dinyatakan secara wajar sebagai 12,54 (dan tidak t benar-benar 12.9 atau 53.2). Saya terkejut saya belum melihat adanya dukungan untuk jenis seperti itu dalam bahasa mainstream, terutama karena mereka tampaknya cocok dengan unit matematika yang dapat beroperasi pada berbagai nilai secara paralel.

(*) Dalam praktiknya, sering kali bermanfaat untuk menggunakan nilai presisi ganda untuk memegang perhitungan menengah ketika bekerja dengan angka presisi tunggal, jadi harus menggunakan tipografi untuk semua operasi semacam itu bisa mengganggu. Bahasa dapat membantu dengan memiliki tipe "fuzzy double", yang akan melakukan komputasi sebagai ganda, dan dapat dengan bebas dilemparkan ke dan dari tunggal; ini akan sangat membantu jika fungsi yang mengambil parameter tipe doubledan kembali doubledapat ditandai sehingga mereka secara otomatis menghasilkan kelebihan yang menerima dan mengembalikan "fuzzy double" sebagai gantinya.

supercat
sumber
2

Jika lebih banyak bahasa pemrograman mengambil halaman dari basis data dan memungkinkan pengembang untuk menentukan panjang dan ketepatan tipe data numerik mereka, mereka secara substansial dapat mengurangi kemungkinan kesalahan terkait titik apung. Jika bahasa memungkinkan pengembang untuk mendeklarasikan variabel sebagai Float (2), yang menunjukkan bahwa mereka membutuhkan angka floating point dengan dua digit desimal presisi, itu bisa melakukan operasi matematika lebih aman. Jika itu dilakukan dengan mewakili variabel sebagai integer secara internal dan membaginya dengan 100 sebelum mengekspos nilai, itu bisa meningkatkan kecepatan dengan menggunakan jalur aritmatika integer yang lebih cepat. Semantik Float (2) juga akan membiarkan pengembang menghindari kebutuhan konstan untuk membulatkan data sebelum mengeluarkannya karena Float (2) akan secara inheren membulatkan data ke dua titik desimal.

Tentu saja, Anda harus mengizinkan pengembang untuk meminta nilai floating point dengan ketelitian maksimum saat pengembang harus memiliki ketepatan itu. Dan Anda akan memperkenalkan masalah di mana ekspresi yang sedikit berbeda dari operasi matematika yang sama menghasilkan hasil yang berpotensi berbeda karena operasi pembulatan menengah ketika pengembang tidak membawa cukup presisi dalam variabel mereka. Tapi setidaknya di dunia basis data, itu sepertinya bukan masalah besar. Kebanyakan orang tidak melakukan perhitungan ilmiah yang membutuhkan banyak ketepatan dalam hasil-hasil antara.

Gua Justin
sumber
Menentukan panjang dan presisi akan sangat sedikit yang berguna. Memiliki titik tetap basis 10 akan berguna untuk pemrosesan keuangan, yang akan menghilangkan banyak kejutan yang didapat orang dari titik mengambang.
David Thornley
@ David - Mungkin saya kehilangan sesuatu tetapi bagaimana basis data tipe 10 titik tetap berbeda dari apa yang saya usulkan di sini? Float (2) dalam contoh saya akan memiliki 2 digit desimal tetap dan secara otomatis akan membulatkan ke seratus terdekat yang kemungkinan Anda gunakan untuk perhitungan keuangan sederhana. Perhitungan yang lebih kompleks akan mengharuskan pengembang mengalokasikan angka desimal yang lebih besar.
Justin Cave
1
Apa yang Anda advokasi adalah tipe data base 10 titik tetap dengan presisi yang ditentukan programmer. Saya mengatakan bahwa presisi yang ditentukan programmer sebagian besar tidak ada gunanya, dan hanya akan mengarah pada jenis kesalahan yang biasa saya temui dalam program COBOL. (Misalnya, ketika Anda mengubah ketepatan variabel, sangat mudah untuk melewatkan satu variabel yang nilainya berjalan. Untuk yang lain, akan lebih banyak berpikir tentang ukuran hasil antara daripada yang baik.)
David Thornley
4
Seorang Float(2)seperti yang Anda usulkan tidak boleh dipanggil Float, karena tidak ada yang mengambang di sini, tentu saja bukan "titik desimal".
Paŭlo Ebermann
1
  • bahasa memiliki dukungan tipe Desimal; tentu saja ini tidak benar-benar menyelesaikan masalah, tetap saja Anda tidak memiliki representasi yang tepat dan terbatas misalnya ⅓;
  • beberapa DB dan kerangka kerja memiliki dukungan tipe Uang, ini pada dasarnya menyimpan sejumlah sen sebagai bilangan bulat;
  • ada beberapa perpustakaan untuk mendukung bilangan rasional; yang memecahkan masalah ⅓, tetapi tidak menyelesaikan masalah misalnya √2;

Ini di atas berlaku dalam beberapa kasus, tetapi tidak benar-benar solusi umum untuk berurusan dengan nilai float. Solusi nyata adalah memahami masalah dan belajar bagaimana menghadapinya. Jika Anda menggunakan perhitungan titik float, Anda harus selalu memeriksa apakah algoritma Anda stabil secara numerik . Ada bidang besar matematika / ilmu komputer yang berhubungan dengan masalah tersebut. Ini disebut Analisis Numerik .

vartec
sumber
1

Seperti jawaban lain telah dicatat, satu-satunya cara nyata untuk menghindari jebakan floating point dalam perangkat lunak keuangan adalah tidak menggunakannya di sana. Ini sebenarnya mungkin layak - jika Anda menyediakan perpustakaan yang dirancang dengan baik yang didedikasikan untuk matematika keuangan .

Fungsi yang dirancang untuk mengimpor estimasi titik apung harus diberi label dengan jelas seperti itu, dan dilengkapi dengan parameter yang sesuai dengan operasi itu, misalnya:

Finance.importEstimate(float value, Finance roundingStep)

Satu-satunya cara nyata untuk menghindari jebakan floating point pada umumnya adalah pendidikan - programmer perlu membaca dan memahami sesuatu seperti Apa Yang Harus Setiap Programmer Ketahui Tentang Aritmatika Floating-Point .

Namun, beberapa hal yang mungkin membantu:

  • Saya akan mendukung mereka yang bertanya "mengapa pengujian kesetaraan yang tepat untuk floating point bahkan legal?"
  • Sebagai gantinya, gunakan isNear()fungsi.
  • Menyediakan, dan mendorong penggunaan, objek akumulator titik mengambang (yang menambahkan urutan nilai titik apung lebih stabil daripada hanya menambahkan mereka semua ke dalam variabel titik apung reguler).
datang badai
sumber
-1

Sebagian besar programmer akan terkejut bahwa COBOL melakukan hal yang benar ... dalam versi pertama COBOL tidak ada floating point, hanya desimal, dan tradisi di COBOL berlanjut hingga hari ini bahwa hal pertama yang Anda pikirkan ketika mendeklarasikan angka adalah desimal. .. floating point hanya akan digunakan jika Anda benar-benar membutuhkannya. Ketika C datang, untuk beberapa alasan, tidak ada tipe desimal primitif, jadi menurut saya, di situlah semua masalah dimulai.

JoelFan
sumber
1
C tidak memiliki tipe desimal karena tidak primitif, sangat sedikit komputer yang memiliki instruksi desimal perangkat keras. Anda mungkin bertanya mengapa BASIC dan Pascal tidak memilikinya, karena mereka tidak dirancang agar sesuai dengan logam. COBOL dan PL / I adalah satu-satunya bahasa yang saya tahu waktu itu yang memiliki hal seperti itu.
David Thornley
3
@ JoelFan: jadi bagaimana Anda menulis ⅓ dalam COBOL? Desimal tidak menyelesaikan masalah, basis 10 sama tidak akuratnya dengan basis 2.
vartec
2
Desimal memecahkan masalah yang secara tepat mewakili dolar dan sen, yang berguna untuk bahasa "Berorientasi Bisnis". Tetapi sebaliknya, desimal tidak berguna; ia memiliki jenis kesalahan yang sama (misalnya, 1/3 * 3 = 0,99999999) sementara jauh lebih lambat. Itulah sebabnya itu bukan default dalam bahasa yang tidak dirancang khusus untuk akuntansi.
dan04
1
Dan FORTRAN, yang mendahului C lebih dari satu dekade, juga tidak memiliki dukungan desimal standar.
dan04
1
@ JoelFan: jika Anda memiliki nilai triwulanan dan Anda perlu nilai per bulan, tebak apa yang harus Anda kalikan dengan ... tidak, ini bukan 0,33, itu ⅓.
vartec