Mengapa mengapung masih menjadi bagian dari bahasa Jawa ketika dobel kebanyakan direkomendasikan?

84

Di setiap tempat yang saya lihat, dikatakan doublelebih unggul floatdalam hampir semua hal. floattelah dibuat usang oleh doubledi Jawa, jadi mengapa masih digunakan?

Saya banyak memprogram dengan Libgdx, dan mereka memaksa Anda untuk menggunakan float(deltaTime, dll.), Tetapi bagi saya sepertinya doublelebih mudah untuk dikerjakan dalam hal penyimpanan dan memori.

Saya juga membaca Kapan Anda menggunakan float dan kapan Anda menggunakan double , tetapi jika floatbenar-benar hanya baik untuk angka dengan banyak digit setelah titik desimal, lalu mengapa kita tidak bisa menggunakan salah satu dari banyak variasi saja double?

Apakah ada alasan mengapa orang bersikeras menggunakan pelampung meskipun sebenarnya tidak memiliki keunggulan lagi? Apakah terlalu banyak pekerjaan untuk mengubah semuanya?

Eames
sumber
8
Kemungkinan rangkap dari Kapan Anda menggunakan kendaraan dan kapan Anda menggunakan ganda
Vincent Savard
58
Bagaimana Anda menyimpulkan "float benar-benar hanya baik untuk angka dengan banyak digit setelah titik desimal" dari jawaban pertanyaan itu ?! Mereka mengatakan sebaliknya !
Biasa
20
@Enames Perhatikan bagaimana bunyinya "angka", bukan "angka". Mengapung lebih buruk ketika Anda membutuhkan presisi atau jangkauan, mereka lebih baik ketika Anda membutuhkan banyak dan banyak data yang tidak begitu tepat. Itulah yang dikatakan jawaban-jawaban itu.
Biasa
29
Mengapa kita memiliki bytedan shortdan intketika ada long?
user253751
15
Pertanyaan yang jauh lebih pas adalah "mengapa Anda menghapus kata kunci dan tipe data primitif dari bahasa dengan kode puluhan tahun yang akan rusak tanpa alasan"?
Sara

Jawaban:

169

LibGDX adalah kerangka kerja yang banyak digunakan untuk pengembangan game.

Dalam pengembangan game, Anda biasanya harus melakukan banyak angka secara real-time dan kinerja apa pun yang Anda bisa dapatkan. Itu sebabnya pengembang game biasanya menggunakan float setiap kali presisi float cukup baik.

Ukuran register FPU dalam CPU bukan satu-satunya hal yang perlu Anda pertimbangkan dalam kasus ini. Bahkan sebagian besar angka berat dalam pengembangan game dilakukan oleh GPU, dan GPU biasanya dioptimalkan untuk float, bukan ganda .

Dan kemudian ada juga:

  • bandwidth bus memori (seberapa cepat Anda dapat menyekop data antara RAM, CPU dan GPU)
  • Cache CPU (yang membuat sebelumnya kurang perlu)
  • RAM
  • VRAM

yang semua sumber daya berharga yang Anda dapatkan dua kali lipat ketika Anda menggunakan float 32bit bukannya 64bit ganda.

Philipp
sumber
2
Terima kasih! Ini benar-benar membantu karena Anda memahami secara mendalam apa yang mengubah penggunaan memori dan mengapa
Eames
7
Juga, untuk operasi SIMD, nilai 32-bit dapat memiliki dua kali throughput. Sebagai jawaban 8bittree menunjukkan, GPU memiliki penalti kinerja yang lebih besar dengan presisi ganda.
Paul A. Clayton
5
Banyak grafik pipa bahkan mendukung pelampung 16-bit setengah untuk meningkatkan kinerja di mana presisi cukup.
Adi Shavit
22
@phhnel Semua adalah. Anda harus memindahkan posisi, memperbarui data, dan apa yang tidak. Dan ini adalah bagian yang sederhana . Maka Anda harus merender (= membaca, memutar, skala, dan menerjemahkan) tekstur, jarak, dapatkan ke format layar ... Ada banyak yang harus dilakukan.
Sebb
8
@phesnel sebagai mantan VP Operations dari sebuah perusahaan pengembangan game, saya yakinkan Anda hampir setiap game ada satu ton angka berderak. Catatan itu biasanya terkandung di perpustakaan dan 100% disarikan dari insinyur, saya berharap mereka mengerti dan menghargai bahwa semua yang terjadi berderak. Root kuadrat terbalik ajaib, siapa saja?
corsiKa
57

