Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Praktik terbaik untuk menyimpan bobot dalam database SQL?

Anda mengklaim bahwa ada ketidakakuratan yang melekat dalam angka floating point. Saya pikir ini layak untuk dieksplorasi sedikit terlebih dahulu.

Saat memutuskan sistem angka untuk mewakili angka (baik di selembar kertas, di sirkuit komputer, atau di tempat lain), ada dua terpisah masalah yang perlu dipertimbangkan:

  1. dasarnya; dan

  2. formatnya .

Pilih basis, basis apa pun…

Dibatasi oleh ruang terbatas, seseorang tidak dapat mewakili anggota sewenang-wenang dari kumpulan tak terbatas . Misalnya:tidak peduli berapa banyak kertas yang Anda beli atau seberapa kecil tulisan tangan Anda, selalu mungkin untuk menemukan bilangan bulat yang tidak sesuai dengan ruang yang diberikan (Anda bisa terus menambahkan angka tambahan sampai kertas habis). Jadi, dengan bilangan bulat , kami biasanya membatasi ruang terbatas kami untuk hanya mewakili ruang yang berada dalam interval tertentu—mis. jika kita memiliki ruang untuk tanda positif/negatif dan tiga digit, kita mungkin membatasi diri kita pada interval [-999,+999] .

Setiap non-kosong interval berisi himpunan bilangan real tak terbatas. Dengan kata lain, tidak peduli interval apa yang diambil alih bilangan real —baik itu [-999,+999] , [0,1] , [0.000001,0.000002] atau apa pun—masih ada himpunan real tak terbatas dalam interval itu (satu hanya perlu terus menambahkan digit pecahan (bukan nol))! Oleh karena itu bilangan real arbitrer harus selalu menjadi "dibulatkan" menjadi sesuatu yang bisa direpresentasikan dalam ruang terbatas.

Rangkaian bilangan real yang dapat dinyatakan dalam ruang berhingga bergantung pada sistem bilangan yang digunakan. Dalam (akrab) posisi kami base-10 sistem, ruang terbatas akan cukup untuk setengah (0.510 ) tetapi tidak untuk sepertiga (0.33333…10 ); sebaliknya, dalam posisi (kurang familiar) base-9 sistem, itu adalah sebaliknya (angka yang sama masing-masing 0.44444…9 dan 0.39 ). Konsekuensi dari semua ini adalah beberapa bilangan yang dapat direpresentasikan hanya dengan menggunakan sedikit ruang pada basis posisi-10 (dan karena itu muncul menjadi sangat "bulat" bagi kita manusia), mis. sepersepuluh, sebenarnya membutuhkan sirkuit biner tak terbatas untuk disimpan dengan tepat (dan karenanya tidak tampak sangat "bulat" bagi teman-teman digital kita)! Khususnya, karena 2 adalah faktor dari 10, hal yang sama tidak berlaku sebaliknya:bilangan apa pun yang dapat direpresentasikan dengan biner hingga juga dapat direpresentasikan dengan desimal hingga.

Kami tidak dapat melakukan yang lebih baik untuk kuantitas berkelanjutan. Pada akhirnya jumlah tersebut harus menggunakan representasi terbatas di beberapa sistem angka:itu sewenang-wenang apakah sistem itu kebetulan mudah di sirkuit komputer, di jari manusia, pada sesuatu yang lain atau tidak sama sekali — sistem mana pun yang digunakan, nilainya harus dibulatkan dan karena itu selalu menghasilkan "kesalahan representasi".

Dengan kata lain, bahkan jika seseorang memiliki alat ukur yang sangat akurat (yang secara fisik tidak mungkin), maka pengukuran apa pun yang dilaporkannya sudah dibulatkan ke nomor yang kebetulan sesuai dengan tampilannya (dalam basis apa pun yang digunakannya — biasanya desimal, untuk alasan yang jelas). Jadi, "86,2 oz" tidak pernah benar-benar "86,2 oz " melainkan representasi dari "sesuatu antara 86.1500000... oz dan 86.2499999... oz ". (Sebenarnya, karena pada kenyataannya instrumennya tidak sempurna, yang bisa kami katakan hanyalah bahwa kami memiliki beberapa tingkat kepercayaan bahwa nilai sebenarnya termasuk dalam interval itu—tapi itu pasti menyimpang dari titik di sini).

