Desimal melakukan persis apa yang seharusnya dilakukan pada kasus ini, ia memotong sisanya, sehingga kehilangan 1/3 bagian.
Jadi untuk jumlah, desimal lebih baik, tetapi untuk pembagian, float lebih baik, sampai titik tertentu, tentu saja. Maksud saya, menggunakan DECIMAL tidak akan memberi Anda "aritmatika bukti gagal" dengan cara apa pun.
Tes yang sangat bagus. Bertahun-tahun yang lalu, fungsi konversi data C lib sering kali akan menghasilkan banyak perbedaan kecil dalam nilai yang dikonversi dari ASCII menjadi mengambang jika dibandingkan dengan yang ada di, katakanlah, SQLServer. Ini jarang benar lagi. Pengujian adalah kebijakan terbaik, karena yang terbaik adalah mengetahui dengan pasti apa trade-off-nya.
15
Sebenarnya, penambahan DECIMAL salah. Jika Anda menambahkan 33.333333333 tiga kali Anda tidak mendapatkan 100. Jika Anda membagi 100 dengan 3 Anda tidak mendapatkan angka rasional tanpa satu set berulang angka trailing, sehingga Anda tidak dapat melipatgandakannya dengan 3 dan mendapatkan 100. Keluar kalkulator dan coba. Secara logis kita tahu 1/3 + 1/3 + 1/3 harus sama dengan 3 / 3rds IE: 1, tetapi kelas nomor rasional ini tidak memungkinkan kita untuk melakukan ini. Jawaban float sudah benar, tetapi akuntan Anda akan BENCI !
user2548100
5
Bukankah @amemberi 99,999999999000000000000000000000 DECIMAL? Yang secara teknis benar.
Vincent Poirier
78
"Float" di sebagian besar lingkungan adalah tipe floating-point biner. Ia dapat secara akurat menyimpan nilai-nilai basis-2 (ke titik tertentu), tetapi tidak dapat secara akurat menyimpan banyak nilai-nilai basis-10 (desimal). Mengapung paling tepat untuk perhitungan ilmiah. Mereka tidak cocok untuk sebagian besar matematika berorientasi bisnis, dan penggunaan float yang tidak tepat akan menggigit Anda. Banyak nilai desimal tidak dapat direpresentasikan secara tepat di basis-2. 0.1tidak bisa, misalnya, dan Anda melihat hasil aneh seperti 1.0 - 0.1 = 0.8999999.
Desimal menyimpan nomor basis-10. Desimal adalah tipe yang baik untuk sebagian besar matematika bisnis (tetapi tipe "uang" bawaan apa pun lebih tepat untuk perhitungan keuangan), di mana rentang nilai melebihi yang disediakan oleh tipe integer, dan nilai fraksional diperlukan. Desimal, seperti namanya, dirancang untuk nomor basis-10 - mereka dapat secara akurat menyimpan nilai desimal (sekali lagi, ke titik tertentu).
@Michael Petrotta - pengguna hanya memasukkan angka desimalnya di bidang yang diberikan dalam bentuk .. saya hanya perlu menyimpannya dalam DB. mana yang akan lebih cocok. ?
Peretas
12
@Pradeep: Saya merasa Anda tidak menjawab pertanyaan saya. Itu mungkin karena Anda sendiri tidak tahu jawabannya - mungkin Anda merasa tidak nyaman untuk bertanya lebih lanjut kepada manajer atau pelanggan Anda. Jika itu masalahnya, saya sarankan menggigit peluru, duduk bersama mereka selama beberapa jam, dan benar-benar berjalan melalui aplikasi Anda. Apa tepatnya , dan dengan sangat terperinci , untuk apa data Anda digunakan?
Michael Petrotta
1
Sebenarnya, saat ini keduanya float dan DECIMAL menyimpan nomor mereka dengan cara yang sama. Perbedaannya terletak pada bagaimana angka-angka itu digunakan. DECIMAL menggunakan semua bit untuk membentuk integer komplemen dua, dengan titik desimal tersirat. Sebuah pelampung memiliki dua bilangan bulat dan satu mengangkat yang lain ke daya. Basis dan eksponen adalah bilangan bulat pelengkap dua.
user2548100
1
Saya pikir jawaban Anda mungkin benar secara teknis, tetapi penekanan pada float menjadi tipe biner mengaburkan titik bahwa mereka berdua menyimpan data mereka dalam format yang sama. Angka floating point dinaikkan ke kekuatan pertama adalah bilangan bulat, dan disimpan persis seperti itu. Bahkan, untuk float presisi 80-bit, basisnya adalah int64. Sebaliknya, jika Anda menulis perpustakaan untuk bilangan bulat yang menaikkannya menjadi kekuatan, Anda akan mengalami masalah yang sama dengan bilangan bulat, atau DECIMALS, atau Angka Romawi, atau lolipop. Bukan penyimpanan yang menciptakan "kesalahan pembulatan", melainkan penanganan perpustakaan terhadap matematika.
user2548100
1
Mengingat kualitas pertanyaan yang sangat buruk, di mana hampir tidak ada parameter yang diberikan untuk menunjukkan apa yang menjadi bidang perhatian OP, sulit untuk mengetahui apa tanggapan yang sesuai. Secara umum DECIMAL akan menyimpan angka yang lebih besar dan lib matematika memenuhi harapan akuntan, sedangkan float ganda adalah media penyimpanan yang kurang efisien yang telah mengoptimalkan lib matematika secara besar-besaran - yang memenuhi harapan para ilmuwan dan keuangan (bukan akuntan) jauh lebih baik.
user2548100
21
MySQL baru-baru ini mengubah cara mereka menyimpan jenis DECIMAL . Di masa lalu mereka menyimpan karakter (atau nybbles) untuk setiap digit yang terdiri dari representasi ASCII (atau nybble) dari angka - vs - integer komplemen dua, atau turunannya.
Format penyimpanan saat ini untuk DECIMAL adalah serangkaian bilangan bulat 1,2,3, atau 4 byte yang bitnya digabungkan untuk membuat angka komplemen dua dengan titik desimal tersirat, ditentukan oleh Anda, dan disimpan dalam skema DB saat Anda mendeklarasikan kolom dan tentukan ukuran DECIMAL dan posisi titik desimal.
Sebagai contoh, jika Anda mengambil int 32-bit Anda dapat menyimpan nomor dari 0 - 4.294.967.295. Itu hanya akan mencakup 999.999.999, jadi jika Anda membuang 2 bit dan menggunakan (1 << 30 -1) Anda tidak akan menyerah. Menutupi semua angka 9 digit dengan hanya 4 byte lebih efisien daripada mencakup 4 digit dalam 32 bit menggunakan 4 karakter ASCII, atau 8 digit nybble. (Nybble adalah 4-bit, memungkinkan nilai 0-15, lebih dari yang diperlukan untuk 0-9, tetapi Anda tidak dapat menghilangkan limbah itu dengan pergi ke 3 bit, karena itu hanya mencakup nilai 0-7)
Contoh yang digunakan pada dokumen online MySQL menggunakan DECIMAL (18,9) sebagai contoh. Ini adalah 9 digit di depan dan 9 digit di belakang titik desimal tersirat, yang seperti dijelaskan di atas membutuhkan penyimpanan berikut.
Sebagai 18 karakter 8-bit: 144 bit
Sebagai 18 4-bit nybbles: 72 bit
Sebagai 2 bilangan bulat 32-bit: 64 bit
Saat ini DECIMAL mendukung maksimal 65 digit, karena DECIMAL (M, D) dengan nilai M terbesar yang diizinkan adalah 65, dan nilai D terbesar yang diizinkan adalah 30.
Agar tidak membutuhkan potongan 9 digit sekaligus, bilangan bulat yang lebih kecil dari 32-bit digunakan untuk menambahkan angka menggunakan bilangan bulat 1,2 dan 3 byte. Untuk beberapa alasan yang menentang logika, bertanda tangan, bukan int unsigned yang digunakan, dan dengan demikian, 1 bit dibuang, menghasilkan kemampuan penyimpanan berikut. Untuk int 1,2 dan 4 byte, bit yang hilang tidak masalah, tetapi untuk int 3-byte itu adalah bencana karena seluruh digit hilang karena hilangnya bit tunggal itu.
Dengan int 7-bit: 0 - 99
Dengan int 15-bit: 0 - 9.999
Dengan int 23-bit: 0 - 999.999 (0 - 9.999.999 dengan int 24-bit)
Bilangan bulat 1,2,3 dan 4-byte digabungkan bersama untuk membentuk "bit pool" yang digunakan DECIMAL untuk merepresentasikan angka tepat sebagai bilangan bulat pelengkap dua. Titik desimal TIDAK disimpan, itu tersirat.
Ini berarti bahwa tidak diperlukan konversi ASCII ke int dari mesin DB untuk mengubah "angka" menjadi sesuatu yang CPU akui sebagai suatu angka. Tanpa pembulatan, tidak ada kesalahan konversi, ini adalah angka nyata yang dapat dimanipulasi CPU.
Penghitungan pada bilangan bulat besar yang sewenang-wenang ini harus dilakukan dalam perangkat lunak, karena tidak ada dukungan perangkat keras untuk nomor seperti ini, tetapi pustaka ini sangat tua dan sangat dioptimalkan, yang telah ditulis 50 tahun yang lalu untuk mendukung data titik mengambang presisi IBM 370 Fortran yang sewenang-wenang . Mereka masih jauh lebih lambat daripada aljabar integer berukuran tetap yang dilakukan dengan perangkat keras integer CPU, atau perhitungan floating point yang dilakukan pada FPU.
Dalam hal efisiensi penyimpanan, karena eksponen float melekat pada masing-masing dan setiap float, menentukan secara implisit di mana titik desimal berada, ia berlebihan secara berlebihan, dan karenanya tidak efisien untuk pekerjaan DB. Dalam DB, Anda sudah tahu di mana titik desimal berada di depan, dan setiap baris dalam tabel yang memiliki nilai untuk kolom DECIMAL hanya perlu melihat spesifikasi 1 & hanya di mana titik desimal itu ditempatkan, disimpan dalam skema sebagai argumen untuk DECIMAL (M, D) sebagai implikasi dari nilai M dan D.
Banyak komentar yang ditemukan di sini tentang format mana yang akan digunakan untuk berbagai jenis aplikasi yang benar, jadi saya tidak akan mengulangi intinya. Saya meluangkan waktu untuk menulis ini di sini karena siapa pun yang memelihara dokumentasi online MySQL yang ditautkan tidak mengerti hal-hal di atas dan setelah putaran-putaran upaya yang semakin membuat frustrasi untuk menjelaskannya kepada mereka, saya menyerah. Indikasi yang baik tentang betapa buruknya mereka memahami apa yang mereka tulis adalah presentasi materi pelajaran yang sangat kacau dan hampir tidak dapat dipahami.
Sebagai pemikiran terakhir, jika Anda membutuhkan perhitungan floating point presisi tinggi, telah ada kemajuan luar biasa dalam kode floating point dalam 20 tahun terakhir, dan dukungan perangkat keras untuk float 96-bit dan Quadruple Precision tepat di tikungan, tetapi ada pustaka presisi arbitrer yang baik di luar sana jika manipulasi nilai yang disimpan itu penting.
Saya percaya pada arsitektur Intel Hazwell ada operasi AVX-2 pada bilangan bulat 256bit, yang mencakup setiap nilai yang mungkin mewakili 77 digit, yang dapat digunakan untuk langsung beroperasi pada bilangan bulat presisi DECIMAL yang diperluas. Ini mungkin terbukti bijaksana bagi Oracle untuk mendukung bentuk baru DECIMAL di masa depan yang mencakup 77 digit vs 65. Saya akan memperkirakan peningkatan kinerja 5-10X menggunakan perangkat keras dan bukan perangkat lunak. 2 ^ 256 = 115.779.089.237.316.195.442.570.985.008.687.907.853.269.984.665.640.564.039.457.584.007.913.129, 639.936 (78 digit)
Prosesor vektor Intel sekarang mendukung operasi matematika 512 bit. Ini akan mencakup 154 digit. 2 ^ 512 = 13.407.807.929.942.597.099.574.024.998.205.846.127.479.365.820.592.393.377.723.561.443.721.764.030.073.546.976.801.874.298.166.903.427.690.031.858.186.486.050.853.753.882.811.946.569.946.433.649.006.084.096 (155 digit)
13
Tidak hanya khusus untuk MySQL, perbedaan antara float dan tipe desimal adalah cara mereka mewakili nilai fraksional. Tipe floating point mewakili fraksi dalam biner, yang hanya bisa mewakili nilai sebagai {m*2^n | m, n Integers}. nilai-nilai seperti 1/5 tidak dapat direpresentasikan secara tepat (tanpa kesalahan pembulatan). Angka desimal juga terbatas, tetapi mewakili angka seperti {m*10^n | m, n Integers}. Desimal masih tidak dapat mewakili angka seperti 1/3, tetapi sering terjadi di banyak bidang umum, seperti keuangan, harapannya adalah bahwa pecahan desimal tertentu selalu dapat dinyatakan tanpa kehilangan kesetiaan. Karena angka desimal dapat mewakili nilai seperti $0.20(seperlima dolar), maka lebih disukai dalam situasi tersebut.
Karena prosesor Intel melakukan semua operasi float ganda antara dalam presisi 80 bit, hampir tanpa kecuali tidak ada kesalahan pembulatan ketika hasil akhir dipangkas kembali dari 80 bit menjadi 64 bit. Bahkan banyak pustaka perangkat lunak floating point dapat menangani ini dan ratusan anomali aritmatika lainnya. Teori dan praktik dengan demikian sangat berbeda di bidang ini.
9
desimal adalah untuk jumlah tetap seperti uang di mana Anda ingin jumlah tempat desimal tertentu. Mengapung adalah untuk menyimpan ... angka presisi titik apung.
Secara umum, nilai Float baik untuk Perhitungan ilmiah, tetapi tidak boleh digunakan untuk Nilai Keuangan / Moneter. Untuk Matematika Berorientasi Bisnis, selalu gunakan Desimal.
mysql>CREATETABLE num(id int ,fl float,dc dec(5,2));
Query OK,0rows affected (0.00 sec)
mysql>INSERTINTO num VALUES(1,13.75,13.75);
Query OK,1row affected (0.00 sec)
mysql>INSERTINTO num VALUES(2,13.15,13.15);
Query OK,1row affected (0.00 sec)
mysql>SELECT*FROM num WHERE fl =13.15;
Empty set(0.00 sec)
mysql>SELECT*FROM num WHERE dc =13.15;+------+-------+-------+| id | fl | dc |+------+-------+-------+|2|13.15|13.15|+------+-------+-------+1rowinset(0.00 sec)
mysql>SELECT SUM(fl),SUM(dc)FROM num;+--------------------+---------+| SUM(fl)| SUM(dc)|+--------------------+---------+|26.899999618530273|26.90|+--------------------+---------+1rowinset(0.00 sec)
mysql>SELECT*FROM num WHERE ABS(fl -13.15)<0.01;+------+-------+-------+| id | fl | dc |+------+-------+-------+|2|13.15|13.15|+------+-------+-------+1rowinset(0.00 sec)
Tipe Floating-Point (Nilai Perkiraan) - FLOAT, GANDA
Tipe FLOAT dan DOUBLE mewakili perkiraan nilai data numerik. MySQL menggunakan empat byte untuk nilai presisi tunggal dan delapan byte untuk nilai presisi ganda.
Untuk FLOAT, standar SQL memungkinkan spesifikasi opsional dari presisi (tetapi bukan kisaran eksponen) dalam bit mengikuti kata kunci FLOAT dalam tanda kurung. MySQL juga mendukung spesifikasi presisi opsional ini, tetapi nilai presisi hanya digunakan untuk menentukan ukuran penyimpanan. Ketelitian dari 0 hingga 23 menghasilkan kolom FLOAT presisi tunggal 4-byte. Sebuah presisi dari 24 hingga 53 menghasilkan kolom DOUBLE presisi ganda 8-byte.
MySQL mengizinkan sintaksis yang tidak standar: FLOAT (M, D) atau REAL (M, D) atau PRECISION GANDA (M, D). Di sini, "(M, D)" berarti daripada nilai-nilai dapat disimpan dengan total hingga M digit, di mana angka D mungkin setelah titik desimal. Misalnya, kolom yang didefinisikan sebagai FLOAT (7,4) akan terlihat seperti -999.9999 saat ditampilkan. MySQL melakukan pembulatan saat menyimpan nilai, jadi jika Anda memasukkan 999.00009 ke dalam kolom FLOAT (7,4), hasil perkiraannya adalah 999.0001.
Karena nilai floating-point adalah perkiraan dan tidak disimpan sebagai nilai yang tepat, upaya untuk memperlakukannya sebagai tepat dalam perbandingan dapat menyebabkan masalah. Mereka juga tergantung pada platform atau dependensi implementasi.
Untuk portabilitas maksimum, kode yang membutuhkan penyimpanan perkiraan nilai data numerik harus menggunakan FLOAT atau DOUBLE PRECISION tanpa spesifikasi presisi atau jumlah digit.
Angka floating-point terkadang menyebabkan kebingungan karena mereka perkiraan dan tidak disimpan sebagai nilai yang tepat . Nilai floating-point sebagaimana ditulis dalam pernyataan SQL mungkin tidak sama dengan nilai yang diwakili secara internal. Upaya untuk memperlakukan nilai floating-point sebagai tepat dalam perbandingan dapat menyebabkan masalah. Mereka juga tergantung pada platform atau dependensi implementasi. Tipe data FLOAT dan DOUBLE tunduk pada masalah ini. Untuk kolom DECIMAL, MySQL melakukan operasi dengan ketepatan 65 angka desimal, yang seharusnya memecahkan masalah ketidaktepatan paling umum.
Contoh berikut ini menggunakan DOUBLE untuk menunjukkan bagaimana perhitungan yang dilakukan menggunakan operasi titik-mengambang tunduk pada kesalahan titik-mengambang.
mysql>CREATETABLE t1 (i INT, d1 DOUBLE, d2 DOUBLE);
mysql>INSERTINTO t1 VALUES(1,101.40,21.40),(1,-80.00,0.00),->(2,0.00,0.00),(2,-13.20,0.00),(2,59.60,46.40),->(2,30.40,30.40),(3,37.00,7.40),(3,-29.60,0.00),->(4,60.00,15.40),(4,-10.60,0.00),(4,-34.00,0.00),->(5,33.00,0.00),(5,-25.80,0.00),(5,0.00,7.20),->(6,0.00,0.00),(6,-51.40,0.00);
mysql>SELECT i, SUM(d1)AS a, SUM(d2)AS b->FROM t1 GROUPBY i HAVING a <> b;+------+-------+------+| i | a | b |+------+-------+------+|1|21.4|21.4||2|76.8|76.8||3|7.4|7.4||4|15.4|15.4||5|7.2|7.2||6|-51.4|0|+------+-------+------+
Hasilnya benar. Meskipun lima catatan pertama terlihat seperti mereka tidak harus memenuhi perbandingan (nilai a dan b tampaknya tidak berbeda), mereka dapat melakukannya karena perbedaan antara angka muncul di sekitar desimal kesepuluh atau lebih, tergantung pada faktor. seperti arsitektur komputer atau versi kompiler atau tingkat optimisasi. Sebagai contoh, CPU yang berbeda dapat mengevaluasi angka floating-point secara berbeda.
Jika kolom d1 dan d2 telah didefinisikan sebagai DECIMAL daripada DOUBLE, hasil dari query SELECT hanya akan berisi satu baris — yang terakhir ditunjukkan di atas.
Cara yang benar untuk melakukan perbandingan angka floating-point adalah pertama-tama memutuskan toleransi yang dapat diterima untuk perbedaan antara angka-angka dan kemudian melakukan perbandingan terhadap nilai toleransi. Sebagai contoh, jika kita sepakat bahwa angka floating-point harus dianggap sama jika mereka sama dalam presisi satu dalam sepuluh ribu (0,0001), perbandingan harus ditulis untuk menemukan perbedaan yang lebih besar daripada nilai toleransi:
mysql>SELECT i, SUM(d1)AS a, SUM(d2)AS b FROM t1->GROUPBY i HAVING ABS(a - b)>0.0001;+------+-------+------+| i | a | b |+------+-------+------+|6|-51.4|0|+------+-------+------+1rowinset(0.00 sec)
Sebaliknya, untuk mendapatkan baris dengan angka yang sama, tes harus menemukan perbedaan dalam nilai toleransi:
mysql>SELECT i, SUM(d1)AS a, SUM(d2)AS b FROM t1->GROUPBY i HAVING ABS(a - b)<=0.0001;+------+------+------+| i | a | b |+------+------+------+|1|21.4|21.4||2|76.8|76.8||3|7.4|7.4||4|15.4|15.4||5|7.2|7.2|+------+------+------+5rowsinset(0.03 sec)
Nilai floating-point tergantung pada platform atau dependensi implementasi. Misalkan Anda menjalankan pernyataan berikut:
Pada beberapa platform, pernyataan SELECT mengembalikan inf dan -inf. Pada yang lain, ia mengembalikan 0 dan -0.
Implikasi dari masalah sebelumnya adalah bahwa jika Anda mencoba untuk membuat budak replikasi dengan membuang konten tabel dengan mysqldump pada master dan memuat kembali file dump ke dalam slave, tabel yang berisi kolom titik-mengambang mungkin berbeda antara dua host.
Jika yang perlu Anda lakukan adalah menambah, mengurangi atau mengalikan angka yang Anda simpan, DECIMAL adalah yang terbaik.
Jika Anda perlu membagi atau melakukan bentuk aritmatika atau aljabar apa pun pada data, Anda hampir pasti akan lebih bahagia dengan float. Pustaka floating point, dan pada prosesor Intel, prosesor floating point itu sendiri, memiliki TON operasi untuk memperbaiki, memperbaiki, mendeteksi dan menangani badai salju pengecualian yang terjadi ketika melakukan fungsi matematika yang khas - terutama fungsi transendental.
Sedangkan untuk keakuratan, saya pernah menulis sistem anggaran yang menghitung% kontribusi dari masing-masing 3.000+ akun, untuk 3.600 unit anggaran, per bulan ke simpul konsolidasi unit itu, kemudian berdasarkan pada matriks persentase (3.000 + x 12 x 3.600) Saya mengalikan jumlah yang dianggarkan oleh node organisasi tertinggi hingga 3 level berikutnya dari node organisasi, dan kemudian menghitung semua (3.000 + 12) nilai untuk semua 3.200 unit detail dari itu. Jutaan dan jutaan perhitungan floating point presisi ganda, yang salah satunya akan membuang roll-up semua proyeksi tersebut dalam konsolidasi bottom-up kembali ke level tertinggi dalam organisasi.
Kesalahan total floating point setelah semua perhitungan itu adalah NOL . Itu pada tahun 1986, dan perpustakaan floating point saat ini jauh, jauh lebih baik daripada sebelumnya. Intel mengerjakan semua perhitungan menengahnya dengan ketepatan ganda dalam 80 bit, yang semuanya menghilangkan kesalahan pembulatan. Ketika seseorang memberi tahu Anda "itu kesalahan floating point" hampir pasti TIDAK benar.
FLOAT(m,n)
, itu mengarah ke dua pembulatan; sementara itu, tidak ada gunanya digunakan.Jawaban:
Inilah yang saya temukan ketika saya memiliki keraguan ini.
Desimal melakukan persis apa yang seharusnya dilakukan pada kasus ini, ia memotong sisanya, sehingga kehilangan 1/3 bagian.
Jadi untuk jumlah, desimal lebih baik, tetapi untuk pembagian, float lebih baik, sampai titik tertentu, tentu saja. Maksud saya, menggunakan DECIMAL tidak akan memberi Anda "aritmatika bukti gagal" dengan cara apa pun.
Semoga ini membantu.
sumber
@a
memberi 99,999999999000000000000000000000 DECIMAL? Yang secara teknis benar."Float" di sebagian besar lingkungan adalah tipe floating-point biner. Ia dapat secara akurat menyimpan nilai-nilai basis-2 (ke titik tertentu), tetapi tidak dapat secara akurat menyimpan banyak nilai-nilai basis-10 (desimal). Mengapung paling tepat untuk perhitungan ilmiah. Mereka tidak cocok untuk sebagian besar matematika berorientasi bisnis, dan penggunaan float yang tidak tepat akan menggigit Anda. Banyak nilai desimal tidak dapat direpresentasikan secara tepat di basis-2.
0.1
tidak bisa, misalnya, dan Anda melihat hasil aneh seperti1.0 - 0.1 = 0.8999999
.Desimal menyimpan nomor basis-10. Desimal adalah tipe yang baik untuk sebagian besar matematika bisnis (tetapi tipe "uang" bawaan apa pun lebih tepat untuk perhitungan keuangan), di mana rentang nilai melebihi yang disediakan oleh tipe integer, dan nilai fraksional diperlukan. Desimal, seperti namanya, dirancang untuk nomor basis-10 - mereka dapat secara akurat menyimpan nilai desimal (sekali lagi, ke titik tertentu).
sumber
MySQL baru-baru ini mengubah cara mereka menyimpan jenis DECIMAL . Di masa lalu mereka menyimpan karakter (atau nybbles) untuk setiap digit yang terdiri dari representasi ASCII (atau nybble) dari angka - vs - integer komplemen dua, atau turunannya.
Format penyimpanan saat ini untuk DECIMAL adalah serangkaian bilangan bulat 1,2,3, atau 4 byte yang bitnya digabungkan untuk membuat angka komplemen dua dengan titik desimal tersirat, ditentukan oleh Anda, dan disimpan dalam skema DB saat Anda mendeklarasikan kolom dan tentukan ukuran DECIMAL dan posisi titik desimal.
Sebagai contoh, jika Anda mengambil int 32-bit Anda dapat menyimpan nomor dari 0 - 4.294.967.295. Itu hanya akan mencakup 999.999.999, jadi jika Anda membuang 2 bit dan menggunakan (1 << 30 -1) Anda tidak akan menyerah. Menutupi semua angka 9 digit dengan hanya 4 byte lebih efisien daripada mencakup 4 digit dalam 32 bit menggunakan 4 karakter ASCII, atau 8 digit nybble. (Nybble adalah 4-bit, memungkinkan nilai 0-15, lebih dari yang diperlukan untuk 0-9, tetapi Anda tidak dapat menghilangkan limbah itu dengan pergi ke 3 bit, karena itu hanya mencakup nilai 0-7)
Contoh yang digunakan pada dokumen online MySQL menggunakan DECIMAL (18,9) sebagai contoh. Ini adalah 9 digit di depan dan 9 digit di belakang titik desimal tersirat, yang seperti dijelaskan di atas membutuhkan penyimpanan berikut.
Sebagai 18 karakter 8-bit: 144 bit
Sebagai 18 4-bit nybbles: 72 bit
Sebagai 2 bilangan bulat 32-bit: 64 bit
Saat ini DECIMAL mendukung maksimal 65 digit, karena DECIMAL (M, D) dengan nilai M terbesar yang diizinkan adalah 65, dan nilai D terbesar yang diizinkan adalah 30.
Agar tidak membutuhkan potongan 9 digit sekaligus, bilangan bulat yang lebih kecil dari 32-bit digunakan untuk menambahkan angka menggunakan bilangan bulat 1,2 dan 3 byte. Untuk beberapa alasan yang menentang logika, bertanda tangan, bukan int unsigned yang digunakan, dan dengan demikian, 1 bit dibuang, menghasilkan kemampuan penyimpanan berikut. Untuk int 1,2 dan 4 byte, bit yang hilang tidak masalah, tetapi untuk int 3-byte itu adalah bencana karena seluruh digit hilang karena hilangnya bit tunggal itu.
Dengan int 7-bit: 0 - 99
Dengan int 15-bit: 0 - 9.999
Dengan int 23-bit: 0 - 999.999 (0 - 9.999.999 dengan int 24-bit)
Bilangan bulat 1,2,3 dan 4-byte digabungkan bersama untuk membentuk "bit pool" yang digunakan DECIMAL untuk merepresentasikan angka tepat sebagai bilangan bulat pelengkap dua. Titik desimal TIDAK disimpan, itu tersirat.
Ini berarti bahwa tidak diperlukan konversi ASCII ke int dari mesin DB untuk mengubah "angka" menjadi sesuatu yang CPU akui sebagai suatu angka. Tanpa pembulatan, tidak ada kesalahan konversi, ini adalah angka nyata yang dapat dimanipulasi CPU.
Penghitungan pada bilangan bulat besar yang sewenang-wenang ini harus dilakukan dalam perangkat lunak, karena tidak ada dukungan perangkat keras untuk nomor seperti ini, tetapi pustaka ini sangat tua dan sangat dioptimalkan, yang telah ditulis 50 tahun yang lalu untuk mendukung data titik mengambang presisi IBM 370 Fortran yang sewenang-wenang . Mereka masih jauh lebih lambat daripada aljabar integer berukuran tetap yang dilakukan dengan perangkat keras integer CPU, atau perhitungan floating point yang dilakukan pada FPU.
Dalam hal efisiensi penyimpanan, karena eksponen float melekat pada masing-masing dan setiap float, menentukan secara implisit di mana titik desimal berada, ia berlebihan secara berlebihan, dan karenanya tidak efisien untuk pekerjaan DB. Dalam DB, Anda sudah tahu di mana titik desimal berada di depan, dan setiap baris dalam tabel yang memiliki nilai untuk kolom DECIMAL hanya perlu melihat spesifikasi 1 & hanya di mana titik desimal itu ditempatkan, disimpan dalam skema sebagai argumen untuk DECIMAL (M, D) sebagai implikasi dari nilai M dan D.
Banyak komentar yang ditemukan di sini tentang format mana yang akan digunakan untuk berbagai jenis aplikasi yang benar, jadi saya tidak akan mengulangi intinya. Saya meluangkan waktu untuk menulis ini di sini karena siapa pun yang memelihara dokumentasi online MySQL yang ditautkan tidak mengerti hal-hal di atas dan setelah putaran-putaran upaya yang semakin membuat frustrasi untuk menjelaskannya kepada mereka, saya menyerah. Indikasi yang baik tentang betapa buruknya mereka memahami apa yang mereka tulis adalah presentasi materi pelajaran yang sangat kacau dan hampir tidak dapat dipahami.
Sebagai pemikiran terakhir, jika Anda membutuhkan perhitungan floating point presisi tinggi, telah ada kemajuan luar biasa dalam kode floating point dalam 20 tahun terakhir, dan dukungan perangkat keras untuk float 96-bit dan Quadruple Precision tepat di tikungan, tetapi ada pustaka presisi arbitrer yang baik di luar sana jika manipulasi nilai yang disimpan itu penting.
sumber
Tidak hanya khusus untuk MySQL, perbedaan antara float dan tipe desimal adalah cara mereka mewakili nilai fraksional. Tipe floating point mewakili fraksi dalam biner, yang hanya bisa mewakili nilai sebagai
{m*2^n | m, n Integers}
. nilai-nilai seperti 1/5 tidak dapat direpresentasikan secara tepat (tanpa kesalahan pembulatan). Angka desimal juga terbatas, tetapi mewakili angka seperti{m*10^n | m, n Integers}
. Desimal masih tidak dapat mewakili angka seperti 1/3, tetapi sering terjadi di banyak bidang umum, seperti keuangan, harapannya adalah bahwa pecahan desimal tertentu selalu dapat dinyatakan tanpa kehilangan kesetiaan. Karena angka desimal dapat mewakili nilai seperti$0.20
(seperlima dolar), maka lebih disukai dalam situasi tersebut.sumber
desimal adalah untuk jumlah tetap seperti uang di mana Anda ingin jumlah tempat desimal tertentu. Mengapung adalah untuk menyimpan ... angka presisi titik apung.
sumber
Saya menemukan ini berguna:
Sumber: http://code.rohitink.com/2013/06/12/mysql-integer-float-decimal-data-types-differences/
sumber
sumber
Jika Anda mengejar kinerja dan tidak presisi, Anda harus mencatat bahwa perhitungan dengan float jauh lebih cepat daripada desimal
sumber
Tipe Floating-Point (Nilai Perkiraan) - FLOAT, GANDA
Tipe FLOAT dan DOUBLE mewakili perkiraan nilai data numerik. MySQL menggunakan empat byte untuk nilai presisi tunggal dan delapan byte untuk nilai presisi ganda.
Untuk FLOAT, standar SQL memungkinkan spesifikasi opsional dari presisi (tetapi bukan kisaran eksponen) dalam bit mengikuti kata kunci FLOAT dalam tanda kurung. MySQL juga mendukung spesifikasi presisi opsional ini, tetapi nilai presisi hanya digunakan untuk menentukan ukuran penyimpanan. Ketelitian dari 0 hingga 23 menghasilkan kolom FLOAT presisi tunggal 4-byte. Sebuah presisi dari 24 hingga 53 menghasilkan kolom DOUBLE presisi ganda 8-byte.
MySQL mengizinkan sintaksis yang tidak standar: FLOAT (M, D) atau REAL (M, D) atau PRECISION GANDA (M, D). Di sini, "(M, D)" berarti daripada nilai-nilai dapat disimpan dengan total hingga M digit, di mana angka D mungkin setelah titik desimal. Misalnya, kolom yang didefinisikan sebagai FLOAT (7,4) akan terlihat seperti -999.9999 saat ditampilkan. MySQL melakukan pembulatan saat menyimpan nilai, jadi jika Anda memasukkan 999.00009 ke dalam kolom FLOAT (7,4), hasil perkiraannya adalah 999.0001.
Karena nilai floating-point adalah perkiraan dan tidak disimpan sebagai nilai yang tepat, upaya untuk memperlakukannya sebagai tepat dalam perbandingan dapat menyebabkan masalah. Mereka juga tergantung pada platform atau dependensi implementasi.
Untuk portabilitas maksimum, kode yang membutuhkan penyimpanan perkiraan nilai data numerik harus menggunakan FLOAT atau DOUBLE PRECISION tanpa spesifikasi presisi atau jumlah digit.
https://dev.mysql.com/doc/refman/5.5/id/floating-point-types.html
Masalah dengan Nilai Floating-Point
Angka floating-point terkadang menyebabkan kebingungan karena mereka perkiraan dan tidak disimpan sebagai nilai yang tepat . Nilai floating-point sebagaimana ditulis dalam pernyataan SQL mungkin tidak sama dengan nilai yang diwakili secara internal. Upaya untuk memperlakukan nilai floating-point sebagai tepat dalam perbandingan dapat menyebabkan masalah. Mereka juga tergantung pada platform atau dependensi implementasi. Tipe data FLOAT dan DOUBLE tunduk pada masalah ini. Untuk kolom DECIMAL, MySQL melakukan operasi dengan ketepatan 65 angka desimal, yang seharusnya memecahkan masalah ketidaktepatan paling umum.
Contoh berikut ini menggunakan DOUBLE untuk menunjukkan bagaimana perhitungan yang dilakukan menggunakan operasi titik-mengambang tunduk pada kesalahan titik-mengambang.
Hasilnya benar. Meskipun lima catatan pertama terlihat seperti mereka tidak harus memenuhi perbandingan (nilai a dan b tampaknya tidak berbeda), mereka dapat melakukannya karena perbedaan antara angka muncul di sekitar desimal kesepuluh atau lebih, tergantung pada faktor. seperti arsitektur komputer atau versi kompiler atau tingkat optimisasi. Sebagai contoh, CPU yang berbeda dapat mengevaluasi angka floating-point secara berbeda.
Jika kolom d1 dan d2 telah didefinisikan sebagai DECIMAL daripada DOUBLE, hasil dari query SELECT hanya akan berisi satu baris — yang terakhir ditunjukkan di atas.
Cara yang benar untuk melakukan perbandingan angka floating-point adalah pertama-tama memutuskan toleransi yang dapat diterima untuk perbedaan antara angka-angka dan kemudian melakukan perbandingan terhadap nilai toleransi. Sebagai contoh, jika kita sepakat bahwa angka floating-point harus dianggap sama jika mereka sama dalam presisi satu dalam sepuluh ribu (0,0001), perbandingan harus ditulis untuk menemukan perbedaan yang lebih besar daripada nilai toleransi:
Sebaliknya, untuk mendapatkan baris dengan angka yang sama, tes harus menemukan perbedaan dalam nilai toleransi:
Nilai floating-point tergantung pada platform atau dependensi implementasi. Misalkan Anda menjalankan pernyataan berikut:
Pada beberapa platform, pernyataan SELECT mengembalikan inf dan -inf. Pada yang lain, ia mengembalikan 0 dan -0.
Implikasi dari masalah sebelumnya adalah bahwa jika Anda mencoba untuk membuat budak replikasi dengan membuang konten tabel dengan mysqldump pada master dan memuat kembali file dump ke dalam slave, tabel yang berisi kolom titik-mengambang mungkin berbeda antara dua host.
https://dev.mysql.com/doc/refman/5.5/id/problems-with-float.html
sumber
Aturan Keras & Cepat
Jika yang perlu Anda lakukan adalah menambah, mengurangi atau mengalikan angka yang Anda simpan, DECIMAL adalah yang terbaik.
Jika Anda perlu membagi atau melakukan bentuk aritmatika atau aljabar apa pun pada data, Anda hampir pasti akan lebih bahagia dengan float. Pustaka floating point, dan pada prosesor Intel, prosesor floating point itu sendiri, memiliki TON operasi untuk memperbaiki, memperbaiki, mendeteksi dan menangani badai salju pengecualian yang terjadi ketika melakukan fungsi matematika yang khas - terutama fungsi transendental.
Sedangkan untuk keakuratan, saya pernah menulis sistem anggaran yang menghitung% kontribusi dari masing-masing 3.000+ akun, untuk 3.600 unit anggaran, per bulan ke simpul konsolidasi unit itu, kemudian berdasarkan pada matriks persentase (3.000 + x 12 x 3.600) Saya mengalikan jumlah yang dianggarkan oleh node organisasi tertinggi hingga 3 level berikutnya dari node organisasi, dan kemudian menghitung semua (3.000 + 12) nilai untuk semua 3.200 unit detail dari itu. Jutaan dan jutaan perhitungan floating point presisi ganda, yang salah satunya akan membuang roll-up semua proyeksi tersebut dalam konsolidasi bottom-up kembali ke level tertinggi dalam organisasi.
Kesalahan total floating point setelah semua perhitungan itu adalah NOL . Itu pada tahun 1986, dan perpustakaan floating point saat ini jauh, jauh lebih baik daripada sebelumnya. Intel mengerjakan semua perhitungan menengahnya dengan ketepatan ganda dalam 80 bit, yang semuanya menghilangkan kesalahan pembulatan. Ketika seseorang memberi tahu Anda "itu kesalahan floating point" hampir pasti TIDAK benar.
sumber
float
(dandouble
) mewakili fraksi binerdecimal
mewakili pecahan desimalsumber
di float ketika menetapkan nilai ke integer print 10 tetapi dalam desimal 11
sumber