Mengapa Anda membutuhkan float / double?

29

Saya sedang menonton http://www.joelonsoftware.com/items/2011/06/27.html dan menertawakan lelucon Jon Skeet tentang 0,3 tidak menjadi 0,3. Saya pribadi tidak pernah memiliki masalah dengan float / desimal / ganda tetapi kemudian saya ingat saya belajar 6502 sangat awal dan tidak pernah membutuhkan float di sebagian besar program saya. Satu-satunya waktu saya menggunakannya untuk grafik dan matematika di mana angka-angka yang tidak akurat ok dan output untuk layar dan tidak untuk disimpan (dalam db, file) atau tergantung pada.

Pertanyaan saya adalah, di mana tempat-tempat yang biasanya Anda gunakan pelampung / desimal / ganda? Jadi saya tahu harus waspada terhadap gotcha ini. Dengan uang, saya menggunakan long dan menyimpan nilai per sen, untuk kecepatan suatu objek dalam permainan, saya menambahkan int dan membagi (atau bitshift) nilai untuk mengetahui apakah saya perlu memindahkan piksel atau tidak. (Saya membuat objek bergerak dalam 6502 hari, kami tidak memiliki celah atau mengapung tetapi memiliki pergeseran).

Jadi saya sebagian besar penasaran.

FrustratedWithFormsDesigner
sumber
10
karena sangat penting bahwa bunga yang saya bayar pada hipotek saya tetap 12,6 dan doest menjadi 13 hanya karena 13 adalah angka bulat yang bagus.
Chani
1
"Saya belajar 6502 sangat awal dan tidak pernah membutuhkan mengapung di sebagian besar program saya ... untuk kecepatan objek saya menambahkan int dan membagi nilai untuk mengetahui apakah akan memindahkan piksel atau tidak." Ini adalah cara yang sangat tidak biasa untuk menyelesaikan tugas-tugas ini dalam praktik modern, kecuali untuk representasi uang selama sen.
jprete
Untung komputer mengerti millicents.
tylermac
1
Atau sebagai tambahan, mengapa menggunakan desimal ketika kita bisa menggunakan pecahan?
tylermac
6
@ Scrooge - ironisnya Anda tidak dapat mewakili 0,6 dalam float.
Martin Beckett

Jawaban:

28

Karena, untuk sebagian besar tujuan, lebih akurat daripada bilangan bulat.

Sekarang bagaimana itu? "untuk kecepatan objek dalam permainan ..." ini adalah contoh yang bagus untuk kasus seperti itu. Katakanlah Anda perlu memiliki beberapa objek yang sangat cepat, seperti peluru. Untuk dapat menggambarkan gerakan mereka dengan variabel kecepatan integer, Anda harus memastikan kecepatannya berada dalam kisaran variabel integer, itu berarti Anda tidak dapat memiliki raster yang berubah-ubah.

Tapi kemudian, Anda mungkin juga ingin menggambarkan beberapa objek yang sangat lambat, seperti jarum jam. Karena ini sekitar 6 urutan besarnya lebih lambat dari objek peluru, ld pertama (10⁶) bits 20 bit adalah nol, yang mengesampingkan short intjenis dari awal. Ok, hari ini kita punya longdi mana-mana, yang meninggalkan kita dengan 12 bit yang masih nyaman. Tetapi meskipun demikian, kecepatan jam akan tepat hanya untuk empat tempat desimal. Itu bukan jam yang sangat bagus ... tapi tentu saja ok untuk sebuah game. Hanya saja, Anda tidak ingin membuat raster lebih kasar dari yang sudah ada.

... yang mengarah ke masalah jika suatu hari Anda ingin memperkenalkan jenis objek baru yang lebih cepat. Tidak ada "ruang kepala" yang tersisa.

