Semua ku
berjanggut , kawan!
Kita semua tahu apa itu pembulatan. Jika seseorang lupa, maka pembulatan adalah penggantian angka dengan nilai perkiraannya, ditulis dengan digit signifikan lebih sedikit. Jika Anda bertanya pada seseorang dengan cepat apa yang terjadi ketika Anda membulatkan 6,5 ke bilangan bulat, ia akan menjawab "7" tanpa ragu-ragu. Kami telah diajarkan dari sekolah bahwa angka dibulatkan ke bilangan bulat terdekat, yang nilainya lebih besar. Yaitu, jika dalam bilangan bulat bagian pecahan sama dengan atau lebih dari setengah pembuangan seluruh bagian, maka kami membulatkan bilangan asli ke bilangan terbesar terdekat.
Sederhananya:
6,4 = 6 6,5 = 7 6,6 = 7
dll.
Maka, meninggalkan sekolah dan menjadi programmer, kita sering mengharapkan perilaku yang sama dari bahasa pemrograman kita yang kuat. Melupakan sepenuhnya bahwa di sekolah kita diajarkan “pembulatan matematis”, tetapi sebenarnya ada lebih banyak jenis pembulatan. Di Wikipedia saja,
Anda dapat menggali berapa banyak opsi pembulatan 0,5 ke bilangan bulat terdekat:
- Pembulatan matematika
- Pembulatan acak
- Pembulatan bergantian
- Pembulatan bank
Jenis pertama, "pembulatan matematika," kita semua belajar dari sekolah. Anda dapat membaca tentang tipe kedua dan ketiga di waktu luang Anda, mereka tidak menarik bagi saya dalam artikel ini hari ini.
Tapi "pembulatan perbankan" sudah menarik. "Kenapa?" - kamu bertanya. Di subnet kita sering menggunakan kelas
Konversi , yang menyediakan banyak metode untuk mengkonversi satu tipe data ke yang lain (tidak menjadi bingung dengan para pemain, itu akan dijelaskan di bawah). Dan sekarang, ternyata ketika mengubah angka floating-point (
dobel, float, desimal ) menjadi tipe
int integer melalui metode
Convert.ToInt32, pembulatan “perbankan” bekerja di bawah tenda. Ini digunakan di sini secara default!
Dan sepertinya ketidaktahuan tentang hal sepele ini tidak terlalu memengaruhi pekerjaan Anda, tetapi segera setelah Anda harus bekerja dengan statistik dan menghitung indikator berdasarkan sekelompok semua jenis catatan dan angka hal ini akan keluar ke samping. Karena kami berharap (dari ketidaktahuan) bahwa semua konversi / pembulatan kami dalam perhitungan akan bekerja sesuai dengan aturan pembulatan "matematika". Dan kita terlihat seperti seekor domba jantan di gerbang baru untuk hasil pembulatan
6.5 , yaitu
6 .
Pikiran pertama dari programmer yang melihat ini adalah: "Mungkin pembulatan bekerja pada arah yang berlawanan, dan menurut aturan itu membulatkan ke angka terkecil?", "Mungkin aku lupa sesuatu dari matematika sekolah?". Kemudian dia pergi ke google dan memahami bahwa mereka tidak melupakan apa pun, dan bahwa beberapa jenis massa sedang terjadi. Pada langkah ini, pengembang malas akan memutuskan bahwa ini adalah perilaku standar metode
Convert.ToInt32 , bulat ke bilangan bulat terkecil, dan skor untuk pencarian lebih lanjut. Dan dia akan berpikir bahwa jika
Convert.ToInt32 (6,5) =
6 , maka dengan analogi
Convert.ToInt32 (7,5) =
7 . Tapi itu dia. Di masa depan, pengembang tersebut akan dipukul dengan sekelompok bug dari departemen QA.
Faktanya adalah pembulatan “perbankan” bekerja sedikit lebih rumit - pembulatan angka ke bilangan bulat genap terdekat, dan bukan ke modulo bilangan bulat terdekat. Jenis pembulatan ini seharusnya lebih jujur jika diterapkan dalam operasi perbankan - bank tidak akan mencabut diri mereka sendiri atau klien, dengan asumsi bahwa ada banyak operasi dengan bagian bilangan bulat genap seperti halnya ada operasi dengan bagian bilangan bulat ganjil. Tetapi bagi saya - masih belum jelas :) Jadi itu sebabnya
Convert.ToInt32 (6.5) akan memberikan hasil
6 , dan hasil untuk
Convert.ToInt32 (7.5) akan menjadi
8 , bukan 7 :)
Apa yang harus dilakukan untuk membuat pembulatan "matematis" yang akrab bagi semua orang? Metode
konversi kelas tidak memiliki opsi pembulatan tambahan. Memang benar, karena kelas ini berfungsi terutama bukan untuk pembulatan, tetapi untuk konversi tipe. Kelas
Matematika yang luar biasa dengan metode
Putarannya datang untuk menyelamatkan. Tapi di sini juga hati-hati, karena secara default metode ini berfungsi sama dengan pembulatan di
Convert.ToInt32 () - sesuai dengan aturan "perbankan". Namun, perilaku ini dapat diubah menggunakan argumen kedua, yang merupakan bagian dari metode
Round . Jadi,
Math.Round (someNumber, MidpointRounding.ToEven ) akan memberi kita pembulatan "perbankan" default. Tapi
Math.Round (someNumber, MidpointRounding.AwayFromZero ) akan bekerja sesuai dengan aturan pembulatan "matematika" yang biasa.
Dan omong-omong,
Convert.ToInt32 () tidak menggunakan
System.Math.Round () di bawah tenda. Khusus menggali
implementasi metode ini pada pembulatan github dianggap sesuai dengan residu:
public static int ToInt32(double value) { if (value >= 0) { if (value < 2147483647.5) { int result = (int)value; double dif = value - result; if (dif > 0.5 || dif == 0.5 && (result & 1) != 0) result++; return result; } } else { if (value >= -2147483648.5) { int result = (int)value; double dif = value - result; if (dif < -0.5 || dif == -0.5 && (result & 1) != 0) result--; return result; } } throw new OverflowException(Environment.GetResourceString("Overflow_Int32")); }
Dan akhirnya, beberapa kata tentang
tipe casting :
var number = 6.9; var intNumber = (int)number;
Dalam contoh ini, saya melemparkan tipe floating point (
ganda dalam hal ini) ke integer
int . Jadi, ketika casting ke tipe integer, seluruh bagian non-integer
terpotong . Dengan demikian, dalam contoh ini, variabel "
intNumber " akan
berisi angka
6 . Tidak ada aturan pembulatan di sini, hanya memotong semua yang muncul setelah titik desimal. Ingat ini!
Tautan terkait:
PS Terima kasih kepada Maxim Yakushkin untuk menarik perhatian pada momen implisit ini.
Omong-omong, dalam
python, pembulatan secara default bekerja dengan cara yang sama pada basis "perbankan". Mungkin hal yang sama dalam bahasa Anda, hati-hati dengan angka :)