Mengapa pembagian integer di C # mengembalikan integer dan bukan float?

131

Adakah yang tahu mengapa pembagian integer di C # mengembalikan integer dan bukan float? Apa ide di baliknya? (Apakah ini hanya warisan C / C ++?)

Dalam C #:

float x = 13 / 4;   
//== operator is overridden here to use epsilon compare
if (x == 3.0)
   print 'Hello world';

Hasil dari kode ini adalah:

'Hello world'

Sebenarnya, tidak ada yang namanya pembagian bilangan bulat (pembagian menurut definisi adalah operasi yang menghasilkan bilangan rasional, bilangan bulat adalah subset yang sangat kecil.)

BanditoBunny
sumber
46
karena itu integerdivisi bukan floating pointdivisi.
Hunter McMillen
itu memang harus (dalam VB.Net) itu diterapkan secara berbeda dalam cara matematika alami di mana semua hasil operasi divisi adalah bilangan irasional.
BanditoBunny
3
Saya pikir maksud Anda angka rasional . Lihat wikipedia : Membagi dua bilangan bulat dapat menghasilkan sisanya. Untuk melengkapi pembagian sisanya, sistem bilangan diperluas untuk memasukkan pecahan atau bilangan rasional karena mereka lebih umum disebut.
crashmstr
6
Ini adalah alasan saya bukan penggemar "menyalin sintaks" dalam bahasa. Saya berasal dari VB berpikir "C #. NET" bukan "C # seperti C". Kesalahan saya, saya kira, tetapi dalam hal ini saya lebih suka cara VB. Jika mereka mengalami kesulitan menghasilkan kesalahan kompiler saat menggunakan tipe sederhana yang tidak diinisialisasi (Anda bahkan tidak mendapatkan peringatan dalam C) maka mengapa tidak memperingatkan Anda ketika Anda menetapkan divisi integer ke float?
darda

Jawaban:

96

Meskipun umum bagi programmer baru untuk melakukan kesalahan dalam melakukan pembagian integer ketika mereka sebenarnya dimaksudkan untuk menggunakan divisi floating point, dalam praktiknya divisi integer adalah operasi yang sangat umum. Jika Anda berasumsi bahwa orang jarang menggunakannya, dan bahwa setiap kali Anda melakukan pembagian, Anda harus selalu ingat untuk memberikan poin mengambang, Anda salah.

Pertama, pembagian integer sedikit lebih cepat, jadi jika Anda hanya perlu hasil bilangan bulat, Anda ingin menggunakan algoritma yang lebih efisien.

Kedua, ada sejumlah algoritma yang menggunakan pembagian integer, dan jika hasil pembagian selalu merupakan angka floating point Anda akan dipaksa untuk membulatkan hasil setiap waktu. Salah satu contoh dari bagian atas kepala saya adalah mengubah dasar angka. Menghitung setiap digit melibatkan pembagian bilangan bulat bersama dengan sisanya, bukan pembagian titik mengambang dari angka.

Karena alasan-alasan ini (dan yang terkait lainnya), pembagian integer menghasilkan integer. Jika Anda ingin mendapatkan pembagian floating point dari dua bilangan bulat, Anda hanya perlu mengingat untuk memasukkan satu ke double/ float/ decimal.

Melayani
sumber
5
Dalam VB.Net .Net arsitek membuat keputusan lain: / - selalu divisi float, \ - integer divisi, jadi itu semacam tidak konsisten, kecuali jika Anda mempertimbangkan warisan C ++;
BanditoBunny
4
Anda dapat menentukan, pada waktu kompilasi, apakah /operator akan melakukan pembagian integer atau floating point (kecuali jika Anda menggunakan dinamis). Jika sulit bagi Anda untuk mengetahuinya karena Anda melakukan begitu banyak pada satu baris, maka saya sarankan memecah garis itu menjadi beberapa baris sehingga lebih mudah untuk mengetahui apakah operan adalah bilangan bulat atau tipe floating point. Pembaca masa depan dari kode Anda akan sangat menghargainya.
Servy
5
Saya pribadi merasa bermasalah karena saya selalu harus memikirkan variabel apa yang saya bagi, saya hitung sebagai penggunaan yang sia-sia dari perhatian saya.
BanditoBunny
8
@ Pelesl Karena itu akan menjadi perubahan besar untuk melakukan itu yang sejumlah program astronomi akan rusak saya dapat mengatakan dengan penuh keyakinan bahwa itu tidak akan pernah terjadi di C #. Itulah hal yang perlu dilakukan sejak hari 1 dalam bahasa atau tidak sama sekali.
Servy
2
@Ervy: Ada banyak hal seperti itu di C, C ++, dan C #. Secara pribadi, saya pikir C # akan menjadi bahasa yang lebih baik jika ada operator yang berbeda untuk divisi integer dan, untuk menghindari kode yang tidak sah menghasilkan perilaku yang mencengangkan, int/intoperator itu hanya ilegal [dengan diagnostik yang menetapkan bahwa kode harus melakukan operan atau menggunakan operator lain, tergantung pada perilaku mana yang diinginkan]. Jika ada beberapa urutan token lain yang tersedia untuk divisi integer, mungkin saja dapat mengurangi penggunaan /untuk tujuan itu, tetapi saya tidak tahu apa yang praktis.
supercat
77