Tetapi kami dapat melakukan yang lebih baik untuk jumlah yang berbeda . Nilai tersebut bukan "bilangan real arbitrer" dan oleh karena itu tidak ada satu pun di atas yang berlaku untuknya:nilai tersebut dapat direpresentasikan dengan tepat dalam sistem angka di mana mereka didefinisikan—dan memang, seharusnya (karena mengonversi ke sistem angka lain dan memotong ke panjang yang terbatas akan menghasilkan pembulatan ke angka yang tidak tepat). Komputer dapat (tidak efisien) menangani situasi seperti itu dengan mewakili nomor sebagai string:mis. pertimbangkan ASCII atau BCD pengkodean.

Terapkan format…

Karena ini adalah properti dari basis sistem angka (agak arbitrer), apakah suatu nilai tampak "bulat" atau tidak, tidak berpengaruh pada presisinya . Itu pengamatan yang sangat penting , yang bertentangan dengan intuisi banyak orang (dan itulah alasan saya menghabiskan begitu banyak waktu untuk menjelaskan basis numerik di atas).

Sebaliknya presisi ditentukan oleh berapa banyak angka signifikan representasi memiliki . Kami membutuhkan format penyimpanan yang mampu merekam nilai kami ke setidaknya sebanyak mungkin angka penting yang kami anggap benar . Mengambil contoh nilai yang kami anggap benar jika dinyatakan sebagai 86.2 dan 0.0000862 , dua opsi yang paling umum adalah:

  • Titik tetap , di mana jumlah angka penting bergantung pada besarnya :misalnya dalam representasi 5-titik desimal tetap, nilai kami akan disimpan sebagai 86.20000 dan 0.00009 (dan karena itu masing-masing memiliki 7 dan 1 angka presisi yang signifikan). Dalam contoh ini, presisi telah hilang dalam nilai yang terakhir (dan memang, tidak perlu waktu lama bagi kami untuk benar-benar tidak dapat mewakili apa pun penting); dan nilai sebelumnya disimpan presisi palsu , yang merupakan pemborosan ruang terbatas kami (dan memang, tidak perlu waktu lama lagi untuk nilainya menjadi begitu besar sehingga melebihi kapasitas penyimpanan).

    Contoh umum tentang kapan format ini mungkin sesuai adalah untuk sistem akuntansi:jumlah moneter biasanya harus dilacak ke sen terlepas dari besarnya (oleh karena itu kurang presisi diperlukan untuk nilai-nilai kecil, dan lebih presisi diperlukan untuk nilai-nilai besar). Seperti yang terjadi, mata uang biasanya juga dianggap diskrit (uang tidak dapat dibagi), jadi ini juga merupakan contoh yang baik dari situasi di mana basis tertentu (desimal untuk sebagian besar mata uang modern) diinginkan untuk menghindari kesalahan representasi yang dibahas di atas.

  • Titik mengambang , di mana jumlah angka penting konstan terlepas dari besarnya :misalnya dalam representasi desimal 5-angka penting, nilai kita akan disimpan sebagai 86.200 dan 0.000086200 (dan, menurut definisi, memiliki 5 angka presisi yang signifikan kedua kali). Dalam contoh ini, kedua nilai telah disimpan tanpa kehilangan presisi; dan keduanya juga memiliki jumlah yang sama presisi palsu, yang kurang boros (dan karena itu kami dapat menggunakan ruang terbatas kami untuk mewakili rentang nilai yang jauh lebih besar—baik besar maupun kecil).

    Contoh umum tentang kapan format ini mungkin sesuai adalah untuk merekam pengukuran dunia nyata apa pun :ketepatan alat ukur (yang semuanya mengalami sistematis dan random kesalahan) cukup konstan terlepas dari skalanya, jadi, dengan angka penting yang cukup (biasanya sekitar 3 atau 4 digit), sama sekali tidak ada presisi yang hilang bahkan jika perubahan basis menghasilkan pembulatan ke angka yang berbeda .

    Namun seberapa tepat format penyimpanan floating point digunakan oleh komputer kita?

    • Sebuah IEEE754 titik mengambang presisi tunggal (binary32) nomor memiliki 24 bit, atau log10(2) (lebih dari 7) digit, signifikansi—yaitu. memiliki toleransi kurang dari ±0.000006% . Dengan kata lain, itu lebih tepat daripada mengatakan "86.20000 ".

    • IEEE754 titik mengambang presisi ganda (binary64) nomor memiliki 53 bit, atau log10(2) (hampir 16) digit, signifikansi—yaitu. ia memiliki toleransi lebih dari ±0.00000000000001% . Dengan kata lain, ini lebih tepat daripada mengatakan "86.2000000000000 ".

    Yang paling penting untuk disadari adalah bahwa format ini, masing-masing, lebih dari sepuluh ribu dan lebih dari satu triliun kali lebih tepat daripada mengatakan "86,2"—meskipun konversi tepat dari biner kembali ke desimal terjadi untuk menyertakan presisi palsu yang salah (yang harus kita abaikan:lebih lanjut tentang ini segera)!