Mengapung menggunakan setengah dari memori sebanyak dua kali lipat.

Mereka mungkin memiliki presisi kurang dari dua kali lipat, tetapi banyak aplikasi tidak membutuhkan presisi. Mereka memiliki jangkauan yang lebih besar daripada format titik tetap berukuran serupa. Oleh karena itu, mereka mengisi ceruk yang membutuhkan rentang angka yang luas tetapi tidak membutuhkan presisi tinggi, dan di mana penggunaan memori penting. Saya telah menggunakan mereka untuk sistem jaringan saraf besar di masa lalu, misalnya.

Bergerak di luar Jawa, mereka juga banyak digunakan dalam grafik 3D, karena banyak GPU menggunakannya sebagai format utama - di luar perangkat NVIDIA Tesla / AMD FirePro yang sangat mahal, floating point presisi ganda sangat lambat pada GPU.

Jules
sumber
8
Berbicara tentang jaringan saraf, CUDA saat ini memiliki dukungan untuk variabel floating point setengah presisi (16-bit), bahkan kurang tepat tetapi dengan jejak memori yang lebih rendah, karena meningkatnya penggunaan akselerator untuk pekerjaan pembelajaran mesin.
JAB
Dan ketika Anda memprogram FPGA, Anda cenderung memilih jumlah bit untuk mantissa dan eksponen secara manual setiap kali: v
Sebi
48

Kompatibilitas Mundur

Ini adalah nomor satu alasan untuk menjaga perilaku dalam sudah ada bahasa / perpustakaan / ISA / etc.

Pertimbangkan apa yang akan terjadi jika mereka membawa kendaraan hias keluar dari Jawa. Libgdx (dan ribuan perpustakaan dan program lain) tidak akan berfungsi. Ini akan membutuhkan banyak upaya untuk mendapatkan semuanya diperbarui, sangat mungkin bertahun-tahun untuk banyak proyek (lihat saja transisi Pemecahan kompatibilitas mundur Python 2 ke Python 3). Dan tidak semuanya akan diperbarui, beberapa hal akan rusak selamanya karena pengelola mengabaikannya, mungkin lebih cepat dari yang seharusnya karena akan membutuhkan lebih banyak upaya daripada yang ingin diperbarui, atau karena tidak mungkin lagi mencapai apa yang seharusnya perangkat lunak mereka perkirakan melakukan.

Performa

64 bit ganda membutuhkan memori dua kali lipat dan hampir selalu lebih lambat untuk diproses daripada float 32 bit (pengecualian yang sangat jarang adalah di mana kemampuan float 32 bit diharapkan digunakan sangat jarang atau tidak sama sekali, sehingga tidak ada upaya yang dilakukan untuk mengoptimalkannya. Kecuali Anda mengembangkan perangkat keras khusus, Anda tidak akan mengalami ini dalam waktu dekat.)

Khusus yang relevan bagi Anda, Libgdx adalah perpustakaan permainan. Game memiliki kecenderungan lebih sensitif terhadap kinerja daripada kebanyakan perangkat lunak. Dan kartu grafis gaming (yaitu AMD Radeon dan NVIDIA Geforce, bukan FirePro atau Quadro) cenderung memiliki kinerja floating point 64 bit yang sangat lemah. Atas perkenan Anandtech, berikut ini perbandingan kinerja presisi ganda dengan kinerja presisi tunggal pada beberapa kartu gaming papan atas AMD dan NVIDIA yang tersedia (per awal 2016)

AMD
Card    R9 Fury X      R9 Fury       R9 290X    R9 290
FP64    1/16           1/16          1/8        1/8

NVIDIA
Card    GTX Titan X    GTX 980 Ti    GTX 980    GTX 780 Ti
FP64    1/32           1/32          1/32       1/24

Perhatikan bahwa seri R9 Fury dan GTX 900 lebih baru daripada seri R9 200 dan GTX 700, sehingga kinerja relatif untuk floating point 64 bit menurun. Kembali cukup jauh dan Anda akan menemukan GTX 580, yang memiliki rasio 1/8 seperti seri R9 200.

1/32 dari kinerja adalah penalti yang cukup besar untuk dibayar jika Anda memiliki batasan waktu yang ketat dan tidak mendapatkan banyak dengan menggunakan ganda yang lebih besar.