Lihat spesifikasi C # . Ada tiga jenis operator divisi

  • Divisi integer
  • Divisi titik mengambang
  • Divisi desimal

Dalam kasus Anda, kami memiliki divisi Integer, dengan aturan berikut diterapkan:

Divisi ini membulatkan hasil menjadi nol, dan nilai absolut dari hasilnya adalah bilangan bulat terbesar yang mungkin lebih kecil dari nilai absolut hasil bagi dari dua operan. Hasilnya nol atau positif ketika kedua operan memiliki tanda yang sama dan nol atau negatif ketika kedua operan memiliki tanda yang berlawanan.

Saya pikir alasan mengapa C # menggunakan jenis pembagian ini untuk bilangan bulat (beberapa bahasa mengembalikan hasil mengambang) adalah perangkat keras - divisi bilangan bulat lebih cepat dan lebih sederhana.

Sergey Berezovskiy
sumber
Bahasa mana yang mengembalikan hasil apung? @SergeyBerezovskiy
Ilaria
40

Setiap tipe data mampu membebani setiap operator. Jika pembilang dan penyebutnya bilangan bulat, tipe integer akan melakukan operasi pembagian dan itu akan mengembalikan tipe integer. Jika Anda ingin pembagian titik mengambang, Anda harus memasukkan satu atau lebih angka ke tipe titik mengambang sebelum membaginya. Misalnya:

int x = 13;
int y = 4;
float x = (float)y / (float)z;

atau, jika Anda menggunakan literal:

float x = 13f / 4f;

Perlu diingat, floating point tidak tepat. Jika Anda peduli tentang presisi, gunakan sesuatu seperti tipe desimal.

Steven Doggart
sumber
1
+1 untuk menyebutkan bahwa hanya satu istilah yang perlu mengambang untuk membuat pembagian floating point.
Xynariz
Jelas pernyataan Anda tentang ketepatan adalah hak dalam konteks pembelajaran dan membuatnya tidak rumit untuk dipahami. Karena kita harus seakurat mungkin dalam pekerjaan kita, saya masih ingin mengklarifikasi tentang ketepatan: Menurut IEE 754-1985 Anda BISA mendapatkan hasil yang tepat (meskipun sebagian besar tidak demikian). Anda bisa mendapatkan hasil yang tepat, ketika nilai perhitungan telah disajikan tepat sebelumnya dan hasilnya - hanya berbicara - jumlah kekuatan 2. Meskipun itu bukan praktik terbaik untuk mengandalkan ketepatan dalam kasus-kasus khusus.
L. Monty
Penambahan presisi: Propabilitas untuk mendapatkan hasil yang tepat meningkat secara drastis karena hasilnya mendekati 1 atau -1. Mungkin agak membingungkan bahwa propabilitas ini masih tetap 0 karena ada angka tak terbatas dan jumlah hasil yang terbatas, yang dapat disajikan dengan tepat. :)
L. Monty
1
@ L.Monty terima kasih sudah menceritakannya. Saya telah belajar lebih banyak tentang floating point karena menulis jawaban ini dan poin yang Anda buat adalah adil. Secara teknis, saya masih akan mengatakan bahwa pernyataan saya "floating point tidak tepat" dapat diterima, dalam arti hanya karena sesuatu bisa akurat kadang tidak berarti, secara keseluruhan, tepat. Seperti yang mereka katakan, jam yang rusak tepat dua kali sehari, tapi saya tidak akan pernah menyebut satu instrumen presisi. Saya sebenarnya agak terkejut itulah bagian yang mengganggu Anda lebih dari saran saya bahwa jenis desimal adalah tepat.
Steven Doggart
Desimal tidak tepat, untuk semua alasan yang sama dengan mengapung; hanya saja mengapung adalah basis-2 dan desimal adalah basis-10. Misalnya, tipe desimal tidak dapat secara akurat menyimpan nilai tepat 1/3.
Steven Doggart
11

