js计算精度问题, 这个函数是什么原理?
我们知道, js里面的计算有时候是有误差的,是因为JavaScript使用二进制表示浮点数,因此不能精确表示所有十进制数
比如0.1 + 0.2不等于0.30.14 * 100不等于14
我一般是用这个函数处理的
Math.signFigures = function(num, rank = 6) {
if(!num) return(0);
const sign = num / Math.abs(num);
const number = num * sign;
const temp = rank - 1 - Math.floor(Math.log10(number));
let ans;
if (temp > 0) {
ans = parseFloat(number.toFixed(temp));
}
else if (temp < 0) {
ans = Math.round(number / Math.pow(10, temp)) * temp;
}
else {
ans = Math.round(number);
}
return (ans * sign);
};
这个函数是从网上来的, 比如计算0.1 + 0.2, Math.sign(0.1 + 0.2)就很准确的等于0.3
我没明白这个函数的运行原理是啥, 看不懂
回复
1个回答
test
2024-07-07
数学函数
Math.log10(x) :以10为底的x的对数
Math.pow(x,y):x的y次方
Math.abs(x):x的绝对值
Math.floor(x):使x向下取整
console.log(Math.floor(5.95));// output: 5
console.log(Math.floor(5.05));// output: 5
console.log(Math.floor(5));// output: 5
console.log(Math.floor(-5.05)); // output: -6
x.toFixed:对x定点
Math.round(x):对x进行四舍五入
一些主要的代码
const sign = num / Math.abs(num);
上面是获取num的符号, 当num > 0, sign = 1; num < 0 , sign = -1; num = 0 情况 if(!num) return(0) 已经排除;
Math.log10(x) = y
Math.log10(1) = 0
Math.log10(10) = 1
Math.log10(100) = 2
Math.log10(1000) = 3
Math.log10(10000) = 4
上面x的位数比y的值多 1
, 那么 y + 1 就等于 x的位数; 但是log10(x)大多数情况下存在小数, 比如log10(88) = 1.94448..; 对此可以使用Math.floor(x) 向下取整,Math.floor(Math.log10(88)) = 1;所以 1 + Math.floor(Math.log10(number)
就是计算num的整数
位数;
Math.signFigures = function(num, rank = 6) {.......}
上面rank 默认设置为 6,也许是
单精度浮点数在大多数平台能够保证6位有效数字; 基于此
, 可以对原来的浮点数进行一些转换来解决丢失精度的问题。
const temp = rank - 1 - Math.floor(Math.log10(number));
= rank - (1 + Math.floor(Math.log10(number)));
1 + Math.floor(Math.log10(number) 是计算num的整数部分的位数, 令rank = 6, temp的含义是以6位有效数字的长度为分界点进行讨论:
- num的整数位数小于6时 temp > 0, 因为有效数位是6位,把num转化为一个定点数表示也没有问题,可以把temp设置为精确的小数部分(number.toFixed(temp));
- num的整数位数等于6时 temp = 0, 直接使用Math.round(number)进行四舍五入;
- num的整数位数大于6时 temp < 0, 此时要把num转化为一个整数; number / Math.pow(10, temp) 实际是把number扩大10的 |temp|次方倍
其他
可以这样:
if(Math.signFigures(x) == Math.signFigures(y)){
//TODO:
}
但如果像下面这样,有时候会发现 x 与 value 相差很多
let value = Math.signFigures(x); // 令x = 10000001,或者令x的位数大于默认的6
回复
适合作为回答的
- 经过验证的有效解决办法
- 自己的经验指引,对解决问题有帮助
- 遵循 Markdown 语法排版,代码语义正确
不该作为回答的
- 询问内容细节或回复楼层
- 与题目无关的内容
- “赞”“顶”“同问”“看手册”“解决了没”等毫无意义的内容