JS前端数字计算精度丢失问题,请问各位是怎么解决的?

比如计算百分比,乘除法,js计算有小数点,精度会丢失,通过toFixed可以截取小数后几位,但是会四舍五入,而toPrecision则需要指定数字长度。现在要保留小数点后2位,请问怎么处理

let n = 123.123;

console.log(n.toPrecision(4)) // 123.1

let n = 123.126;

console.log(n.toFixed(2)) // 123.13

期望结果:
let n = 123.1266646635525563;
// 123.12


回答:

所谓“没有完美的算法,只有合适的场景”,浮点数字(小数)就是个很好的例子。

我们知道,按照目前的规范,JS 无法直接完美的处理小数。但是实际上,我们往往也不需要它“完美”处理小数。比如,以记账为例,我们通常只关心小数点后两位,也就是“分”,再细的,我们关注它意义不大,投入产出比太低。那么我们就可以把所有数字 * 100,取整后保存,带来的误差非常低。

所以,讨论小数精度问题,要看具体的需求。只要满足需求,怎么保存都可以。


回答:

类似的方法,函数其实很多,比如说可以用Math.floor函数,将结果向下取整,最后再除以100。这样可以保留小数点后2位并且不进行四舍五入。
可以这样:

let n = 123.1266646635525563;

let result = Math.floor(n * 100) / 100;

console.log(result); // 123.12

或者用字符串的substring函数截取小数点后的位数也是可以的,相对刚刚纯数字的方法多了一个转换步骤,相对复杂一点点,但有时候用得上,将len n转换为s字符串,然后在里面找到小数点的位置,最后再输出。

let n = 123.1266646635525563;

let result = n.toString();

let decimalIndex = result.indexOf('.') + 1;

result = result.substring(0, decimalIndex + 2);

console.log(parseFloat(result)); // 123.12


回答:

可以考虑先乘以100再整数取整,最后除以100恢复到原数字

Math.floor(n * 100) / 100


回答:

使用decimal.js,或者bignumber.js


回答:

自定义计算函数:

function multiply(a, b) {

let m = 0;

const s1 = a.toString();

const s2 = b.toString();

try { m += s1.split(".")[1].length } catch (e) {}

try { m += s2.split(".")[1].length } catch (e) {}

return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m);

}

function divide(a, b) {

let t1 = 0;

let t2 = 0;

try { t1 = a.toString().split(".")[1].length } catch (e) {}

try { t2 = b.toString().split(".")[1].length } catch (e) {}

const r1 = Number(a.toString().replace(".", ""));

const r2 = Number(b.toString().replace(".", ""));

return multiply((r1 / r2), Math.pow(10, t2 - t1));

}

function add(a, b) {

let c = 0;

let d = 0;

try { c = a.toString().split(".")[1].length } catch (e) {}

try { d = b.toString().split(".")[1].length } catch (e) {}

const m = Math.pow(10, Math.max(c, d));

return (multiply(a, m) + multiply(b, m)) / m;

}

function subtract(a, b) {

let c = 0;

let d = 0;

try { c = a.toString().split(".")[1].length } catch (e) {}

try { d = b.toString().split(".")[1].length } catch (e) {}

const m = Math.pow(10, Math.max(c, d));

const n = (c >= d) ? c : d;

return ((multiply(a, m) - multiply(b, m)) / m).toFixed(n);

}

let n = 123.1266646635525563;

let result = multiply(n, 100);

result = Math.floor(result);

result = divide(result, 100);

console.log(result); // 123.12


回答:

// 示例:使用 Bigint 进行计算

const num1 = BigInt(0.1 * 10);

const num2 = BigInt(0.2 * 10);

const result = (num1 + num2) / BigInt(10);

console.log(result.toString()); // 输出: 0.3


回答:

解决精度缺失问题,要么是第三方库,要么就是自己写方法计算,自定义方法中的加减乘除大部分是基于计算小数位个数,如3位,计算前先乘1000,计算完之后再除以1000就可以了


回答:

math.js


回答:

