Comments (1)
js精度问题
1.浮点数精度问题 2.大数精度问题
浮点数精度问题,比如 0.1 + 0.2 !== 0.3
大数精度问题,比如 9999 9999 9999 9999 == 1000 0000 0000 0000 1
toFixed 四舍五入结果不准确,比如 1.335.toFixed(2) == 1.33
四舍五入 toFixed()方法
let a = 2.446242342;
a = a.toFixed(2); // 输出结果为 2.45
let b = 2.335;
b = b.toFixed(2); // 输出结果为 2.33
round()、floor()、ceil() 等都不能真正的四舍五入,有精度问题。
ES6 在Number对象上面,新增一个极小的常量Number.EPSILON。它表示 1 与大于 1 的最小浮点数之间的差。
Number.EPSILON实际上是 JavaScript 能够表示的最小精度。误差如果小于这个值,就可以认为已经没有意义了,即不存在误差了。
round()
可以通过以下方式来确保精度是正确的:
let c = 2.446242342;
c = Math.round((c + Number.EPSILON) * 100) / 100; // 输出结果为 2.45
let d = 2.335;
d = Math.round((d + Number.EPSILON) * 100) / 100; // 输出结果为 2.34
// 能精确表示的整数范围上限,S为1个0,E为11个0,S为53个1
Math.pow(2, 53) - 1 === Number.MAX_SAFE_INTEGER // true
// 能精确表示的整数范围下限,S为1个1,E为11个0,S为53个1
-(Math.pow(2, 53) - 1) === Number.MIN_SAFE_INTEGER // true
[MIN_SAFE_INTEGER, MAX_SAFE_INTEGER] 的整数都可以精确表示,但是超出这个范围的整数就不一定能精确表示。这样就会产生所谓的大数精度丢失问题。
解决思路
首先考虑的是如何解决浮点数运算的精度问题,有 3 种思路:
1· 考虑到每次浮点数运算的偏差非常小(其实不然),可以对结果进行指定精度的四舍五入,比如可以parseFloat(result.toFixed(12));
2. 将浮点数转为整数运算,再对结果做除法。比如0.1 + 0.2,可以转化为(1 + 2)/10。 (转化后的两个整数相乘的结果有可能超过 MAX_SAFE_INTEGER)
3. 把浮点数转化为字符串,模拟实际运算的过程。
所以,最终考虑使用第三种方案,目前已经有了很多较为成熟的库,比如 bignumber.js,decimal.js,以及big.js等。
我们可以根据自己的需求来选择对应的工具。并且,这些库不仅解决了浮点数的运算精度问题,还支持了大数运算,并且修复了原生toFixed结果不准确的问题。
function toDecimal(num) {
return Math.round(num + Number.EPSILON);
}
以上方法虽然不会产生精度问题,但是它有一点小陷阱容易忽略。
toDecimal(-1.5) // -1 不是我们想要的结果
特殊精度解决方案
// 金额price(大于等于0)保留n(n一般为2)位小数,此方法不会有精度问题
function formatPrice(price, digit) {
const accuracyNum = Math.pow(10, digit);
return parseFloat(Math.round((price + Number.EPSILON) * accuracyNum) / accuracyNum).toFixed(digit);
}
将浮点数转为整数运算,运算结果附上小数点 的四则运算
,可能会出现数据溢出
//加
function add(arg1,arg2){
let digits1,digits2,maxDigits;
try{digits1=arg1.toString().split(".")[1].length}catch(e){digits1=0}
try{digits2=arg2.toString().split(".")[1].length}catch(e){digits2=0}
maxDigits=Math.pow(10,Math.max(digits1,digits2))
return (arg1*maxDigits+arg2*maxDigits)/maxDigits
}
//减
function sub(arg1,arg2){
let digits1,digits2,maxDigits;
try{digits1=arg1.toString().split(".")[1].length}catch(e){digits1=0}
try{digits2=arg2.toString().split(".")[1].length}catch(e){digits2=0}
maxDigits=Math.pow(10,Math.max(digits1,digits2));
return (arg1*maxDigits-arg2*maxDigits)/maxDigits;
}
//乘
function mul(arg1,arg2) {
let digits=0,s1=arg1.toString(),s2=arg2.toString();
try{digits+=s1.split(".")[1].length}catch(e){}
try{digits+=s2.split(".")[1].length}catch(e){}
return Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,digits);
}
//除
function div(arg1,arg2){
let int1=0,int2=0,digits1,digits2;
try{digits1=arg1.toString().split(".")[1].length}catch(e){digits1=0}
try{digits2=arg2.toString().split(".")[1].length}catch(e){digits2=0}
int1=Number(arg1.toString().replace(".",""))
int2=Number(arg2.toString().replace(".",""))
return (int1/int2)*Math.pow(10,digits2-digits1);
}
金额按照千分位格式化(不会有精度问题,不会有溢出问题)
const x= new BigNumber('123456789.123556789'); // 注意:参数必须为字符串,接口返回参数也必须为字符串
// 格式化(小数点)
console.log('-----x.toFormat()------', x.toFormat()); // '123,456,789.123556789'
console.log('-----x.toFormat(3)------', x.toFormat(2)); // '123,456,789.124'
from fe9-interview.
Related Issues (20)
- 微店: 将二维数组转成一维数组的方法有哪些(一面) HOT 1
- 有赞: 为什么在类实例中可以访问this.setState (二面) HOT 1
- 有赞: 介绍暂时性死区(一面) HOT 2
- 兑吧: prototype 和 proto 区别(一面) HOT 1
- 今日头条: 介绍下Promise,内部实现(一面) HOT 1
- 有赞: 在不改变原数组的前提下,添加或删除某个元素(一面) HOT 2
- 阿里巴巴: 使用伪码实现 npm install 部分内容(二面)
- 有赞: sum(2, 3)实现sum(2)(3)的效果(一面) HOT 1
- To Tom0121 前端开发中设计到什么模式 HOT 1
- 滴滴: JS异步解决方案的发展历程以及优缺点(一面) HOT 1
- 携程:数组去重和数组扁平化(一面) HOT 1
- 阿里巴巴:实现一些主流框架的循环渲染(笔试) HOT 1
- To littleKnave: 实现一个Promise.prototype.first(今日头条) HOT 1
- 阿里巴巴:浏览器的强缓存和协商缓存(一面) HOT 3
- 51 信用卡: apply,call,bind 的区别(一面) HOT 2
- 为什么使用 ctrl+f5 或启用开发者面板中 Disable cache 选项后还会存在读取缓存的现象 HOT 1
- 阿里:Koa-body原理(一面)
- 爱云校:算法两道(一、1-100所有的素数 二、快速排序)(笔试) HOT 2
- 如何将 node 标准的回调 API 在 fibjs 内转为"同步"调用形式(一面) HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from fe9-interview.