Jika saya bertanya apa itu 0,1 + 0,2? Bolehkah saya menatap kosong, 0,1 + 0,2 = 0,3 Ah, apakah Anda masih perlu bertanya? Bahkan anak-anak di taman kanak-kanak pun bisa menjawab pertanyaan pediatrik seperti itu. Namun tahukah Anda, permasalahan yang sama pada bahasa pemrograman mungkin tidak sesederhana yang dibayangkan.
Tidak percaya? Mari kita lihat bagian dari JS terlebih dahulu.
var angkaA = 0,1;
var angkaB = 0,2;
peringatan( (angkaA + angkaB) === 0,3 );
Hasil eksekusi salah. Ya, ketika saya pertama kali melihat kode ini, saya berasumsi bahwa itu benar, tetapi hasil eksekusinya mengejutkan saya. Apakah metode pembukaan saya salah? Tidak, tidak. Mari kita coba jalankan kembali kode berikut dan kita akan mengetahui mengapa hasilnya salah.
var angkaA = 0,1;
var angkaB = 0,2;
peringatan(angkaA + angkaB);
Ternyata 0,1 + 0,2 = 0,30000000000000004. Bukankah ini aneh? Faktanya, untuk empat operasi aritmatika bilangan floating point, hampir semua bahasa pemrograman akan mengalami masalah yang mirip dengan kesalahan presisi. Namun, dalam bahasa seperti C++/C#/Java, metode telah dienkapsulasi untuk menghindari masalah presisi. dan JavaScript adalah tipe yang lemah. Bahasa ini tidak memiliki tipe data yang ketat untuk angka floating point dari konsep desain, sehingga masalah kesalahan presisi sangat menonjol. Mari kita analisa mengapa ada kesalahan akurasi ini dan bagaimana cara memperbaikinya.
Pertama-tama, kita harus memikirkan masalah pediatrik sebesar 0,1 + 0,2 dari sudut pandang komputer. Kita tahu bahwa yang bisa dibaca oleh komputer adalah biner, bukan desimal, jadi mari kita ubah dulu 0,1 dan 0,2 menjadi biner dan lihat:
0,1 => 0,0001 1001 1001 1001… (lingkaran tak terbatas)
0,2 => 0,0011 0011 0011 0011… (lingkaran tak terbatas)
Bagian desimal dari bilangan floating point presisi ganda mendukung hingga 52 bit, jadi setelah menambahkan keduanya, kita mendapatkan string 0,0100110011001100110011001100110011001100110011001100 Bilangan biner terpotong karena keterbatasan tempat desimal bilangan floating point Saat ini, kita ubah menjadi desimal dan menjadi 0,30000000000000004.
Jadi itu saja, lalu bagaimana cara mengatasi masalah ini? Hasil yang saya inginkan adalah 0,1 + 0,2 === 0,3 Ah! ! !
Salah satu solusi paling sederhana adalah dengan memberikan persyaratan presisi yang jelas Dalam proses pengembalian nilai, komputer akan otomatis melakukan pembulatan, seperti:
var angkaA = 0,1;
var angkaB = 0,2;
peringatan( parseFloat((numA + numB).toFixed(2)) === 0,3 );
Namun yang jelas ini bukan metode sekali dan untuk semua. Alangkah baiknya jika ada metode yang dapat membantu kita menyelesaikan masalah presisi bilangan floating point ini. Mari kita coba metode ini:
Math.formatFloat = fungsi(f, digit) {
var m = Matematika.pow(10, angka);
kembalikan parseInt(f * m, 10) / m;
}
var angkaA = 0,1;
var angkaB = 0,2;
alert(Math.formatFloat(numA + numB, 1) === 0,3);
Apa yang dimaksud dengan metode ini? Untuk menghindari perbedaan presisi, kita perlu mengalikan angka yang akan dihitung dengan 10 pangkat ke-n, mengubahnya menjadi bilangan bulat yang dapat dikenali secara akurat oleh komputer, lalu membaginya dengan 10 pangkat ke-n bahasa pemrograman menangani perbedaan presisi, kami akan menggunakannya untuk menangani kesalahan presisi angka floating point di JS.
Jika lain kali seseorang bertanya kepada Anda apa yang sama dengan 0,1 + 0,2, Anda harus berhati-hati dengan jawaban Anda! !