Apa tipe data terbaik yang digunakan untuk uang dalam C #?

Jawaban:

422

Seperti yang dijelaskan pada desimal sebagai:

Kata kunci desimal menunjukkan tipe data 128-bit. Dibandingkan dengan tipe floating-point, tipe desimal memiliki presisi lebih dan rentang yang lebih kecil, yang membuatnya sesuai untuk perhitungan finansial dan moneter .

Anda dapat menggunakan desimal sebagai berikut:

decimal myMoney = 300.5m;
Lee Treveil
sumber
41
Anda harus menjelaskan apa tentang tautan itu penting. Jawaban harus cukup baik sendiri, dengan tautan sebagai referensi atau detail tambahan. Lihat stackoverflow.com/help/how-to-answer
TheRubberDuck
2
Jadi jawaban panjang minimum bisa lebih sedikit karakter daripada komentar panjang minimum - menarik! Bukannya saya punya masalah dengan jawaban singkat / ringkas, terutama ketika itu juga "dalam" dalam hal itu terkait dengan diskusi lebih lanjut.
B. Clay Shannon
3
Jawaban yang luar biasa, dan saya merasa tidak perlu penjelasan lebih lanjut karena sepenuhnya menjawab pertanyaan. Tautan ke dokumentasi MSDN adalah bonus sejauh yang saya ketahui. Bravo!
trnelson
@Leee Treveil, seperti apa uang itu (9.0098) berarti 4 karakter setelah Poin
SAR
114

Sistem

Tipe nilai desimal mewakili angka desimal mulai dari positif 79.228.162.514.264.333.543.950.335 ke negatif 79.228.162.514.264.333.593.543.950.335. Jenis nilai desimal sesuai untuk perhitungan keuangan yang membutuhkan sejumlah besar angka integral dan fraksional yang signifikan dan tidak ada kesalahan pembulatan. Jenis desimal tidak menghilangkan kebutuhan pembulatan. Sebaliknya, ini meminimalkan kesalahan karena pembulatan.

Saya ingin menunjukkan jawaban yang sangat bagus ini oleh zneak tentang mengapa double tidak boleh digunakan.

David Walschots
sumber
68

Gunakan pola Uang dari Pola Arsitektur Aplikasi Perusahaan ; tentukan jumlah sebagai desimal dan mata uang sebagai enum.

lmsasu
sumber
2
Saya sebenarnya akan menyarankan ini, tetapi saya membuat Mata Uang kelas sehingga saya dapat menentukan nilai tukar (dalam kaitannya dengan "mata uang dasar", seringkali dolar AS [yang saya tetapkan memiliki nilai tukar 1,00]).
Thomas Owens
5
Untuk pengunjung masa depan dari utas ini (seperti saya), sekarang ada ini: nuget.org/packages/Money and it rock!
Korijn
Ingin tahu apakah tipe seperti itu harus berupa struct atau kelas. Sebuah desimal + an (int) enum membuatnya menjadi 20 byte. Uang saya masih dalam struct.
nawfal
Yang Moneynuget memiliki github dead link untuk lokasi proyek sehingga ... tidak ada docs?
George Mauer
Masalah dengan ini adalah jika Anda membuat implementasi Anda sendiri, Anda harus mencari cara untuk benar-benar bertahan. Dan ORM (EF) paling populer tidak memiliki dukungan sama sekali untuk tipe data khusus. Oleh karena itu seseorang diminta untuk benar-benar tenggelam dalam rumput liar untuk melakukan apa yang seharusnya menjadi hal yang sangat mudah.
George Mauer
25

Desimal. Jika Anda memilih dua kali lipat, Anda membiarkan diri Anda terbuka terhadap kesalahan pembulatan