Apa yang terjadi jika kita memilih tipe float? Ukuran yang sama dari 32 bit, tetapi sekarang Anda memiliki presisi 24 bit penuh, untuk semua objek. Itu berarti, jam memiliki presisi yang cukup untuk tetap sinkron hingga detik selama bertahun-tahun. Peluru tidak memiliki presisi yang lebih tinggi, tetapi mereka hanya "hidup" untuk sepersekian detik, jadi itu akan sama sekali tidak berguna jika mereka punya. Dan Anda tidak mendapatkan masalah apa pun jika Anda ingin menggambarkan objek yang jauh lebih cepat (mengapa tidak kecepatan cahaya? Tidak masalah) atau yang jauh lebih lambat. Anda tentu tidak akan membutuhkan hal-hal seperti itu dalam permainan, tetapi kadang-kadang Anda lakukan dalam simulasi fisika.

Dan dengan angka floating-point, Anda mendapatkan ketepatan yang sama ini selalu dan tanpa terlebih dahulu harus pintar memilih beberapa raster yang tidak jelas. Itu mungkin poin yang paling penting, karena kebutuhan pilihan seperti itu sangat rawan kesalahan.

leftaroundabout
sumber
Integer sangat akurat. Ketidaktepatan bergantung pada perhitungan yang salah.
fjdumont
15
Integer benar-benar akurat hanya ketika Anda menggunakannya untuk benar-benar mewakili angka integer (ℤ). Mewakili hal lain berarti penghitungan yang salah. Dalam kasus seperti itu, Anda memiliki dua kemungkinan: menentukan beberapa jenis yang sesuai dengan angka yang ingin Anda wakili. ini dimungkinkan, misalnya Mathematica dapat melakukannya. Tapi itu sangat rumit dan mahal waktu, dan biasanya tidak sepadan dengan usaha karena Anda sebenarnya tidak membutuhkan ketepatan sempurna. Tetapi Anda memang membutuhkan presisi yang baik , dan di situlah pelampung umumnya melakukan pekerjaan yang lebih baik daripada bilangan bulat.
leftaroundabout
53

Anda menggunakannya ketika Anda menggambarkan nilai kontinu daripada nilai diskrit . Tidak ada yang lebih rumit untuk dijelaskan daripada itu. Hanya saja, jangan membuat kesalahan dengan mengasumsikan nilai dengan titik desimal adalah kontinu. Jika itu berubah sekaligus dalam potongan, seperti menambahkan satu sen, itu terpisah.

Karl Bielefeldt
sumber
28

Anda benar-benar memiliki dua pertanyaan di sini.

Kenapa sih ada yang butuh matematika floating point?

Seperti yang ditunjukkan Karl Bielefeldt, angka floating point memungkinkan Anda memodelkan jumlah terus menerus - dan Anda menemukan semuanya di mana-mana - tidak hanya di dunia fisik, tetapi bahkan tempat-tempat seperti bisnis dan keuangan.

Saya telah menggunakan matematika floating point dalam banyak, banyak bidang dalam karir pemrograman saya: kimia, bekerja di AutoCAD, dan bahkan menulis simulator Monte Carlo untuk melakukan prediksi keuangan. Bahkan, ada seorang pria bernama David E. Shaw yang menggunakan teknik pemodelan ilmiah berbasis floating-point untuk Wall Street untuk menghasilkan miliaran.

Dan, tentu saja, ada grafik komputer. Saya berkonsultasi untuk mengembangkan eye candy untuk antarmuka pengguna, dan mencoba melakukannya saat ini tanpa pemahaman yang kuat tentang floating point, trigonometri, kalkulus, dan aljabar linier, akan seperti muncul untuk pertarungan senjata dengan pisau lipat.

Mengapa ada yang butuh pelampung versus ganda ?

Dengan representasi standar IEEE 754, float 32-bit memberi Anda sekitar 7 digit desimal akurasi, dan eksponen dalam kisaran 10 -38 hingga 10 38 . Double 64-bit memberi Anda sekitar 15 digit desimal akurasi, dan eksponen dalam kisaran 10 -307 hingga 10 307 .

Ini mungkin tampak seperti pelampung yang cukup untuk apa yang dibutuhkan oleh siapa pun, tetapi ternyata tidak. Misalnya, banyak kuantitas dunia nyata diukur dalam lebih dari 7 digit desimal.

