Причина: Дж.
Проблема добавления, вычитания, умножения и деления десятичных точек в JavaScript (JS) является ошибкой в JS, такой как 0,3*1 = 0,29999999999 и т. Д. В следующих перечислены четыре алгоритмы JS, которые могут идеально рассчитать соответствующую точность.
функция accdiv (arg1, arg2) {var t1 = 0, t2 = 0, r1, r2; try {t1 = arg1.toString (). split (".") [1] .length} catch (e) {} try {t2 = arg2.tostring (). split (".") [1] .length} catch (e) {} с (math) {r1 = число (arg1.tostring (). r2 = number (arg2.toString (). заменить (".", ")) return accmul ((r1/r2), pow (10, t2-t1)); }} // множественная функция accmul (arg1, arg2) {var m = 0, s1 = arg1.toString (), s2 = arg2.toString (); try {m+= s1.split (".") [1] .length} catch (e) {} try {m+= s2.split (".") [1] .length} catch (e) {} return number (s1.replace (".", "))*Num accadd (arg1, arg2) {var r1, r2, m; try {r1 = arg1.toString (). split (".") [1] .length} catch (e) {r1 = 0} try {r2 = arg2.toString (). split (".") [1] .length} catch (e) {r2 = 0} m = math.pow (10, math.max (r1, r2) arg1/max/arg1/max (r2)) (r2) rag1/max/m math.pow. } // Функция вычитания subtr (arg1, arg2) {var r1, r2, m, n; try {r1 = arg1.toString (). split (".") [1] .length} catch (e) {r1 = 0} try {r2 = arg2.toString (). split (".") [1] .length} catch (e) {r2 = 0} m = math.pow (10, math.max (r1, r2); n = (r1> = r2)? r1: r2; return ((arg1*m-arg2*m)/m) .tofixed (n); }Давайте проанализируем потерю цифровой точности в JavaScript.
1. Некоторые типичные проблемы цифровой потери JS Digital Precision
1. Добавьте два простых номера с плавающей запятой
0,1 + 0,2! = 0,3 // true
Firebug
Это на самом деле не проблема Firebug, вы можете попробовать ее с предупреждением (ха -ха, шучу).
Проверьте результаты расчета Java
Взгляните на Python
2. Большая целочисленная операция
9999999999999999999 == 1000000000000000000001 //?
Firebug
16-значные и 17-значные цифры на самом деле равны, они необоснованно.
Также как
var x = 9007199254740992x + 1 == x //?
Смотрите результаты
Три вида были снова подрываются.
3. ToFixed не будет круглым (хром)
1.335.tofixed (2) // 1.33
Firebug
Были случаи противоречивых цен в Chrome и других браузерах в Интернете, и именно из -за проблемы совместимости ToFixed.
2. Причины точности потери номера JS
Некоторые цифры не могут быть выражены в конечном счете с помощью компьютерных бинарных реализаций и лимитов битов. Точно так же, как некоторые иррациональные числа не могут быть конечно, такие как PI 3.1415926 ..., 1.3333 ... и т. Д. JS следует спецификации IEEE 754, принимает двойное хранилище и занимает 64 бита. Как показано
значение
Номера плавающей запятой, например,
0,1 >> 0,0001 1001 1001 1001… (1001 Infinite Loop) 0,2 >> 0,0011 0011 0011 0011… (0011 Infinite Loop)
В настоящее время вы можете только окружить его, имитируя десятичную систему, но есть только две бинарные системы: 0 и 1, поэтому она становится 0 и окружает ее на 1. Это основная причина, по которой некоторые числа с плавающей точкой в компьютерах-ошибки и утраченная точность.
Потеря о точности крупных целых чисел по сути такая же, как номера плавающей запятой. Максимальный бит Mantissa составляет 52 бита, поэтому максимальное целое число, которое может быть точно представлено в JS, - Math.pow (2, 53), которая составляет 9007199254740992.
Более 9007199254740992 может потерять точность
9007199254740992 >> 100000000000000000 ... 000 // Всего 53 09007199254740992 + 1 >> 10000000000000000 ... 001 // В середине 52 09007199254740992 + 2 >> 10000000000000000000000 ... 010 //ne Средний 510992 + 2 >> 1000000000000000000000000 ....
Фактически
9007199254740992 + 1 // Потерянный 9007199254740992 + 2 // не потерян 9007199254740992 + 3 // Потерянный 9007199254740992 + 4 // не потеряно
Результаты показаны на рисунке
Как упоминалось выше, мы можем знать, что, казалось бы, конечные цифры бесконечны в двоичном представлении компьютера. Из -за предела бита хранения, есть «ушел», и происходит потеря точности.
Для более глубокого анализа вы можете прочитать эту статью (длинное и вонючие): что каждый компьютерный ученый должен знать о арифметике с плавающей точкой.
3. Решение
Для целых чисел вероятность проблем на переднем крае может быть относительно низкой. В конце концов, немногие предприятия должны использовать супер-большие целые числа. Пока результат расчета не превышает математику. 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 Infinite Loop)* 0.2 >> 0,0011 0011 0011 0011… (0011 Infinite Loop)* Хранилище в типике компьютера. Например, JavaScript использует 64-битные цифры хранения, поэтому те, которые их превышают, будут отброшены. Часть, которая потеряна, - это та часть, которая теряется в точности. ** ** method *** add / subtract / multiply /divide** ** explanation *** 0.1 + 0.2 == 0.300000000000000004 (0.0000000000000004 more) * 0.2 + 0.4 == 0.60000000000000000001 (0.00000000000000001) * 19.9 * 100 == 1989.9999999999999998 (0.00000000000000002 less) ** floatObj.add(0.1, 0.2) >> 0.3* floatObj.multiply(19.9, 100) >> 1990**/var floatObj = function() {/** Determine whether obj is an integer*/function isInteger(obj) {return Math.floor(obj) === obj}/** Convert a floating point number into an целое число и вернуть целое число и множественное. Например, 3.14 >> 314, Multy IS 100* @param floatnum {number} decimal* @return {object}* {times: 100, num: 314}*/function tointeger (floatnum) {var ret = {times: 1, 0} if (isInteger (floatnum)) {ret.num = strum = strum strum = floatn strum = floatn strurn = floatn strur '' var dotpos = strfi.indexof ('.') var len = strfi.substr (dotpos + 1) .lengthvar times = math.pow (10, len) var intnum = parseint (floatnum* times + 0,5, 10) ret.times = timesret.num = intnumretur не теряется* Идея: увеличить десятичное значение в целое число (множитель), выполнять арифметические операции, а затем сжиматься до десятичного (разделенного) ** @param a {number} Операция № 1* @param b {номер} Операция 2* @param Digits {номер} Точность ocraded ocradal, как 2, есть два десяти. {string} Тип работы, с добавлением, вычитанием, умножением и делением (добавление/вывоз/умножо/разделение) **/Функциональная операция (A, B, цифры, OP) {var O1 = tointeger (a) var o2 = tointeger (b) var n1 = o1.numvar n2 = o2.numvar t1 = o1.timesvar t2 = t2 = oxvar = oxvar = t2 = oxvar = oxvar = t2 = o. T2? T1: t2var result = nullswitch (op) {case 'add': if (t1 === t2) {// два десятичных значения являются одинаковыми результатами = n1 + n2} else if (t1> t2) {// o1 десятичные места, больше, чем o2result = n1 + n2 * (t1 / t2)} inse {// // o1 decmult = n1 + n2 * (t1 / t2)} {// // o1 decmult = n1 + n2 * (t1 / t2)} {// / / demal decmult = n2 * (t1 / t2)} (t2 / t1) + n2} return result / maxcase 'suptract': if (t1 === t2) {result = n1 - n2} else if (t1> t2) {result = n1 - n2 * (t1 / t2)} else {result = n1 * (t2 / t1) - n2} return result / maxc.cept 'result' result 'neffore' neffore = nobles t2) 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, цифры) {Операция возврата (a, b, цифры, 'умножение')} function divide (a, b, digits) {return operation (a, b, цифры, 'divide')} // exportSreturn {добавить: добавить, вычтите: вычтите, умножьте: умножьте, разделить: divide}} (););Исправление ToFixed заключается в следующем
// Функция Fixed Fix ToFixed (num, s) {var times = math.pow (10, s) var des = num * times + 0,5des = parseint (des, 10) / timesretur des + ''}