Karena Anda tidak menggunakan sufiks apa pun, literal 13dan 4ditafsirkan sebagai bilangan bulat:

Manual :

Jika literal tidak memiliki akhiran, ia memiliki pertama jenis ini yang nilainya dapat diwakili: int, uint, long, ulong.

Dengan demikian, karena Anda menyatakan 13sebagai integer, pembagian integer akan dilakukan:

Manual :

Untuk operasi bentuk x / y, resolusi kelebihan operator biner diterapkan untuk memilih implementasi operator tertentu. Operan dikonversi ke tipe parameter dari operator yang dipilih, dan tipe hasilnya adalah tipe pengembalian dari operator.

Operator divisi yang ditentukan sebelumnya tercantum di bawah ini. Semua operator menghitung hasil bagi x dan y.

Divisi integer:

int operator /(int x, int y);
uint operator /(uint x, uint y);
long operator /(long x, long y);
ulong operator /(ulong x, ulong y);

Dan pembulatan terjadi:

Divisi ini membulatkan hasil menjadi nol, dan nilai absolut dari hasilnya adalah bilangan bulat terbesar yang mungkin lebih kecil dari nilai absolut hasil bagi dari dua operan. Hasilnya nol atau positif ketika kedua operan memiliki tanda yang sama dan nol atau negatif ketika kedua operan memiliki tanda yang berlawanan.

Jika Anda melakukan hal berikut:

int x = 13f / 4f;

Anda akan menerima kesalahan kompilator, karena divisi floating-point ( /operator dari13f ) menghasilkan float, yang tidak dapat dilemparkan ke int secara implisit.

Jika Anda ingin divisi menjadi divisi floating-point, Anda harus menjadikan hasilnya sebagai float:

float x = 13 / 4;

Perhatikan bahwa Anda masih akan membagi bilangan bulat, yang secara implisit akan dilemparkan ke float: hasilnya akan menjadi 3.0. Untuk secara eksplisit mendeklarasikan operan sebagai float, menggunakan fakhiran ( 13f, 4f).

CodeCaster
sumber
+1 untuk menjelaskan bahwa Anda dapat memiliki jawabannya sebagai pelampung tetapi masih melakukan pembagian bilangan bulat. Selain itu, cara umum lain yang saya lihat untuk memaksa divisi floating point adalah dengan mengalikan istilah pertama dari divisi dengan 1.0.
Xynariz
8

Ini hanya operasi dasar .

Ingatlah ketika Anda belajar membagi. Pada awalnya kami memecahkan 9/6 = 1 with remainder 3.

9 / 6 == 1  //true
9 % 6 == 3 // true

/ -Operator dalam kombinasi dengan% -operator digunakan untuk mengambil nilai-nilai itu.

L. Monty
sumber
6

Mungkin bermanfaat:

double a = 5.0/2.0;   
Console.WriteLine (a);      // 2.5

double b = 5/2;   
Console.WriteLine (b);      // 2

int c = 5/2;   
Console.WriteLine (c);      // 2

double d = 5f/2f;   
Console.WriteLine (d);      // 2.5
eozten
sumber
Silakan coba tambahkan beberapa penjelasan untuk jawaban Anda
NetStarter
Ungkapan terakhir akan menghasilkan 2.5, bukan 2.
Lasse V. Karlsen
Ya, salah mengeja. Terima kasih.
eozten
4

Hasilnya akan selalu bertipe yang memiliki rentang pembilang dan penyebut yang lebih besar. Pengecualiannya adalah byte dan pendek, yang menghasilkan int (Int32).

var a = (byte)5 / (byte)2;  // 2 (Int32)
var b = (short)5 / (byte)2; // 2 (Int32)
var c = 5 / 2;              // 2 (Int32)
var d = 5 / 2U;             // 2 (UInt32)
var e = 5L / 2U;            // 2 (Int64)
var f = 5L / 2UL;           // 2 (UInt64)
var g = 5F / 2UL;           // 2.5 (Single/float)
var h = 5F / 2D;            // 2.5 (Double)
var i = 5.0 / 2F;           // 2.5 (Double)
var j = 5M / 2;             // 2.5 (Decimal)
var k = 5M / 2F;            // Not allowed

Tidak ada konversi implisit antara tipe floating-point dan tipe desimal, sehingga pembagian di antara mereka tidak diperbolehkan. Anda harus secara eksplisit melemparkan dan memutuskan mana yang Anda inginkan (Desimal memiliki lebih banyak presisi dan rentang yang lebih kecil dibandingkan dengan tipe floating-point).

zm
sumber