8bree
sumber
1
perhatikan bahwa kinerja untuk floating point 64-bit menurun relatif terhadap kinerja 32-bit karena instruksi 32-bit yang semakin dioptimalkan, bukan karena kinerja 64-bit yang sebenarnya menurun. itu juga tergantung pada tolok ukur aktual yang digunakan; Saya ingin tahu apakah defisit kinerja 32-bit yang disorot dalam tolok ukur ini adalah karena masalah bandwidth memori serta kecepatan komputasi yang sebenarnya
sig_seg_v
Jika Anda akan berbicara tentang kinerja DP dalam kartu grafis, Anda harus menyebutkan Titan / Titan Black. Kedua mod fitur yang memungkinkan kartu mencapai 1/3 kinerja, dengan biaya kinerja presisi tunggal.
SGR
@sig_seg_v Pasti ada setidaknya beberapa kasus di mana kinerja 64-bit menurun secara absolut, bukan hanya relatif. Lihat hasil ini untuk tolok ukur Folding @ Home presisi ganda, di mana GTX 780 Ti mengalahkan GTX 1080 (kartu rasio 1/32 lainnya) dan 980 Ti, dan di sisi AMD, 7970 (kartu rasio 1/4) , serta R9 290 dan R9 290X semuanya mengalahkan seri R9 Fury. Bandingkan dengan versi presisi tunggal dari benchmark , di mana kartu yang lebih baru semuanya dengan mudah mengungguli pendahulunya.
8bittree
36

Operasi atom

Selain apa yang telah dikatakan orang lain, kerugian spesifik Java dari double(dan long) adalah bahwa penugasan untuk tipe primitif 64-bit tidak dijamin atomik . Dari Spesifikasi Bahasa Jawa, Edisi Java SE 8 , halaman 660 (penekanan ditambahkan):

17.7 Perawatan Non-atomik doubledanlong

Untuk keperluan model memori bahasa pemrograman Java, satu tulisan ke non-volatile longatau doublenilai diperlakukan sebagai dua tulisan terpisah: satu untuk masing-masing setengah 32-bit. Ini dapat menghasilkan situasi di mana utas melihat 32 bit pertama dari nilai 64-bit dari satu penulisan, dan 32 bit kedua dari penulisan lain.

Yuck.

Untuk menghindari hal ini, Anda harus mendeklarasikan variabel 64-bit denganvolatile kata kunci, atau menggunakan bentuk sinkronisasi lain di sekitar penugasan.

Kevin J. Chase
sumber
2
Tidakkah Anda perlu menyinkronkan akses bersamaan ke int dan mengapung untuk mencegah pembaruan yang hilang dan membuatnya mudah berubah untuk mencegah caching yang terlalu banyak? Apakah saya salah dalam berpikir bahwa satu-satunya hal yang mencegah atomitas int / float adalah bahwa mereka tidak pernah dapat mengandung nilai-nilai "campuran" yang tidak seharusnya mereka pegang?
Traubenfuchs
3
@Traubenfuchs Yaitu, memang apa yang dijamin di sana. Istilah yang saya dengar digunakan untuk itu adalah "merobek," dan saya pikir itu menangkap efeknya dengan cukup baik. Model bahasa pemrograman Java menjamin bahwa nilai 32 bit, ketika dibaca, akan memiliki nilai yang dituliskan kepada mereka di beberapa titik. Itu adalah jaminan yang sangat berharga.
Cort Ammon
Poin tentang atomisitas ini sangat penting. Wow, saya sudah lupa tentang fakta penting ini. Kontra-intuitif karena kita mungkin cenderung menganggap primitif sebagai atom pada dasarnya. Tapi bukan atom dalam kasus ini.
Basil Bourque
3

Tampaknya jawaban lain melewatkan satu poin penting: Arsitektur SIMD dapat memproses data lebih sedikit / lebih tergantung jika mereka beroperasi pada doubleatau floatstruct (misalnya, delapan nilai float pada suatu waktu, atau empat nilai ganda pada suatu waktu).

Ringkasan pertimbangan kinerja

  • float mungkin lebih cepat pada CPU tertentu (misalnya, perangkat seluler tertentu).
  • float menggunakan lebih sedikit memori sehingga dalam kumpulan data besar itu dapat secara substansial mengurangi total memori yang dibutuhkan (hard disk / RAM) dan bandwidth yang dikonsumsi.
  • float dapat menyebabkan CPU mengkonsumsi daya lebih sedikit (saya tidak dapat menemukan referensi, tetapi jika tidak memungkinkan setidaknya tampaknya masuk akal) untuk perhitungan presisi tunggal dibandingkan dengan perhitungan presisi ganda.
  • float mengkonsumsi lebih sedikit bandwidth, dan dalam beberapa aplikasi yang penting.
  • Arsitektur SIMD dapat memproses sebanyak dua kali jumlah data yang sama karena biasanya.
  • float menggunakan sebanyak setengah dari memori cache dibandingkan dengan menggandakan.