Perhatikan juga bahwa keduanya memperbaiki dan format floating point akan mengakibatkan hilangnya presisi saat nilai diketahui lebih tepat daripada format yang didukung. kesalahan pembulatan tersebut dapat menyebar dalam operasi aritmatika untuk menghasilkan hasil yang tampaknya salah (yang tidak diragukan lagi menjelaskan referensi Anda ke "ketidakakuratan bawaan" angka floating point):misalnya, 3 × 3000 di titik tetap 5 tempat akan menghasilkan 999.99000 daripada 1000.00000; dan 7 − ⁄50 dalam 5 angka penting floating point akan menghasilkan 0.0028600 daripada 0.0028571 .

Bidang analisis numerik didedikasikan untuk memahami efek ini, tetapi penting untuk menyadari bahwa apa pun sistem yang dapat digunakan (bahkan melakukan perhitungan di kepala Anda) rentan terhadap masalah seperti itu karena tidak ada metode perhitungan yang dijamin untuk dihentikan yang dapat menawarkan presisi tak terbatas :pertimbangkan, misalnya, cara menghitung luas lingkaran—pasti akan ada kehilangan presisi dalam nilai yang digunakan untuk , yang akan merambat ke hasil.

Kesimpulan

  1. Pengukuran dunia nyata harus menggunakan titik mengambang biner :cepat, ringkas, sangat presisi, dan tidak lebih buruk dari apa pun (termasuk versi desimal tempat Anda memulai). Sejak tipe data floating-point MySQL adalah IEEE754, inilah yang mereka tawarkan.

  2. Aplikasi mata uang harus menggunakan titik tetap denary :meskipun lambat dan membuang-buang memori, ini memastikan bahwa nilai tidak dibulatkan ke jumlah yang tidak tepat dan bahwa uang tidak hilang dalam jumlah moneter yang besar. Sejak tipe data titik tetap MySQL adalah string yang dikodekan BCD, inilah yang mereka tawarkan.

Terakhir, ingatlah bahwa bahasa pemrograman biasanya mewakili nilai pecahan menggunakan titik-mengambang biner jenis:jadi jika database Anda menyimpan nilai dalam format lain, Anda harus berhati-hati bagaimana nilai tersebut dibawa ke aplikasi Anda atau nilai tersebut dapat dikonversi (dengan semua masalah berikutnya yang menyertainya) di antarmuka.

Pilihan mana yang terbaik dalam kasus ini?

