Mengapa "f" diperlukan saat mendeklarasikan float?

88

Contoh:

float timeRemaining = 0.58f;

Mengapa fharus ada di akhir nomor ini?

Thomas
sumber
4
Mungkin, karena jika tidak maka akan diperlakukan sebagai double.
Uwe Keim
2
0,58 (tanpa sufiks f) adalah literal tipe double dan seseorang tidak dapat menetapkan nilai ganda ke float, sama seperti seseorang tidak dapat menetapkan nilai int ke string. Namun Anda dapat menetapkan nilai float ke double karena di sini Anda melebarkan (C # secara implisit akan mengonversinya untuk Anda karena tidak ada presisi yang hilang).
Dave New
@AVD Meskipun ini adalah duplikat, judul pertanyaan di atas tidak menghasilkan tautan Anda dalam kemungkinan daftar duplikat. Jadi ini mungkin menambah nilai setidaknya dalam hal kriteria pencarian lebih.
Adam Houldsworth
1
@AdamHouldsworth - semua jalan menuju double & int .
adatapost

Jawaban:

98

Deklarasi float Anda berisi dua bagian:

  1. Ini menyatakan bahwa variabel timeRemainingbertipe float.
  2. Ini memberikan nilai 0.58ke variabel ini.

Masalahnya terjadi di bagian 2.

Sisi kanan dievaluasi dengan sendirinya. Menurut spesifikasi C #, angka yang mengandung titik desimal yang tidak memiliki sufiks diartikan sebagai a double.

Jadi kita sekarang memiliki doublenilai yang ingin kita tetapkan ke tipe variabel float. Untuk melakukan ini, harus ada konversi implisit dari doublemenjadi float. Tidak ada konversi seperti itu, karena Anda mungkin (dan dalam hal ini memang) kehilangan informasi dalam konversi tersebut.

Alasannya adalah nilai yang digunakan oleh compiler sebenarnya bukan 0,58, tetapi nilai floating-point yang paling dekat dengan 0,58, yaitu 0,57999999999999978655962351581366 ... untuk doubledan tepat 0,579999946057796478271484375 untuk float.

Sebenarnya, ftidak diperlukan. Anda dapat menghindari penggunaan fsufiks dengan mentransmisikan nilai ke float:

float timeRemaining = (float)0.58;
Jeffrey Sax
sumber
4
Dua pertanyaan, bagaimana Anda sampai di nomor '0.579999946057796478271484375', dan bagaimana cara (float) 0.58kerjanya? Tadi Anda mengatakan bahwa tidak ada konversi, karena informasi mungkin hilang, lalu kenapa pemeran bisa bekerja?
SexyBeast
9
1. Saya menggunakan kalkulator Windows, yang menggunakan hingga 34 digit. 2. Saya katakan tidak ada konversi implisit . Cast adalah konversi eksplisit, jadi Anda secara eksplisit memberi tahu compiler bahwa Anda menginginkan konversi, dan itu diperbolehkan.
Jeffrey Sax
Menarik ... Saya harap Anda masih memantau postingan ini. Saya diperkenalkan dengan sufiks yang mengalami 'm' sebelumnya untuk webcast yang saya lihat. Bagaimana Anda mendapatkan kalkulator Windows untuk menampilkan 0,58 sebagai nilai float? Saya mencoba beberapa tombol yang sepertinya akan memaksa ini terjadi tetapi tidak ... terus mendapatkan 0,58. Saya harus menghormati orang yang mengetahui peralatannya dengan baik ...
user1585204
Saya memahami keseluruhan F untuk float tetapi mengapa? Ketika Anda mendeklarasikan variabel dideklarasikan sebagai float sehingga ketika dikompilasi harus tahu nilai ini adalah float. Dan ketika Anda menyatakan hal yang sama ganda. Ini tidak masuk akal karena Anda memiliki float myvalue = 2.4; sekarang ketika dikompilasi, kompilator seharusnya sudah tahu float adalah tipe variabel. Apakah saya melewatkan sesuatu? Terima kasih!
Frank G.
@Tokopedia Dua alasan: 1. Ekspresi 2.4diartikan sebagai dobel di tempat lain. 2. Konversi penyempitan implisit (seperti dari ganda menjadi mengambang) tidak diperbolehkan. Jika Anda ingin membuat pengecualian terhadap aturan ini, Anda harus memiliki alasan yang sangat bagus. Menyimpan 1 pukulan kunci sepertinya tidak cukup baik.
Jeffrey Sax
36

Karena ada beberapa jenis numerik yang compiler dapat digunakan untuk mewakili nilai 0.58: float, doubledan decimal. Kecuali Anda setuju dengan kompilator yang memilihkan satu untuk Anda, Anda harus mengerti.

Dokumentasi untuk doublemenyatakan bahwa jika Anda tidak menentukan jenisnya sendiri, kompilator selalu memilih doublejenis literal numerik nyata apa pun:

Secara default, literal numerik nyata di sisi kanan operator penugasan diperlakukan sebagai ganda. Namun, jika Anda ingin bilangan bulat diperlakukan sebagai ganda, gunakan akhiran d atau D.

Menambahkan sufiks fmembuat a float; sufiks dmenciptakan a double; akhiran mmenciptakan a decimal. Semua ini juga bekerja dalam huruf besar.

Namun, ini masih belum cukup untuk menjelaskan mengapa ini tidak dapat dikompilasi:

float timeRemaining = 0.58;

Setengah dari jawaban yang hilang adalah bahwa konversi dari the double 0.58ke float timeRemainingberpotensi kehilangan informasi, sehingga compiler menolak untuk menerapkannya secara implisit. Jika Anda menambahkan cast eksplisit, konversi dilakukan; jika Anda menambahkan fsufiks maka tidak diperlukan konversi. Dalam kedua kasus, kode kemudian akan dikompilasi.

Jon
sumber
tetapi bagaimana bisa menjadi ganda atau desimal jika variabelnya adalah pelampung, saya kehilangan sesuatu
Thomas
@BlazArt Ya, kalimat yang menyatakan kompilator bahkan tidak mencoba memeriksa target penugasan. Alasannya akan terkubur dalam pilihan desain yang dibuat oleh tim penyusun. Saya kira yang terbaik adalah bersikap eksplisit dalam menghadapi kemungkinan kebingungan, atau terlalu mahal untuk repot-repot menerapkan daripada hanya memiliki dua aturan, satu untuk intdan satu untuk double.
Adam Houldsworth
@BlazArt: Baru saja selesai menyempurnakan jawabannya, silakan lihat lagi.
Jon
1
Mengenai kehilangan informasi, dapatkah Anda memberi tahu saya bagaimana pemeran sebenarnya dilakukan, sehubungan dengan format IEEE 754 tempat mereka disimpan? Double memiliki presisi yang lebih tinggi, jadi apakah itu berarti cast dari float ke double akan selalu berfungsi, seperti double a = 0.69f;?
SexyBeast
@Cupidvogel: Ya, spesifikasi menjamin (dalam §6.1.2) bahwa "konversi numerik implisit lainnya tidak pernah kehilangan informasi apa pun", yang antara lain mencakup konversi floatke double.
Jon
2

Masalahnya adalah bahwa .NET, untuk memungkinkan beberapa jenis operasi implisit dilakukan yang melibatkan floatdan double, diperlukan baik secara eksplisit menentukan apa yang harus terjadi dalam semua skenario yang melibatkan operan campuran atau memungkinkan konversi implisit antara jenis yang akan dilakukan dalam satu arah saja; Microsoft memilih untuk mengikuti jejak Java dalam mengizinkan arah yang kadang-kadang lebih menyukai presisi, tetapi sering mengorbankan kebenaran dan umumnya menimbulkan kerumitan.

Dalam hampir semua kasus, mengambil doublenilai yang paling dekat dengan kuantitas numerik tertentu dan menugaskannya ke a floatakan menghasilkan floatnilai yang paling dekat dengan kuantitas yang sama. Ada beberapa kasus sudut, seperti nilai 9.007.199.791.611.905; floatrepresentasi terbaik akan menjadi 9.007.200.328.482.816 (yang dihapus oleh 536.870.911), tetapi memberikan doublerepresentasi terbaik (yaitu 9.007.199.791.611.904) untuk floatmenghasilkan 9.007.199.254.740.992 (yang turun sebesar 536.870.913). Namun secara umum, mengubah doublerepresentasi terbaik dari beberapa kuantitas menjadi floatakan menghasilkan floatrepresentasi terbaik yang mungkin , atau salah satu dari dua representasi yang pada dasarnya sama baiknya.

Perhatikan bahwa perilaku yang diinginkan ini berlaku bahkan pada kondisi ekstrem; misalnya, floatrepresentasi terbaik untuk kuantitas 10 ^ 308 cocok dengan floatrepresentasi yang dicapai dengan mengubah doublerepresentasi terbaik dari kuantitas tersebut. Demikian juga, floatrepresentasi terbaik dari 10 ^ 309 cocok dengan floatrepresentasi yang dicapai dengan mengubah doublerepresentasi terbaik dari kuantitas tersebut.

Sayangnya, konversi ke arah yang tidak memerlukan pemeran eksplisit jarang seakurat itu. Mengonversi floatrepresentasi terbaik dari suatu nilai menjadi doublejarang akan menghasilkan sesuatu yang mendekati doublerepresentasi terbaik dari nilai tersebut, dan dalam beberapa kasus hasilnya mungkin meleset oleh ratusan lipat (mis. Mengubah floatrepresentasi terbaik dari 10 ^ 40 menjadi doubleakan menghasilkan nilai yang membandingkan lebih besar dari doublerepresentasi terbaik 10 ^ 300.

Sayangnya, aturan konversi adalah apa adanya, jadi orang harus hidup dengan menggunakan typecast dan sufiks yang konyol saat mengonversi nilai ke arah "aman", dan berhati-hati dengan typecast implisit ke arah berbahaya yang sering kali akan menghasilkan hasil palsu.

supercat
sumber