Ringkasan pertimbangan akurasi

  • Dalam banyak aplikasi floatsudah cukup
  • double toh memiliki presisi yang jauh lebih baik

Pertimbangan kompatibilitas

  • Jika data Anda harus diserahkan ke GPU (misalnya, untuk gim video menggunakan OpenGL atau apa pun rendering API lainnya), format floating point jauh lebih cepat daripada double(itu karena produsen GPU mencoba meningkatkan jumlah inti grafis, dan jadi mereka mencoba untuk menyelamatkan sirkuit sebanyak mungkin di setiap inti, jadi mengoptimalkan untuk floatmemungkinkan untuk membuat GPU dengan lebih banyak inti di dalamnya)
  • GPU lama dan beberapa perangkat seluler tidak dapat menerima doublesebagai format internal (untuk operasi rendering 3D)

Kiat umum

  • Pada prosesor desktop modern (dan mungkin sejumlah besar prosesor seluler) Anda pada dasarnya dapat mengasumsikan menggunakan doublevariabel sementara pada stack memberikan presisi ekstra secara gratis (presisi ekstra tanpa penalti kinerja).
  • Jangan pernah menggunakan presisi lebih dari yang Anda butuhkan (Anda mungkin tidak tahu seberapa presisi yang Anda butuhkan).
  • Kadang-kadang Anda hanya dipaksa oleh rentang nilai (beberapa nilai akan menjadi tak terbatas jika Anda menggunakan float, tetapi mungkin nilai yang terbatas jika Anda menggunakan double)
  • Hanya menggunakan floatatau hanya doublesangat membantu kompiler untuk SIMD-ify instruksi.

Lihat komentar di bawah dari PeterCordes untuk wawasan lebih lanjut.

GameDeveloper
sumber
1
doubletemporaries hanya gratis di x86 dengan FPU x87, bukan dengan SSE2. Auto-vectorizing loop dengan doubletemporaries berarti membongkar floatke double, yang mengambil instruksi tambahan, dan Anda memproses setengah karena banyak elemen per vektor. Tanpa auto-vektorisasi, konversi biasanya dapat terjadi dengan cepat saat memuat atau menyimpan, tetapi itu berarti instruksi tambahan saat Anda mencampur float dan menggandakan ekspresi.
Peter Cordes
1
Pada CPU x86 modern, div dan sqrt lebih cepat untuk float daripada dobel, tetapi hal-hal lain memiliki kecepatan yang sama (tidak termasuk masalah lebar vektor SIMD, atau bandwidth memori / jejak cache tentu saja).
Peter Cordes
@PeterCordes terima kasih telah memperluas beberapa poin. Saya tidak mengetahui perbedaan div dan sqrt
GameDeveloper
0

Terlepas dari alasan lain yang disebutkan:

Jika Anda memiliki data pengukuran, baik itu tekanan, arus, arus, tegangan atau apa pun, ini sering dilakukan dengan perangkat keras yang memiliki ADC.

ADC biasanya memiliki 10 atau 12 bit, 14 atau 16 bit lebih jarang. Tapi mari kita tetap pada bit 16 - jika mengukur sekitar skala penuh, Anda memiliki akurasi 1/65535. Itu berarti perubahan dari 65534/65535 menjadi 65535/65535 hanyalah langkah ini - 1/65535. Itu kira-kira 1.5E-05. Keakuratan float adalah sekitar 1E-07, jadi jauh lebih baik. Itu berarti Anda tidak kehilangan apa pun dengan menggunakan floatuntuk menyimpan data ini.

Jika Anda melakukan perhitungan berlebihan dengan pelampung, Anda berkinerja lebih buruk daripada dengan doublesdalam hal akurasi, tetapi seringkali Anda tidak membutuhkan akurasi itu, karena Anda sering tidak peduli jika Anda baru saja mengukur tegangan 2 V atau 2.00002 V. Demikian pula , jika Anda mengubah tegangan ini menjadi tekanan, Anda tidak peduli jika Anda memiliki 3 bar atau 3,00003 bar.

glglgl
sumber