SquidScareMe
sumber
8
@ Jean doubledapat memperkenalkan kesalahan pembulatan karena floating point tidak dapat mewakili semua angka dengan tepat (misal 0,01 tidak memiliki representasi yang tepat di floating point). Decimal, Di sisi lain, tidak mewakili angka persis . (Trade-off Decimalmemiliki rentang yang lebih kecil dari floating point) Floating point dapat memberi Anda * kesalahan pembulatan * yang tidak disengaja (misalnya 0.01+0.01 != 0.02). Decimaldapat memberikan Anda kesalahan pembulatan, tetapi hanya ketika Anda memintanya (mis. Math.Round(0.01+0.02)mengembalikan nol)
Ian Boyd
2
@IanBoyd: Nilai "$ 1,57" dapat direpresentasikan dengan tepat (ganda) 157. Jika seseorang menggunakan doubledan dengan hati-hati menerapkan penskalaan dan pembulatan khusus domain bila perlu, itu bisa sangat tepat. Jika seseorang ceroboh dalam pembulatannya, decimaldapat menghasilkan hasil yang secara semantik tidak benar (mis. Jika seseorang menambahkan bersama beberapa nilai yang seharusnya dibulatkan ke sen terdekat, tetapi sebenarnya tidak ada di sekitar mereka terlebih dahulu). Satu-satunya hal yang baik tentang decimalscaling adalah built-in.
supercat,
1
@supercat, mengenai komentar ini "jika seseorang menambahkan bersama beberapa nilai yang seharusnya dibulatkan ke sen terdekat, tetapi tidak benar-benar di sekitar mereka dulu", saya tidak melihat bagaimana float akan menyelesaikan ini. Ini adalah kesalahan pengguna dan tidak ada hubungannya dengan desimal IMHO. saya memang mendapatkan intinya tetapi saya merasa itu salah tempat, terutama karena IanBoyd memang menentukan itu ... jika Anda memintanya.
sawe
13

Setuju dengan pola Uang: Menangani mata uang terlalu rumit ketika Anda menggunakan desimal.

Jika Anda membuat mata uang-kelas, Anda kemudian dapat menempatkan semua logika yang berkaitan dengan uang di sana, termasuk metode ToString () - yang benar, lebih banyak kontrol nilai parsing dan kontrol divisi yang lebih baik.

Juga, dengan kelas Mata Uang, tidak ada peluang untuk secara tidak sengaja menggabungkan uang dengan data lain.

Lennaert
sumber
10

Pilihan lain (terutama jika Anda menggulirkan kelas Anda sendiri) adalah menggunakan int atau int64, dan menunjuk empat digit yang lebih rendah (atau mungkin bahkan 2) sebagai "kanan titik desimal". Jadi "di tepi" Anda akan membutuhkan "* 10.000" di jalan masuk dan beberapa "/ 10000" di jalan keluar. Ini adalah mekanisme penyimpanan yang digunakan oleh Microsoft SQL Server, lihat http://msdn.microsoft.com/en-au/library/ms179882.aspx

Inti dari ini adalah bahwa semua penjumlahan Anda dapat dilakukan menggunakan aritmatika integer (cepat).

dsz
sumber
7

Sebagian besar aplikasi yang pernah saya gunakan digunakan decimaluntuk mewakili uang. Ini didasarkan pada asumsi bahwa aplikasi tidak akan pernah peduli dengan lebih dari satu mata uang.

Asumsi ini mungkin didasarkan pada asumsi lain, bahwa aplikasi tidak akan pernah digunakan di negara lain dengan mata uang yang berbeda. Saya telah melihat kasus yang terbukti salah.

Sekarang asumsi sedang ditantang dengan cara baru: Mata uang baru seperti Bitcoin menjadi lebih umum, dan mereka tidak spesifik untuk negara mana pun. Bukanlah tidak realistis bahwa aplikasi yang digunakan di satu negara saja mungkin masih perlu mendukung banyak mata uang.

Beberapa orang akan mengatakan bahwa membuat atau bahkan menggunakan jenis hanya untuk uang adalah "pelapisan emas," atau menambahkan kompleksitas tambahan di luar persyaratan yang diketahui. Saya sangat tidak setuju. Semakin banyak konsep ada di dalam domain Anda, semakin penting untuk membuat upaya yang masuk akal untuk menggunakan abstraksi yang benar di muka. Jika Anda ingin melihat kerumitan, cobalah bekerja di aplikasi yang dulu digunakan decimaldan sekarang ada Currencyproperti tambahan di sebelah setiap decimalproperti.

Jika Anda menggunakan abstraksi yang salah di muka, menggantinya nanti akan lebih berhasil seratus kali. Itu berarti berpotensi memasukkan cacat ke dalam kode yang ada, dan bagian terbaiknya adalah bahwa cacat itu kemungkinan akan melibatkan jumlah uang, transaksi dengan uang, atau apa pun dengan uang.

Dan tidak sulit untuk menggunakan sesuatu selain desimal. Google "jenis uang nuget" dan Anda akan melihat bahwa banyak pengembang telah membuat abstraksi semacam itu (termasuk saya.) Sangat mudah. Ini semudah menggunakan DateTimealih-alih menyimpan tanggal dalam sebuah string.

Scott Hannen
sumber
5

Buat kelas Anda sendiri. Ini terlihat aneh, tetapi tipe .Net tidak memadai untuk menutup mata uang yang berbeda.

Noel Kennedy
sumber