Alasan: JS memproses penambahan, pengurangan, perkalian dan pembagian desimal menurut 2. Atas dasar ARG1, keakuratan ARG2 diperluas atau diperluas secara terbalik, sehingga situasi berikut akan terjadi.
Masalah penambahan, pengurangan, perkalian dan pembagian titik desimal dalam JavaScript (JS) adalah bug di JS seperti 0,3*1 = 0,29999999999, dll. Daftar empat algoritma JS berikut yang dapat menghitung akurasi yang sesuai dengan sempurna.
fungsi accdiv (arg1, arg2) {var t1 = 0, t2 = 0, r1, r2; coba {t1 = arg1.toString (). split (".") [1] .length} catch (e) {} coba {t2 = arg2.tostring (). split (".") [1] .length} catch (e) {} dengan (matematika) {r1 = angka (arg1.toString (e) {} dengan (matematika) {r1 = angka (arg1.toString (e) {} dengan (matematika) {r1 = bilangan (arg1.toString (). " r2 = angka (arg2.toString (). ganti (".", ")) return accmul ((r1/r2), pow (10, t2-t1)); }} // Beberapa fungsi accmul (arg1, arg2) {var m = 0, s1 = arg1.toString (), s2 = arg2.toString (); Coba {m+= s1.split (".") [1] .length} catch (e) {} coba {m+= s2.split (".") [1] .length} catch (e) {}}} {}} {} {} {} {} {} {} {} {s1 (. accadd (arg1, arg2) {var r1, r2, m; coba {r1 = arg1.toString (). split (".") [1] .length} catch (e) {r1 = 0} coba {r2 = arg2.tostring (). split (".") [1] .length} catch (e) {r2 = 0} m = math.pow (10, math.mex (e) {r2 = 0} m = math.pow (10, math.mex } // Fungsi Subtraksi Subtr (arg1, arg2) {var r1, r2, m, n; coba {r1 = arg1.toString (). split (".") [1] .length} catch (e) {r1 = 0} coba {r2 = arg2.toString (). split (".") [1] .length} catch (e) {r2 = 0} m = math.pow (10, math.max n = (r1> = r2)? r1: r2; return ((arg1*m-arg2*m)/m) .tofixed (n); }Mari kita analisis hilangnya ketepatan digital dalam JavaScript.
1. Beberapa masalah khas kehilangan presisi digital JS
1. Tambahkan dua nomor titik mengambang sederhana
0.1 + 0.2! = 0.3 // Benar
Pembakar
Ini benar -benar bukan masalah Firebug, Anda dapat mencobanya dengan peringatan (haha, bercanda).
Lihat hasil perhitungan Java
Lihatlah Python
2. Operasi Integer Besar
999999999999999999 == 1000000000000000000001 //?
Pembakar
Angka 16 digit dan 17 digit sebenarnya sama, tidak masuk akal.
Juga suka
var x = 9007199254740992x + 1 == x //?
Lihat hasilnya
Tiga tampilan ditumbangkan lagi.
3. Tofixed tidak akan bulat (chrome)
1.335.tofixed (2) // 1.33
Pembakar
Ada kasus -kasus harga yang tidak konsisten di Chrome dan browser lainnya secara online, dan justru karena masalah kompatibilitas tofixed.
2. Alasan akurasi kerugian nomor JS
Beberapa angka tidak dapat dinyatakan secara halus dengan implementasi biner komputer dan batas bit. Sama seperti beberapa bilangan irasional tidak dapat diwakili secara halus, seperti PI 3.1415926 ..., 1.3333 ..., dll. JS mengikuti spesifikasi IEEE 754, mengadopsi penyimpanan presisi ganda, dan menempati 64 bit. Seperti yang ditunjukkan
makna
Angka titik mengambang, mis.
0.1 >> 0.0001 1001 1001 1001… (1001 Loop Infinite) 0.2 >> 0.0011 0011 0011 0011… (0011 Infinite Loop)
Pada saat ini, Anda hanya dapat membulatkannya dengan meniru sistem desimal, tetapi hanya ada dua sistem biner: 0 dan 1, jadi itu menjadi 0 dan di sekitarnya dengan 1. Ini adalah alasan mendasar mengapa beberapa bilangan titik mengambang di komputer adalah kesalahan dan kehilangan akurasi.
Kehilangan akurasi bilangan bulat besar pada dasarnya sama dengan angka titik mengambang. Bit mantissa maksimum adalah 52 bit, sehingga bilangan bulat maksimum yang dapat diwakili secara akurat dalam JS adalah matematika. (2, 53), yaitu 9007199254740992.
Lebih dari 9007199254740992 mungkin kehilangan akurasi
9007199254740992 >> 1000000000000000 ... 000 // Total 53 09007199254740992 + 1 >> 10000000000000000000000 ... 001 // di tengah 52 0900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
nyatanya
9007199254740992 + 1 // Kehilangan 900719254740992 + 2 // tidak hilang 9007199254740992 + 3 // Kehilangan 9007199254740992 + 4 // tidak hilang
Hasilnya ditunjukkan pada gambar
Seperti disebutkan di atas, kita dapat mengetahui bahwa angka -angka yang tampaknya terbatas tidak terbatas dalam representasi biner komputer. Karena batas bit penyimpanan, ada "lolos" dan kerugian akurasi terjadi.
Untuk analisis yang lebih mendalam, Anda dapat membaca makalah ini (panjang dan bau): Apa yang harus diketahui oleh setiap ilmuwan komputer tentang aritmatika titik mengambang
3. Solusi
Untuk bilangan bulat, probabilitas masalah di front-end mungkin relatif rendah. Lagi pula, beberapa bisnis perlu menggunakan bilangan bulat super besar. Selama hasil perhitungan tidak melebihi matematika.Pow (2, 53), keakuratannya tidak akan hilang.
Untuk desimal, masih ada banyak peluang masalah dengan front-end, terutama di beberapa situs web e-commerce yang melibatkan data seperti jumlah. Solusi: Masukkan desimal ke dalam bilangan bulat (multiple), dan kemudian menyusut kembali ke beberapa asli (membagi beberapa)
// 0,1 + 0,2 (0,1*10 + 0,2*10) / 10 == 0,3 // Benar
Berikut ini adalah objek yang saya tulis untuk memblokir hilangnya akurasi penambahan, pengurangan, perkalian dan pembagian desimal. Tentu saja, bilangan bulat yang dikonversi tidak dapat melebihi 9007199254740992.
/*** FloatoBJ berisi empat metode: penambahan, pengurangan, perkalian dan divisi, yang dapat memastikan bahwa perhitungan bilangan titik mengambang tidak kehilangan akurasi ** Kita tahu bahwa perhitungan bilangan titik mengambang akan memiliki kerugian akurasi (atau kesalahan pembulatan). Akar penyebabnya adalah bahwa beberapa angka tidak dapat dinyatakan dalam biner dan mengimplementasikan batas bit* Berikut ini adalah representasi biner yang sesuai dengan desimal desimal* 0,1 >> 0,0001 1001 1001 1001 1001 ... (1001 loop tak terbatas)* 0,2 >> 0,0011 0011 0011 0011 ... (0011 LOOP INFINITE). Misalnya, JavaScript menggunakan tipe numerik penyimpanan 64-bit, sehingga yang melebihi mereka akan dibuang. Bagian yang hilang adalah bagian yang hilang dalam akurasi. ** ** METODE *** Tambah / Kurangi / Multiply / Divide ** ** Penjelasan *** 0,1 + 0,2 == 0,300000000000000004 (0,0000000000.0004 lebih)* 0,2 + 0,4 == 0.600000000000000999999999999999999999999999999999999999 syne (0,00000000000000002 lebih sedikit) ** floatobj.add (0,1, 0,2) >> 0,3*floatobj.multiply (19,9, 100) >> 1990 **/var floatobj = function () {/** Tentukan apakah OBJ adalah integer*/function isInteger (obj) {return math.floor adalah integer*/function isInteger (obj) {return math.floor adalah integer*/function isInteger (obj) {return math.floor* bilangan bulat dan mengembalikan bilangan bulat dan banyak. For example, 3.14 >> 314, the multiple is 100* @param floatNum {number} decimal* @return {object}* {times:100, num: 314}*/function toInteger(floatNum) {var ret = {times: 1, num: 0}if (isInteger(floatNum)) {ret.num = floatNumreturn ret}var strfi = floatNum + '' var dotpos = strfi.indexOf ('.') Var len = strfi.substr (dotpos + 1) .lengthvar kali = math.pow (10, len) var intnum = parseInt (floatnum* kali + 0.5, 10) ret.times = timesret.num = intnumreturn retasi} kali + 0.5, 10) ret.times = Timesret.num = intnumreturn retasi} retasi} 0.5, 10) ret.times = Timesret.num = intnumreturn retasi} retasi} 0) Akurasi itu tidak hilang* Gagasan: memperbesar desimal menjadi bilangan bulat (pengganda), melakukan operasi aritmatika, dan kemudian menyusut ke desimal (dibagi) ** @param a {angka} nomor operasi 1* @param b {angka} nomor 2* @param digit {angka} akurasi, jumlah decim {decim points 2* @param digit {angka} akurasi, jumlah decim points 2 poin decim 2 poines 2 {String} Jenis operasi, dengan penambahan, pengurangan, multiplikasi dan divisi (tambahkan/kurangi/multiply/divide) **/Operasi fungsi (a, b, digit, op) {var o1 = tointeger (a) var o2 = tointeger (b) var n1 = o1.numvar n2 = o2.numvarrer t1 = t1 = T1 = T12. ? T1: T2VAR Hasil = nullswitch (op) {case 'add': if (t1 === t2) {// Dua tempat desimal adalah hasil yang sama = n1 + n2} lain jika (t1> t2) {// O1 tempat desimal lebih besar dari o2Result = n1 + n2 * (T1 / T2)}} oMal {o2Result = n1 + n2 * (T1 / T2)} oMal {o2Result = n1 + n2 * (t1 / t2)} place {o2Result = n1 + n2 * (t1 / t2) (t2 / t1) + n2} hasil pengembalian / maxcase 'kurangi': if (t1 === t2) {result = n1 - n2} else if (t1> t2) {hasil = n1 - n2 * (t1 / t2)} else {result = n1 * (t2 / t1) - n2} hasil pengembalian / max = n1 * (t2 / t1) - n2} return / max = n1 * (t2 / t1) - n2} return resultcase 'divide':result = (n1 / n2) * (t2 / t1)return result}}// Four interfaces of addition, subtraction, multiplication and division function add(a, b, digits) {return operation(a, b, digits, 'add')}function subtract(a, b, digits) {return operation(a, b, digits, 'subtract')}function multiply(a, b, digits) {pengembalian operasi (a, b, digit, 'multiply')} function divide (a, b, digit) {pengembalian operasi (a, b, digit, 'divide')} // ekspor retsurn {add: add, kurangi: kurangi, multiply: multiply, bagikan: divide}} ();Perbaikan Tofixed adalah sebagai berikut
// fungsi fix tofixed tofixed (num, s) {var kali = math.pow (10, s) var des = num * kali + 0.5des = parseInt (des, 10) / Timesreturn des + ''}