我的经验是解决计算精度 直接用现成的库去处理 比如上面说的BigNumber decimal等等, 我个人更喜欢jsbi-calculator, 加减乘除写起来简单 也不用像其他几个库那样要设置 引入的体积也更小
而保留小数主要看是不是要四舍五入或者银行家舍入 比如自己写一个舍入的方法 或者用lodash的round等 看个人选择


回答:

个人用的比较多的方法,加减除

function preciseAdd(num1, num2) {

let m = 0, s1 = num1.toString(), s2 = num2.toString();

try { m += s1.split(".")[1].length } catch (e) { }

try { m += s2.split(".")[1].length } catch (e) { }

return Number(s1.replace(".", "")) + Number(s2.replace(".", "")) / Math.pow(10, m);

}

function preciseMultiply(num1, num2) {

let m = 0, s1 = num1.toString(), s2 = num2.toString();

try { m += s1.split(".")[1].length } catch (e) { }

try { m += s2.split(".")[1].length } catch (e) { }

return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m);

}

function preciseDivide(num1, num2) {

let t1 = 0, t2 = 0, s1 = num1.toString(), s2 = num2.toString();

try { t1 = s1.split(".")[1].length } catch (e) { }

try { t2 = s2.split(".")[1].length } catch (e) { }

let r1 = Number(s1.replace(".", ""));

let r2 = Number(s2.replace(".", ""));

return (r1 / r2) * Math.pow(10, t2 - t1);

}


回答:

/**

* 数字运算(主要用于小数点精度问题)

* [see](https://juejin.im/post/6844904066418491406#heading-12)

* @param {number} a 前面的值

* @param {"+"|"-"|"*"|"/"} type 计算方式

* @param {number} b 后面的值

* @example

* 可链式调用

* const res = computeNumber(1.3, "-", 1.2).next("+", 1.5).next("*", 2.3).next("/", 0.2).result;

*/

export function computeNumber(a, type, b) {

/**

* 获取数字小数点的长度

* @param {number} n 数字

*/

function getDecimalLength(n) {

const decimal = n.toString().split(".")[1];

return decimal ? decimal.length : 0;

}

/**

* 修正小数点

* @description 防止出现 `33.33333*100000 = 3333332.9999999995` && `33.33*10 = 333.29999999999995` 这类情况做的处理

* @param {number} n

*/

const amend = (n, precision = 15) => parseFloat(Number(n).toPrecision(precision));

const power = Math.pow(10, Math.max(getDecimalLength(a), getDecimalLength(b)));

let result = 0;

a = amend(a * power);

b = amend(b * power);

switch (type) {

case "+":

result = (a + b) / power;

break;

case "-":

result = (a - b) / power;

break;

case "*":

result = (a * b) / (power * power);

break;

case "/":

result = a / b;

break;

}

result = amend(result);

return {

/** 计算结果 */

result,

/**

* 继续计算

* @param {"+"|"-"|"*"|"/"} nextType 继续计算方式

* @param {number} nextValue 继续计算的值

*/

next(nextType, nextValue) {

return computeNumber(result, nextType, nextValue);

},

};

}


回答:

let m = 123.1923
let a = n.toString()
console.log(a.indexOf('.')===-1?(+a).toFixed(2):a.slice(0,a.indexOf('.')+3))
不四舍五入只能借助字符串 比如截取


回答:

消除js计算误差add、reduce是传入的加减数字,reduce是被加数(被减数),s是加减符号

formatNum(add, reduce, s, num) {

let m = Math.pow(10, num); //num是10的次幂

let res = s == '+' ? (add * m + reduce * m) / m : (add * m - reduce * m) / m;

return Math.round(res * m) / m;

},

let n= 123.123

console.log(this.formatNum(n, 0, '-', 2)) // 123.12


回答:

我们项目组用的是decimal.js库去解决这个问题的,所以哪一个库最好用希望有大佬来解答一下

以上是 JS前端数字计算精度丢失问题,请问各位是怎么解决的? 的全部内容, 来源链接: utcz.com/p/934995.html

回到顶部