JS 数字丢失精度的原因: 计算机的二进制实现和位数限制有些数无法有限表示。
意义:
1位用来表示符号位
11位用来表示指数
52位表示尾数
大整数的精度丢失和浮点数本质上是一样的,尾数位最大是 52 位,因此 JS 中能精准表示的最大整数是 Math.pow(2, 53),十进制即 :9007199254740992。
大于 9007199254740992 的可能会丢失精度
注意的是toFixed()坑
文章的最下边 有个封装方法,适用所有场合,并完全符合数学中的四舍五入规则。
解决
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
// 自己实现 num为xxx , n为2(会在2后面补上00.即2.00)
// Math.pow(x, y); 返回的是x的y次方
// 2的5次方 2 * 2 * 2 * 2 * 2
// 5的2次方 也叫平方 5 * 5
// 5的3次方 也叫立方 5 * 5 * 5
const toFixed = (num, n) => {
if (num < 0) {
num = -num;
} else {
return -(parseInt(num * Math.pow(10, n) + 0.5, 10) / Math.pow(10, n));
}
return parseInt(num * Math.pow(10, n) + 0.5, 10) / Math.pow(10, n);
};
// 两个浮点数求和
const Add = (num1, num2) => {
let r1, r2, m;
try {
r1 = `${num1}`.split('.')[1].length;
} catch (e) {
r1 = 0;
}
try {
r2 = `${num2}`.split('.')[1].length;
} catch (e) {
r2 = 0;
}
m = Math.pow(10, Math.max(r1, r2));
return Math.round(num1 * m + num2 * m) / m;
};
// 两个浮点数相减
const Sub = (num1, num2) => {
let r1, r2, m, n;
try {
r1 = `${num1}`.split('.')[1].length;
} catch (e) {
r1 = 0;
}
try {
r2 = `${num2}`.split('.')[1].length;
} catch (e) {
r2 = 0;
}
m = Math.pow(10, Math.max(r1, r2));
n = r1 >= r2 ? r1 : r2;
return toFixed(Math.round(num1 * m - num2 * m) / m, n);
};
// 两个浮点数相乘
const Mul = (num1, num2) => {
let m = 0,
s1 = `${num1}`,
s2 = `${num2}`;
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)
);
};
// 两个浮点数相除
const Div = (num1, num2) => {
let t1, t2, r1, r2;
try {
t1 = `${num1}`.split('.')[1].length;
} catch (e) {
t1 = 0;
}
try {
t2 = `${num2}`.toString().split('.')[1].length;
} catch (e) {
t2 = 0;
}
r1 = Number(`${num1}`.replace('.', ''));
r2 = Number(`${num2}`.toString().replace('.', ''));
return (r1 / r2) * Math.pow(10, t2 - t1);
};
module.exports = {
toFixed,
Add,
Sub,
Mul,
Div
};
</script>
</body>
</html>
这个和这个一样,只不过一个是html,一个是js
下面这个封装方法,适用所有场合,并完全符合数学中的四舍五入规则
// val要保留的数据,places保留位数,type返回类型(1数字,2字符串)
function keepDecimals(val, places, type) {
let num = val + ''; // console.log(num, 'a') 字符串 0.015
let numStart = num.split('.')[0] ; // console.log(numStart, 'b' ) // 字符串 0
let numEnd = num.split('.')[1]; // console.log(numEnd, 'c') // 字符串 015
let powVal = Math.pow(10, places); // console.log(powVal,'d') // 数字类型 100
if (numEnd) {
console.log(numEnd,'e') // 字符串 015
num = Math.round(num * powVal) / powVal + '';
// console.log(num, 'f') // 字符串 0.02
if (num.split('.')[1]&&num.split('.')[1].length < places) {
// console.log(num,'g')
for (let n = 0; n < places - num.split('.')[1].length; n++) {
num += '0' ;
// console.log(num,'h')
}
}
} else {
// console.log(num, 'i')
num = numStart + '.';
// console.log(num, 'j')
for (let n = 0; n < places; n++) {
num += '0';
// console.log(num, 'k')
}
}
// console.log(num, 'L', num*1, num+'')
return type==1?num=num*1:num=num+''
// 或者直接 return num ;
// 毕竟这个类型其实无所谓,尝试了一下,拿到的都是 字符换。
// 计算的时候都要转成数字类型。直接乘 1
// 即: return num *1
}
let num = keepDecimals(0.015, 2, 2);
// console.log(num)
亲测有效,最后这个得到的结果都是字符串 类型的,当然这个type 值也可以不传,并且你要是想得到一个数字类型的值,在最后的结果后边直接 乘 1 就行(隐式转换)
// let num = keepDecimals(7.665666, 2)*1; console.log(num) // 数字类型 7.67
总的来说看你要啥类型的