Tapi yang lebih halus, ada masalah bahasa sehari-hari yang disebut "kesalahan pembulatan". Representasi titik mengambang biner hanya berlaku untuk nilai yang bagian pecahannya memiliki penyebut yang memiliki kekuatan 2, seperti 1/2, 1/4, 3/4, dll. Untuk mewakili fraksi lain, seperti 1/10, Anda "bulat" nilai ke fraksi biner terdekat, tapi itu sedikit salah - itulah "kesalahan pembulatan". Kemudian ketika Anda menghitung dengan angka-angka yang tidak akurat itu, ketidakakuratan dalam hasil bisa jauh lebih buruk daripada yang Anda mulai - kadang-kadang persentase kesalahan berlipat ganda, atau bahkan menumpuk secara eksponensial.

Bagaimanapun, semakin banyak digit biner yang harus Anda kerjakan, semakin dekat representasi biner bulat Anda akan ke angka yang Anda coba wakili, sehingga kesalahan pembulatannya akan lebih kecil. Kemudian ketika Anda melakukan perhitungan matematika, jika Anda memiliki banyak digit untuk dikerjakan, Anda dapat melakukan lebih banyak operasi sebelum kesalahan pembulatan kumulatif menumpuk di mana itu merupakan masalah.

Sebenarnya, 64-bit ganda dengan 15 angka desimal mereka tidak cukup baik untuk banyak aplikasi. Saya menggunakan angka floating point 80-bit pada tahun 1985, dan IEEE sekarang mendefinisikan tipe floating point 128-bit (16-byte), yang dapat saya bayangkan digunakan.

Bob Murphy
sumber
2
+1 Bob pengalaman saya dengan sistem kontrol resolusi tinggi seperti teleskop untuk astronomi adalah bahwa 64bit ganda tidak cukup baik kecuali Anda menyortir istilah Anda. Ditto untuk pengendalian kebakaran dan navigasi jarak jauh
Tim Williscroft
20

Ini adalah kesalahpahaman umum, bahwa di mana pun Anda berurusan dengan uang, Anda harus menyimpan nilainya sebagai bilangan bulat (sen). Walaupun dalam beberapa kasus sederhana seperti toko online itu benar, jika Anda memiliki sesuatu yang lebih canggih, itu tidak banyak membantu.

Mari kita ambil contoh: seorang pengembang menghasilkan $ 100.000 setahun. Berapa gaji bulannya? Menggunakan integer Anda mendapatkan hasil $ 8333,33 (¢ 833333), yang dikalikan dengan 12 adalah $ 99.999,96. Apakah menjaganya sebagai integer membantu? Tidak, tidak.

Apakah bank selalu menggunakan nilai desimal / integer? Ya, mereka melakukannya untuk bagian transaksional. Tapi misalnya begitu Anda mulai berbicara tentang perbankan investasi, dengan pengecualian melacak transaksi aktual, yang lainnya mengambang. Karena ini semua kode internal, Anda tidak akan melihatnya, tetapi Anda dapat mengambil puncak di QuantLib , yang pada dasarnya sama (kecuali jauh lebih bersih ;-).

Mengapa menggunakan pelampung? Karena menggunakan desimal tidak membantu sama sekali ketika Anda menggunakan fungsi seperti root kuadrat, logaritma, kekuatan dengan eksponen non-integer dll. Dan tentu saja mengapung jauh lebih cepat daripada tipe Desimal.

vartec
sumber
1
@ Job - desimal dan float sangat berbeda. Anda dapat menyimpan 0,1 tepat dalam tipe desimal, tetapi tidak dalam float atau double.
Scott Whitlock
3
Saya punya pertanyaan lain. Jika Anda membayar $100,000/12dan menggunakan pelampung. Mengapa hasilnya persis $ 100.000? Mengapa float (atau desimal) tidak akan naik atau turun setiap kali seseorang dibayar? Saya berbicara tentang ketika menulis cek (Anda tidak dapat melakukan 1/2 atau 1/3 sen) atau setoran langsung (saya menganggap itu memiliki keterbatasan yang sama)
@acid: >>> x = 100000 / 12.0 >>> x * 12 100000.0
vartec
baca kembali komentar saya? pertanyaan saya adalah kapan saya menggunakan perangkat lunak untuk membuat cek setiap bulan. Karena seseorang tidak dapat membayar 1/2 sen, bagaimana orang tersebut mendapatkan jumlah penuh setelah satu tahun?
2
@ asam: Anda tidak bisa menggunakan pembagian lurus, terlepas dari apakah Anda menggunakan integer, desimal atau bagi sebagai float lalu bulatkan. Itulah intinya, menggunakan desimal tidak membantu hal itu.
vartec
4

