Bagaimana cara menyimpan hasil perhitungan desimal di mysql dan mengambilnya kembali seperti di memori

Dokumentasi MySQL mengatakan :

Tipe DECIMAL dan NUMERIC menyimpan nilai data numerik yang tepat. Jenis ini digunakan ketika penting untuk menjaga presisi yang tepat, misalnya dengan data moneter.

Saya melakukan tes ini pada kolom itu decimal_column DECIMAL(31,30).

insert into tests (decimal_column) values(1/3);

kemudian memeriksa apa yang telah disimpan memberikan ini

select * from tests ;
> result : 0.333333333000000000000000000000

kemudian membalikkan operasi matematika dengan kueri ini menghasilkan ini

select decimal_column*3 from test;
> result: 0.999999999000000000000000000000

Saya mengharapkan untuk mendapatkan bilangan bulat "1" seperti yang kami lakukan di kalkulator dan di lembar excel! seperti ini

 #calculator or excel sheet
 >input: 1 / 3
 >result: 0.3333333333333333333333333333333333
 >input: * 3
 >result: 1

1- mengapa MySQL tidak menyimpan representasi biner yang tepat dari (1/3) sehingga saya dapat menggunakan hasil itu lagi dalam perhitungan saya karena hasilnya ada di memori seperti kalkulator atau lembar excel.

2- Bagaimana cara menyimpan di mysql hasil (1/3) seperti yang ada di memori selama waktu perhitungan, Jadi saya dapat mengambil kembali nilai persisnya dan melakukan sesuatu seperti 3 * $storedValue untuk menghasilkan 1 bilangan bulat seperti yang kita lakukan di kalkulator atau lembar excel.


person Accountant م    schedule 16.03.2017    source sumber


Jawaban (3)


Masalahnya bukan pada penyimpanan. Dalam contoh Anda, nilainya dipecah sebelum menyimpannya di tabel.

Sayangnya, jika Anda menulis 1/3, itu akan dihitung (dan disisipkan) menggunakan representasi default:

SELECT 1/3

0.333333333

yang, seperti yang Anda lihat, memiliki presisi yang tidak memadai.

Masalah tambahannya adalah ketika Anda mengirim konstanta (1, atau 3) ke server, Anda melakukannya menggunakan perpustakaan atau konektor, yang dapat memberikan kebebasan pada nilai. Misalnya, mereka mungkin percaya bahwa "1" dan "3" adalah bilangan bulat dan hasilnya harus diperlakukan sebagai bilangan bulat. Jadi Anda mendapatkan "1/3 = 0", tetapi "1./3 = 0,333333", karena titik di "1." membuat konektor menyadari bahwa ia perlu menggunakan floating point defaultnya. Dan Anda hanya mendapatkan enam angka 3 karena "floating point default" konektor memiliki 6 digit. Lalu Anda menyimpannya ke dalam database, tetapi sudah terlambat. Anda menyimpan dengan presisi tinggi nilai yang telah dipotong menjadi presisi rendah.

Anda dapat mencoba memberikan konstanta dari awal. Alih-alih "1", Anda menggunakan 1 sebagai desimal yang cukup besar. Saya menggunakan 31,30 Anda di sini, tetapi pastikan Anda tidak perlu menyimpan angka yang lebih besar. Mungkin, "31,20" akan lebih baik.

mysql> SELECT 1/3 UNION SELECT CAST(1 AS DECIMAL(31,30))/CAST(3 AS DECIMAL(31,30));
+----------------------------------+
| 1/3                              |
+----------------------------------+
| 0.333333333000000000000000000000 |
| 0.333333333333333333333333333333 |
+----------------------------------+
2 rows in set (0.00 sec)

Ini sangat canggung, tetapi hasilnya seharusnya lebih baik. Selain itu, menurut saya, hanya perlu memberikan nilai satu dalam sebuah ekspresi; MySQL kemudian akan mempromosikan semua jumlah yang terlibat sesuai kebutuhan. Jadi, menambahkan CAST(0 AS DECIMAL(x,y)) ke penjumlahan dan CAST(1 AS DECIMAL(x,y)) ke perkalian mungkin sudah cukup.

mysql> SELECT 3*CAST(1 AS DECIMAL(31,30))/CAST(3 AS DECIMAL(31,30));
+-------------------------------------------------------+
| 3*CAST(1 AS DECIMAL(31,30))/CAST(3 AS DECIMAL(31,30)) |
+-------------------------------------------------------+
|                      1.000000000000000000000000000000 |
+-------------------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT CAST(1 AS DECIMAL(31,30))*1/3;
+----------------------------------+
| CAST(1 AS DECIMAL(31,30))*1/3    |
+----------------------------------+
| 0.333333333333333333333333333333 |
+----------------------------------+
1 row in set (0.00 sec)

Perhatikan bahwa ini tidak berfungsi karena perkalian memiliki prioritas lebih tinggi:

mysql> SELECT CAST(0 AS DECIMAL(31,30))+1/3;
+----------------------------------+
| CAST(0 AS DECIMAL(31,30))+1/3    |
+----------------------------------+
| 0.333333333000000000000000000000 |
+----------------------------------+
1 row in set (0.00 sec)
person LSerni    schedule 16.03.2017
comment
Terima kasih. tapi masih ada yang membuatku bingung. kenapa ketika saya mengerjakan di lembar excel 1/3 lalu mengalikan hasilnya dengan 3. Saya mendapatkan 1 ketika saya memformat hasil itu 1 untuk menampilkan angka desimal yang masih saya lihat (1.0000000000000....) tidak ada pecahan sama sekali selama lebih dari 70 digit semuanya NOL. ! - person Accountant م; 16.03.2017
comment
Excel memiliki beberapa trik pemformatan yang berguna - apa yang dapat Anda lihat bukanlah apa yang ada di dalamnya. Dan ia mencoba untuk memahami. Misalnya, 16/1/16 secara harfiah adalah 1 dalam aritmatika - ini adalah 16 Januari 2016 di salinan Excel saya. Dan 16/1/16+1 bukanlah 2 melainkan sekitar 46250 - jumlah hari Julian sejak suatu tanggal yang saya tidak ingat. Dalam kasus lain, Excel akan memperbaiki apa yang dianggapnya sebagai kesalahan pembulatan... apakah itu tindakan yang benar atau tidak. Singkatnya: jangan gunakan Excel (atau program [Microsoft] lainnya) sebagai contoh bagaimana matematika (atau matematika pemrogram) seharusnya bekerja. - person LSerni; 16.03.2017
comment
astaga, bertahun-tahun bekerja dengan kalkulator Saya berpikir bahwa ketika saya melakukan 1/3 lalu membalikkan prosesnya result * 3 Saya mendapatkan hasil yang sama dengan yang saya mulai. terima kasih banyak atas waktunya. Saya akan membaca panduan floating point itu dengan penuh minat. - person Accountant م; 16.03.2017

Itu tergantung pada apa yang Anda perlukan informasinya.

Jika disimpan untuk perhitungan dan penyimpanan, hitung hasilnya (0,33 bukan 1/3) dan simpan sebagai desimal (1,5). Namun Anda tidak bisa dengan mudah menghitungnya mundur jika ingin menampilkannya.

Jika disimpan untuk ditampilkan di lain waktu tetapi tidak pernah diubah lagi (atau setidaknya tidak cepat) Anda dapat menyimpannya sebagai varchar tetapi itu akan merusak penyortiran.

Atau Anda dapat menyimpan elemen yang berbeda (positif, negatif, total, ... apa pun) sebagai desimal(5,0) dan menampilkan/menghitungnya saat menggunakannya.

Dan tentu saja Anda dapat menggabungkan hal-hal di atas jika Anda ingin mendapatkan keunggulan dalam waktu komputasi saat memilih.

person Ashwin Golani    schedule 16.03.2017

MySQL melakukan aritmatika pecahan internal menggunakan angka titik mengambang IEEE 754 64-bit.

Umumnya merupakan perkiraan. Sangat tidak masuk akal mengharapkan floating point IEEE, atau aritmatika desimal, untuk mencapai kesetaraan yang tepat saat melakukan

   3*(1/3) == 1

Itu bukan cara kerja aritmatika komputer.

Juga tidak ada cara untuk menyimpan representasi tepat dari nilai 1/3, kecuali Anda menggunakan sistem komputasi eksotik yang menyimpan bilangan rasional (pecahan) dalam bentuk pasangan (pembilang, penyebut). MySQL bukanlah sistem seperti itu.

Kebanyakan kalkulator secara implisit membulatkan hasilnya ke jumlah digit yang dapat ditampilkan. Excel juga berisi modul pemformatan. Anda dapat memilih format sel dengan menekan -1. Modul pemformatan membulatkan angka floating point ini. Anda dapat mencapai efek yang sama di MySQL menggunakan ROUND( ) fungsi. Fungsi tersebut tidak mengubah nilai yang disimpan, namun merendernya sedemikian rupa sehingga menyembunyikan kesalahan kecil yang melekat pada aritmatika mengambang IEEE 754.

SELECT ROUND(decimal_column, 2) AS decimal_column

(Bukankah orang akuntansi harus mempelajari hal ini di sekolah?)

person O. Jones    schedule 16.03.2017
comment
jadi, ketika saya mengerjakan kalkulator saya 1/3 lalu kalikan hasilnya dengan 3 *3 dan kalkulator memberi saya 1 . apakah itu berarti 1 ini bukan nilai bilangan bulat 1 yang sama persis dengan nilai yang saya gunakan untuk memulai perhitungan? itu lebih seperti 1.0000000000000000000000000000000000000000001 ? - person Accountant م; 16.03.2017
comment
Bukankah orang akuntansi harus mempelajari hal ini di sekolah? . Tidak, mereka tidak melakukannya. bagaimana bilangan floating point direpresentasikan dalam sistem biner berada di luar bidang akuntansi. bahkan masih membingungkan beberapa programmer. - person Accountant م; 16.03.2017