Mari kita lihat dua pertanyaan terlebih dahulu:
0,1 + 0,2 == 0,3; // PALSU
9999999999999999999 == 100000000000000.000; // BENAR
Masalah pertama adalah keakuratan desimal, yang telah dibahas di banyak blog di industri ini. Masalah kedua adalah bahwa tahun lalu, ketika database sistematis mengoreksi data, ditemukan bahwa beberapa data digandakan. Artikel ini akan dimulai dari norma dan merangkum masalah di atas.
Integer maksimum
Angka dalam JavaScript disimpan menggunakan IEEE 754 Double Precision 64-bit Floating Point Numbers, dan formatnya adalah:
SXMX 2^e
S adalah tanda tanda, menunjukkan positif dan negatif. M adalah mantissa, dengan 52 bit. E adalah eksponen, dengan 11 bit. Dalam spesifikasi ecmascript, kisaran yang diberikan oleh E adalah [-1074, 971]. Dengan cara ini, mudah untuk menyimpulkan bahwa bilangan bulat maksimum yang dapat diwakili JavaScript adalah:
1 x (2^53 - 1) x 2^971 = 1.7976931348623157e+308
Nilai ini adalah angka.max_value
Demikian pula, nilai angka.min_value dapat disimpulkan sebagai:
1 x 1 x 2^(-1074) = 5e-324
Perhatikan bahwa Min_Value mewakili angka positif yang paling dekat dengan 0, bukan angka terkecil. Angka terkecil adalah -number.max_value
Keakuratan desimal hilang
Nomor JavaScript adalah angka floating-point presisi ganda dan disimpan dalam biner di komputer. Ketika jumlah bit signifikan melebihi 52 bit, akan ada kerugian akurasi. Misalnya:
Biner desimal 0,1 adalah 0,0 0011 0011 0011 ... (loop 0011)
Biner dari desimal 0,2 adalah 0,0011 0011 0011 ... (loop 0011)
Penambahan 0,1 + 0,2 dapat dinyatakan sebagai:
E = -4; M = 1.10011001100 ... 1100 (52 bit)
+ e = -3; M = 1.10011001100 ... 1100 (52 bit)
-----------------------------------------------------------------------------------------------------------------------------
e = -3; M = 0.11001100110 ... 0110
+ e = -3; M = 1.10011001100 ... 1100
-----------------------------------------------------------------------------------------------------------------------------
e = -3; M = 10.01100110011 ... 001
-----------------------------------------------------------------------------------------------------------------------------
= 0,01001100110011 ... 001
= 0,3000000000000000004 (desimal)
Berdasarkan perhitungan di atas, kita juga dapat menarik kesimpulan: Ketika jumlah terbatas desimal desimal dalam representasi biner tidak melebihi 52 bit, itu dapat disimpan secara akurat dalam javascript. Misalnya:
0,05 + 0,005 == 0,055 // Benar
Aturan lebih lanjut, seperti:
0,05 + 0,2 == 0,25 // Benar
0,05 + 0,9 == 0,95 // Salah
Mode pembulatan IEEE 754 perlu dipertimbangkan, dan mereka yang tertarik dapat mempelajarinya lebih lanjut.
Keakuratan bilangan bulat besar hilang
Pertanyaan ini jarang disebutkan. Pertama, kita harus mencari tahu apa masalahnya:
1. Berapa bilangan bulat maksimum yang bisa disimpan JavaScript?
Pertanyaan ini telah dijawab sebelumnya, dan number.max_value, jumlah yang sangat besar.
2. Berapa bilangan bulat maksimum yang dapat disimpan JavaScript tanpa kehilangan presisi?
Menurut SXMX 2^E, bit tanda positif, mantissa 52-bit sepenuhnya empuk dengan 1, dan eksponen E adalah nilai maksimum 971. Jelas, jawabannya masih nomor. Max_value.
Apa sebenarnya masalah kita? Kembali ke kode awal:
9999999999999999999 == 100000000000000.000; // BENAR
Jelas bahwa 16 9s jauh lebih sedikit dari 308 10. Masalah ini tidak ada hubungannya dengan max_value, dan itu harus dikaitkan dengan mantis M dengan hanya 52 digit.
Itu dapat dijelaskan dalam kode:
var x = 1; // Untuk mengurangi jumlah perhitungan, nilai awal dapat ditetapkan menjadi lebih besar, seperti Math.pow (2, 53) - 10
while (x! = x+1) x ++;
// x = 9007199254740992 yaitu 2^53
Dengan kata lain, ketika X kurang dari atau sama dengan 2^53, dipastikan bahwa keakuratan X tidak hilang. Ketika x lebih besar dari 2^53, keakuratan x dapat hilang. Misalnya:
Ketika x adalah 2^53 + 1, representasi binernya adalah:
100000000000 ... 001 (ada 52 0s di tengah)
Saat disimpan dengan nomor titik mengambang presisi ganda:
E = 1; M = 10000..00 (Total 52 0s, 1 adalah bit tersembunyi)
Jelas, ini sama dengan penyimpanan 2^53.
Menurut ide di atas, dapat diuraikan bahwa untuk 2^53 + 2, binernya adalah 100000 ... 0010 (51 0s di tengah), dan juga dapat disimpan secara akurat.
Aturan: Ketika x lebih besar dari 2^53 dan jumlah digit signifikan biner lebih besar dari 53 bit, akan ada kerugian akurasi. Ini pada dasarnya sama dengan hilangnya ketepatan desimal.
Bit tersembunyi dapat digunakan untuk referensi: Tutorial tentang tipe ganda Java.
ringkasan
Keakuratan desimal dan bilangan bulat besar tidak hanya hilang dalam javascript. Sebenarnya, bahasa pemrograman apa pun (C/C ++/C#/Java, dll.) Yang menggunakan format nomor floating point IEEE 754 untuk menyimpan tipe floating point memiliki masalah kerugian akurasi. Dalam C# dan Java, kelas enkapsulasi desimal dan besar disediakan untuk melakukan pemrosesan yang sesuai, untuk menghindari kehilangan akurasi.
Catatan: Sudah ada proposal desimal dalam spesifikasi ecmascript, tetapi belum secara resmi diadopsi.
Akhirnya, uji semua orang:
Number.max_value + 1 == numer.max_value;
Number.max_value + 2 == numer.max_value;
...
Number.max_value + x == numer.max_value;
Number.max_value + x + 1 == Infinity;
...
Number.max_value + number.max_value == Infinity;
// pertanyaan:
// 1. Berapa nilai x?
// 2. Infinity - number.max_value == x + 1; benar atau salah?
Diskusi singkat di atas tentang akurasi hilangnya desimal dan bilangan bulat besar di JavaScript adalah semua konten yang saya bagikan dengan Anda. Saya harap Anda dapat memberi Anda referensi dan saya harap Anda dapat mendukung wulin.com lebih lanjut.