Apa yang telah Anda gambarkan adalah pekerjaan yang sangat baik untuk situasi di mana Anda mengontrol semua input dan output .

Dalam kata sebenarnya bukan itu masalahnya. Anda harus dapat mengatasi sistem yang memasok data mereka kepada Anda sebagai nilai nyata hingga tingkat presisi tertentu dan akan mengharapkan Anda mengembalikan data dalam format yang sama. Dalam kasus seperti itu, Anda akan menghadapi masalah ini.

Bahkan Anda akan menghadapi masalah ini bahkan jika Anda menggunakan trik yang Anda daftarkan. Saat menghitung pajak 17,5% pada harga Anda akan mendapatkan sen pecahan apakah Anda menyimpan nilainya dalam dolar atau sen. Anda harus mendapatkan pembulatan yang benar karena petugas pajak menjadi sangat marah jika Anda tidak membayarnya cukup. Menggunakan moneytipe-tipe yang benar (apa pun itu dalam bahasa yang Anda gunakan) akan menyelamatkan Anda dari dunia kesakitan.

ChrisF
sumber
Apa jenis uangnya? (bahasa atau tautan referensi) dan mengapa itu jenis yang 'benar'? Apakah karena ... 128bits atau lebih sesuatu? Alasan saya yang lain mengapa menggunakan 'trik' saya salah? Anda memiliki seluruh bilangan persen. Jika Anda mengalikannya dengan 0,175 Anda akan mendapatkan seluruh nomor dan menggunakannya untuk apa pun yang Anda inginkan. Berpikir tentang contoh Anda saya pikir float akan dapat memegang nilai saya dengan cukup presisi tetapi saya tidak perlu khawatir tentang 0,3f == 0,3d menjadi salah. -edit- dan +1
1
@ acidzombie24 - Saya tidak bermaksud jenis tertentu, tapi apa yang pernah ketik bahasa Anda gunakan untuk mewakili nilai uang. Juga jika Anda memiliki 10 sen dan kalikan dengan 0,175 Anda memiliki 1,75 sen - bagaimana Anda menghadapinya dengan aritmatika integer? Apakah 1 sen atau 2 sen? Salah dan pelanggan Anda akhirnya memiliki banyak uang petugas pajak .
ChrisF
Anda seharusnya tidak pernah mengalikan 10 (bilangan bulat) dengan 0,175 (angka nyata / mengambang) karena Anda tidak boleh mencampur angka pastinya dengan angka tidak eksak; hasilnya akan tidak tepat. Dengan kata lain, dalam sistem angka pastinya, nilai seperti .175 tidak akan pernah ada, jadi ini adalah perhitungan yang tidak masuk akal. Solusi yang lebih baik adalah mengalikan 10.000 dengan 175 dan secara manual memasukkan titik desimal jika sesuai.
Barry Brown
8
@ Barry - Saya tahu. Saya mencoba mengilustrasikan jenis masalah yang Anda dapatkan. Nilai 0,175 juga ada jika tarif pajaknya 17,5% dan Anda harus menghitung pajak untuk item yang harganya 10 sen.
ChrisF
1
@acidzombie: Jenis yang tepat untuk digunakan untuk uang adalah desimal titik tetap dengan presisi tinggi (setidaknya 4 poin desimal). Tidak ada ifs, ands, atau buts. Menyimpan nilai uang sebagai sen tidak cukup, karena dalam praktiknya hanya memberi Anda dua poin presisi.
Aaronaught
3

"Tuhan menciptakan bilangan bulat, yang lainnya adalah pekerjaan manusia." - Leopold Kronecker (1886).

Menurut definisi, Anda tidak memerlukan jenis angka lainnya. Kelengkapan Turing untuk bahasa pemrograman didasarkan pada hubungan sederhana di antara berbagai jenis angka. Jika Anda dapat bekerja dengan bilangan bulat (a / k / bilangan alami), Anda dapat melakukan apa saja.