Semoga saya telah meyakinkan Anda bahwa nilai-nilai Anda dapat dengan aman (dan seharusnya ) disimpan dalam tipe floating point tanpa terlalu mengkhawatirkan "ketidakakuratan"? Ingat, mereka lebih tepat daripada representasi desimal 3-digit signifikan yang pernah ada:Anda hanya perlu mengabaikan presisi palsu (tetapi harus selalu tetap lakukan itu, meskipun menggunakan format desimal titik tetap).

Adapun pertanyaan Anda:pilih salah satu opsi 1 atau 2 daripada opsi 3—itu membuat perbandingan lebih mudah (misalnya, untuk menemukan massa maksimal, seseorang bisa menggunakan MAX(mass) , sedangkan untuk melakukannya secara efisien di dua kolom akan memerlukan beberapa penyatuan).

Di antara keduanya, tidak masalah yang mana yang dipilih—angka titik mengambang disimpan dengan jumlah bit signifikan yang konstan terlepas dari skalanya .

Selanjutnya, sementara dalam kasus umum dapat terjadi bahwa beberapa nilai dibulatkan ke bilangan biner yang lebih dekat ke representasi desimal aslinya menggunakan opsi 1 sementara secara bersamaan yang lain dibulatkan ke bilangan biner yang lebih dekat ke representasi desimal aslinya menggunakan opsi 2, sebagai kita akan segera melihat kesalahan representasi seperti itu hanya terwujud dalam presisi palsu yang harus selalu diabaikan.

Namun, dalam ini kasus, karena kebetulan ada 16 ons hingga 1 pon (dan 16 adalah pangkat 2), perbedaan relatif antara nilai desimal asli dan bilangan biner yang disimpan menggunakan dua pendekatan adalah identik :

  1. 5.387510 (bukan 5.3367187510 sebagaimana dinyatakan dalam pertanyaan Anda) akan disimpan dalam float binary32 sebagai 101.0110001100110011001102 (yaitu 5.3874998092651367187510 ):ini 0.0000036% dari nilai aslinya (tetapi, seperti yang dibahas di atas, "nilai asli" sudah merupakan representasi yang cukup buruk dari kuantitas fisik yang diwakilinya).

    Mengetahui bahwa float binary32 hanya menyimpan 7 digit desimal presisi, kompiler kami mengetahui dengan pasti bahwa semuanya dari digit ke-8 dan seterusnya adalah pasti presisi palsu dan karena itu harus diabaikan di setiap case—dengan demikian, asalkan nilai input kita tidak memerlukan presisi lebih dari itu (dan jika ya, binary32 jelas merupakan pilihan format yang salah), menjamin pengembalian ke nilai desimal yang terlihat sama bulatnya dengan nilai awal kita:5.38750010 . Namun, kita harus benar-benar menerapkan pengetahuan domain pada titik ini (seperti yang seharusnya kita lakukan dengan format penyimpanan apa pun) untuk membuang presisi palsu lebih lanjut yang mungkin ada, seperti dua angka nol di belakangnya.

  2. 86.210 akan disimpan dalam float binary32 sebagai 1010110.001100110011001102 (yaitu 86.199996948242187510 ):ini juga 0.0000036% dari nilai aslinya. Seperti sebelumnya, kami kemudian mengabaikan presisi palsu untuk kembali ke input asli kami.

Perhatikan bagaimana representasi biner dari angka-angka tersebut identik, kecuali untuk penempatan titik radix (yang terpisah empat bit):

101.0110 00110011001100110
101 0110.00110011001100110

Ini karena 5,3875 × 2 =86,2.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cara yang lebih baik menyimpan kata sandi di mysql yang dapat didekripsi juga menggunakan php

  2. membersihkan db dari data yang berlebihan

  3. Bagaimana cara menyimpan tanggal di database MySQL?

  4. Permata MySQL di OSX 10.7 Lion

  5. Kode Kesalahan MySQL 1452 Batasan Kunci Asing