السبب: تقوم JS بمعالجة الإضافة والطرح والضرب وتقسيم العشرية وفقًا لـ 2. على أساس Arg1 ، يتم توسيع دقة Arg2 أو توسيع عكسي ، وبالتالي فإن الموقف التالي سيحدث.
إن مشكلة الإضافة والطرح والضرب وتقسيم النقاط العشرية في JavaScript (JS) هي خطأ في JS مثل 0.3*1 = 0.29999999999 ، إلخ. يسرد التالية أربعة خوارزميات JS التي يمكنها حساب الدقة المقابلة بشكل مثالي.
دالة accdiv (arg1 ، arg2) {var t1 = 0 ، t2 = 0 ، r1 ، r2 ؛ حاول {t1 = arg1.toString (). split (".") [1] .Length} catch (e) {} try {t2 = arg2.toString (). split (". r2 = number (Arg2.ToString (). استبدال (". }} // متعددة الدالة accmul (arg1 ، arg2) {var m = 0 ، s1 = arg1.toString () ، s2 = arg2.toString () ؛ حاول {m+= s1.split (".") [1] .Length} catch (e) {} جرب {m+= s2 accadd (arg1 ، arg2) {var r1 ، r2 ، m ؛ حاول {r1 = arg1.toString (). split (".") [1] .Length} catch (e) {r1 = 0} جرب {r2 = arg2.toString (). split (".". ". } // وظيفة الطرح subtr (arg1 ، arg2) {var r1 ، r2 ، m ، n ؛ حاول {r1 = arg1.toString (). split (".") [1] n = (r1> = r2)؟ r1: r2 ؛ العودة ((Arg1*m-arg2*m)/m) .Tofixed (n) ؛ }دعنا نحلل فقدان الدقة الرقمية في JavaScript.
1. بعض المشكلات النموذجية لفقدان الدقة الرقمية JS
1. أضف اثنين من أرقام النقطة العائمة البسيطة
0.1 + 0.2! = 0.3 // صحيح
Firebug
هذه في الحقيقة ليست مشكلة Firebug ، يمكنك تجربتها بتنبيه (هاها ، تمزح).
تحقق من نتائج حساب Java
ألق نظرة على بيثون
2. عملية عدد صحيح كبير
99999999999999999 == 10000000000000000001 //؟
Firebug
الأرقام المكونة من 16 رقمًا و 17 رقماً متساوية في الواقع ، إنها غير معقولة.
مثل أيضا
var x = 9007199254740992x + 1 == x //؟
انظر النتائج
تم تخريب وجهات النظر الثلاثة مرة أخرى.
3.
1.335.Tofixed (2) // 1.33
Firebug
كانت هناك حالات ذات أسعار غير متناسقة في Chrome والمتصفحات الأخرى عبر الإنترنت ، ويرجع ذلك بالتحديد إلى مشكلة التوافق التي تم توافقها.
2. أسباب دقة فقدان رقم JS
لا يمكن التعبير عن بعض الأرقام بشكل نهائي بواسطة تطبيقات الكمبيوتر الثنائية وحدود البتات. تمامًا مثل بعض الأرقام غير المنطقية ، لا يمكن تمثيلها بشكل نهائي ، مثل PI 3.1415926 ... ، 1.3333 ... ، إلخ. كما هو موضح
دلالة
أرقام نقاط العائمة ، على سبيل المثال
0.1 >> 0.0001 1001 1001 1001 ... (1001 lofinite loop) 0.2 >> 0.0011 0011 0011 0011 ...
في هذا الوقت ، يمكنك فقط تقريبه عن طريق تقليد النظام العشري ، ولكن لا يوجد سوى نظامين ثنائيان: 0 و 1 ، لذلك يصبح 0 ودوره بمقدار 1. وهذا هو السبب الأساسي في أن بعض أرقام النقاط العائمة في أجهزة الكمبيوتر هي أخطاء ودقة ضائعة.
إن فقدان الدقة في الأعداد الصحيحة الكبيرة هو في الأساس نفس أرقام النقاط العائمة. الحد الأقصى بت mantissa هو 52 بت ، وبالتالي فإن الحد الأقصى عدد صحيح يمكن تمثيله بدقة في JS هو Math.Pow (2 ، 53) ، وهو 9007199254740992.
قد يفقد أكثر من 9007199254740992 الدقة
9007199254740992 >> 1000000000000000 ... 000 // Total 53 09007199254740992 + 1 >> 100000000000000… 001 // في Middle 52 09007199254740992 + 2>
في الحقيقة
9007199254740992 + 1 // فقدت 9007199254740992 + 2 // لم تضيع 9007199254740992 + 3 // فقد 9007199254740992 + 4 // لم تضيع
تظهر النتائج في الشكل
كما ذكر أعلاه ، يمكننا أن نعرف أن الأرقام المحدودة على ما يبدو غير محدودة في التمثيل الثنائي للكمبيوتر. نظرًا لحد بت التخزين ، هناك "ابتعد" ويحدث فقدان الدقة.
لمزيد من التحليل المتعمق ، يمكنك قراءة هذه الورقة (طويلة ورائحة): ما يجب على كل عالم كمبيوتر معرفته عن الحساب العائم
3. الحل
بالنسبة للأعداد الصحيحة ، قد يكون احتمال حدوث مشاكل في الواجهة الأمامية منخفضة نسبيًا. بعد كل شيء ، تحتاج القليل من الشركات إلى استخدام أعداد صحيحة للغاية. طالما أن نتيجة الحساب لا تتجاوز Math.Pow (2 ، 53) ، لن تضيع الدقة.
بالنسبة إلى العشرية ، لا تزال هناك العديد من الفرص في المشكلات في الواجهة الأمامية ، خاصة في بعض مواقع التجارة الإلكترونية التي تتضمن بيانات مثل المبالغ. الحل: ضع العشرية في عدد صحيح (متعدد متعددة) ، ثم تقلص مرة أخرى إلى المضاعف الأصلي (تقسيم متعدد)
// 0.1 + 0.2 (0.1*10 + 0.2*10) / 10 == 0.3 // TRUE
فيما يلي كائن كتبته لمنع فقدان دقة الإضافة والطرح والضرب وتقسيم العشرية. بالطبع ، لا يمكن أن يتجاوز عدد صحيح تم تحويله 9007199254740992.
/*** يحتوي Floatobj على أربع طرق: الإضافة ، الطرح ، الضرب والقسمة ، والتي يمكن أن تضمن أن حساب أرقام النقطة العائمة لا يفقد الدقة ** نحن نعلم أن حسابات أرقام النقطة العائمة سيكون لها فقدان الدقة (أو خطأ تقريب). السبب الجذري هو أنه لا يمكن التعبير عن بعض الأرقام في حدود البت الثنائية وتنفيذها* فيما يلي التمثيل الثنائي المقابل للعشرية العشرية* 0.1 >> 0.0001 1001 1001 1001 1001 ... (1001 حلقة لا نهائية)* 0.2 >> 0.0011 0011 0011 ... (0011 loop loop)* على سبيل المثال ، يستخدم JavaScript أنواعًا رقميًا للتخزين 64 بت ، لذلك سيتم التخلص من تلك التي تتجاوزها. الجزء المفقود هو الجزء المفقود في الدقة. ** ** الطريقة *** إضافة / طرح / مضاعفة / قسمة ** ** التفسير *** 0.1 + 0.2 == 0.300000000000000004 (0.00000000000004 أكثر)* 0.2 + 0.4 == 0.600000000000000001 (0.000000000000001)* 19.9* (0.0000000000000000002 أقل) ** floatobj.add (0.1 ، 0.2) >> 0.3*floatobj.multiply (19.9 ، 100) >> 1990 **/var floatobj = function () {/** حدد ما إذا نقطة النقطة في عدد صحيح وإرجاع عدد صحيح ومتعدد. على سبيل المثال ، 3.14 >> 314 ، فإن المضاعف هو 100* param floatnum {number} decimal* @return {object}* {times: 100 ، num: 314}*/function tointeger (floatnum) {var ret = floatnum + '' var dotpos = strfi.indexof ('.') var len = strfi.substr (dotpos + 1) .LengthVar Times = Math.Pow (10 ، len) var intnum = parseint (floatnum* times + 0.5 ، العمليات لضمان عدم فقد الدقة* الفكرة: توسيع العشري في عدد صحيح (مضاعف) ، وأداء العمليات الحسابية ، ثم تقلص إلى العشري (مقسم) ** param a {number} رقم التشغيل 1* param b {number}. الأماكن*param op {string} نوع العملية ، مع الإضافة والطرح والضرب والقسمة (إضافة/طرح/مضاعفة/تقسيم) **/تشغيل الوظيفة (A ، B ، الأرقام ، المرجع) {var o1 = toInteger (a) var o2 = tointeger (b) var n1 = o1.numvar n2 = o2.numvar = T1> T2؟ T1: t2var result = nullswitch (op) {case 'add': if (t1 === t2) {// اثنين من الأماكن العشرية هما نفس النتيجة = n1 + n2} آخر آخر (T2 / T1) + n2} نتيجة الإرجاع / maxcase 'اطرح': if (t1 === t2) {result = n1 - n2} آخر إذا (t1> t2) {result = n1 - n2 * (t1 / t2)} {result = n1 * (t2 / t1) - n2} return return / max. T2) RETRESS REDORDCASE 'DISIDE': result = (n1 / n2) * (t2 / t1) نتيجة الإرجاع}} الأرقام) {عملية الإرجاع (A ، B ، الأرقام ، 'Metreubly')} divide (a ، b ، الأرقام) {عملية الإرجاع (a ، b ، الأرقام ، 'Divide')} // exportsreturn {add: add ، اطرح: طرح ، مضاعفة ، Divide: divide}} () ؛إصلاح Tofixed كما يلي
// tofixed fix function tofixed (num ، s) {var times = math.pow (10 ، s) var des = num * times + 0.5des = parseint (des ، 10) / timesReturn des + ''}