Pertanyaannya agak membingungkan karena Anda tidak membutuhkannya . Mungkin Anda menginginkan tempat yang nyaman atau optimal atau lebih murah atau apa?

S.Lott
sumber
7
Kita juga bisa mengeluarkan bilangan bulat, karena kita juga bisa membangunnya hanya dengan menggunakan operasi teori himpunan dan himpunan kosong. Namun baik itu maupun argumentasi dari Turing kelengkapan adalah reduksionisme akademik dibawa ke ekstrem.
Bob Murphy
4
Juga, kelengkapan Turing hanya berlaku untuk komputasi. Baik bilangan bulat maupun rasional tidak lengkap secara matematis, karena tidak ada yang tertutup untuk konvergensi urutan Cauchy. Jadi Kronecker penuh dengan udara panas: jika Anda menginginkan ruang metrik lengkap yang mencakup seluruh bilangan, Anda harus menjadi nyata: xkcd.com/849
Bob Murphy
1
@ Bob Murphy: "reduksionisme akademik dibawa ke ekstrem". Tepat. Pertanyaannya buruk dan mengarah ke jawaban ini.
S.Lott
2

Dalam sebuah kalimat, tipe desimal floating-point merangkum konversi ke dan dari nilai integer (yang mana semua komputer tahu bagaimana berurusan dengan tingkat biner; tidak ada titik desimal dalam biner) yang menyediakan logika, umumnya mudah dilakukan. memahami antarmuka untuk perhitungan angka desimal.

Terus terang, mengatakan bahwa Anda tidak perlu mengapung karena Anda tahu bagaimana melakukan matematika desimal menggunakan bilangan bulat seperti mengatakan Anda tahu bagaimana melakukan aritmatika secara langsung, jadi mengapa menggunakan kalkulator? Jadi, Anda tahu konsepnya; bravo. Tidak berarti Anda harus menggunakan pengetahuan itu setiap saat. Seringkali lebih cepat, lebih murah, dan lebih mudah dipahami oleh jagoan non-biner untuk hanya mengatakan 3,5 + 4,6 = 8,1 daripada mengubah gambar ara ke kuantitas integer.

KeithS
sumber
1

Keuntungan utama tipe floating-point adalah bahwa dari perspektif run-time, dua atau tiga format (saya berharap lebih banyak bahasa mendukung format 80-bit) akan mencukupi untuk sebagian besar tujuan komputasi yang cepat. Jika bahasa pemrograman dapat dengan mudah mendukung keluarga jenis titik tetap, kompleksitas perangkat keras yang diperlukan untuk tingkat kinerja tertentu akan sering lebih rendah dengan jenis titik tetap daripada dengan titik mengambang. Sayangnya, memberikan dukungan seperti itu masih jauh dari "mudah".

Agar suatu bahasa pemrograman dapat memenuhi 98% kebutuhan numerik aplikasi secara efisien, ia harus menyertakan lusinan jenis, dan menyediakan operasi yang pasti untuk ratusan kombinasi; lebih lanjut, bahkan jika bahasa pemrograman memiliki dukungan titik tetap yang luar biasa, beberapa aplikasi masih perlu mempertahankan presisi relatif yang relatif konstan pada rentang yang cukup besar sehingga memerlukan titik-mengambang. Mengingat bahwa matematika titik-mengambang akan diperlukan pada beberapa kesempatan dalam peristiwa apa pun, memiliki vendor perangkat keras fokus pada kinerja matematika dengan dua atau tiga format titik-mengambang, dan memiliki kode yang menggunakan format-format itu setiap kali mereka bekerja dengan cukup baik, umumnya akan mencapai yang lebih baik "bang for the buck" daripada mencoba mengoptimalkan perilaku matematika fixed-point.

Kebetulan, matematika fixed-point lebih menguntungkan dengan prosesor 8-bit dan 16-bit daripada dengan yang 32-bit. Pada prosesor 8-bit, dalam situasi di mana 32 bit tidak akan cukup, tipe 40-bit hanya akan menghabiskan biaya 25% lebih banyak ruang dan 25-50% lebih banyak waktu daripada tipe 32-bit, dan akan membutuhkan 37,5% lebih sedikit ruang dan waktu 37,5-60% lebih sedikit daripada tipe 64-bit. Pada platform 32-bit, jika tipe 32-bit tidak cukup untuk sesuatu, seringkali ada sedikit alasan untuk menggunakan sesuatu yang kurang dari 64 bit. Jika tipe titik tetap 48-bit akan memadai, "ganda" 64-bit akan berfungsi sama baiknya dengan tipe titik tetap.

supercat
sumber
0

Secara umum, Anda harus sangat berhati-hati dalam menggunakannya. Memahami hilangnya ketepatan yang dapat timbul bahkan dari perhitungan sederhana adalah sebuah tantangan. Misalnya, rata-rata daftar angka seperti ini adalah ide yang sangat buruk:

double average(List<Double> data) {
  double ans = 0;
  for(Double d : data) {
    ans += d;
  }
  return ans / data.size();
}

Alasannya adalah, untuk daftar yang cukup besar, Anda pada dasarnya kehilangan semua titik data ketika ansmenjadi cukup besar (lihat misalnya ini ). Masalah dengan kode ini adalah bahwa untuk daftar kecil, itu mungkin hanya akan berfungsi --- itu hanya pada skala yang rusak.

Secara pribadi, saya pikir Anda hanya boleh menggunakannya ketika: a) perhitungannya harus cepat; b) Anda tidak peduli bahwa hasilnya cenderung jauh (kecuali Anda benar-benar tahu apa yang Anda lakukan).

redjamjar
sumber
-1

Satu pemikiran adalah bahwa Anda akan menggunakan representasi float atau dobel ketika Anda perlu berurusan dengan nilai-nilai di luar rentang integer.

Arsitektur hari ini (secara kasar) memiliki kisaran integer bertanda +/- 2.147.483.647 (32 bit) atau +/- 9.222.372.036.854.775.807 (64 bit). Unsigned memperluasnya dengan faktor 2.

IEEE 754 mengapung (kira-kira) naik dari +/- 1,4 × 10 ^ −45 ke 3,4 × 10 ^ 38. Double memanjang hingga +/- 5 × 10−324 ± 2.225 × 10 ^ −308 dengan banyak kondisi dan spesifikasi dihilangkan di sini.

Tentu saja, alasan yang paling jelas adalah bahwa Anda mungkin perlu mewakili -0 ;-)

Stephen
sumber
Angka terutama dari artikel wikipedia dan dimaksudkan sebagai ilustrasi. Kecuali -0, itu hanya untuk bersenang-senang.
Stephen
Masalahnya adalah ada BANYAK bilangan bulat dalam kisaran besar yang tidak terwakili sama sekali.
Barry Brown
@ BarryBrown Benar sekali. "Namun banyak kondisi dan spesifikasi dihilangkan".
Stephen
-1

Alasan biasa adalah karena mereka cepat karena JVM biasanya menggunakan dukungan perangkat keras yang mendasarinya (kecuali Anda menggunakan strictfp).

Lihat https://stackoverflow.com/questions/517915/when-to-use-strictfp-keyword-in-java untuk apa yang disiratkan strictfp.

Komunitas
sumber
Matematika floating point lebih cepat dari matematika integer? Pada prosesor apa perhitungan floating point mengambil siklus lebih sedikit daripada perhitungan integer?
this.josh
1
@ this.josh, sangat tergantung pada jumlah digit yang Anda miliki di nomor Anda. Juga bilangan bulat tidak dapat membagi secara tepat yang mungkin atau mungkin tidak penting.
-2

Itu sebabnya kami membutuhkan sistem operasi 256bit.

Panjang Plank (jarak terkecil yang bisa Anda ukur) = 10 ^ -35m
Alam semesta yang dapat diamati adalah parsecs sepanjang 14Bn = 10 ^ 25m
Jadi Anda bisa mengukur apa pun dalam satuan panjang Plank sebagai bilangan bulat jika Anda hanya memiliki presisi 200 bit.

Martin Beckett
sumber
2
-1: bagaimana jika Anda mensimulasikan hal-hal pada skala yang lebih besar dari alam semesta yang dapat diamati?
amara
2
@sparkleshy, itulah gunanya FAR pointer!
Martin Beckett