javascript避免数字计算精度误差的方法详解


Posted in Javascript onMarch 05, 2014

如果我问你 0.1 + 0.2 等于几?你可能会送我一个白眼,0.1 + 0.2 = 0.3 啊,那还用问吗?连幼儿园的小朋友都会回答这么小儿科的问题了。但是你知道吗,同样的问题放在编程语言中,或许就不是想象中那么简单的事儿了。
不信?我们先来看一段 JS。

var numA = 0.1;
var numB = 0.2;
alert( (numA + numB) === 0.3 );

执行结果是 false。没错,当我第一次看到这段代码时,我也理所当然地以为它是 true,但是执行结果让我大跌眼镜,是我的打开方式不对吗?非也非也。我们再执行以下代码试试就知道结果为什么是 false 了。

var numA = 0.1;
var numB = 0.2;
alert( numA + numB );

原来,0.1 + 0.2 = 0.30000000000000004。是不是很奇葩?其实对于浮点数的四则运算,几乎所有的编程语言都会有类似精度误差的问题,只不过在 C++/C#/Java 这些语言中已经封装好了方法来避免精度的问题,而 JavaScript 是一门弱类型的语言,从设计思想上就没有对浮点数有个严格的数据类型,所以精度误差的问题就显得格外突出。下面就分析下为什么会有这个精度误差,以及怎样修复这个误差。

首先,我们要站在计算机的角度思考 0.1 + 0.2 这个看似小儿科的问题。我们知道,能被计算机读懂的是二进制,而不是十进制,所以我们先把 0.1 和 0.2 转换成二进制看看:

0.1 => 0.0001 1001 1001 1001…(无限循环)
0.2 => 0.0011 0011 0011 0011…(无限循环)

双精度浮点数的小数部分最多支持 52 位,所以两者相加之后得到这么一串 0.0100110011001100110011001100110011001100110011001100 因浮点数小数位的限制而截断的二进制数字,这时候,我们再把它转换为十进制,就成了 0.30000000000000004。

原来如此,那怎么解决这个问题呢?我想要的结果就是 0.1 + 0.2 === 0.3 啊!!!

有种最简单的解决方案,就是给出明确的精度要求,在返回值的过程中,计算机会自动四舍五入,比如:

var numA = 0.1;
var numB = 0.2;
alert( parseFloat((numA + numB).toFixed(2)) === 0.3 );

但是明显这不是一劳永逸的方法,如果有一个方法能帮我们解决这些浮点数的精度问题,那该多好。我们来试试下面这个方法:

Math.formatFloat = function(f, digit) {
    var m = Math.pow(10, digit);
    return parseInt(f * m, 10) / m;
}

var numA = 0.1;
var numB = 0.2;

alert(Math.formatFloat(numA + numB, 1) === 0.3);

这个方法是什么意思呢?为了避免产生精度差异,我们要把需要计算的数字乘以 10 的 n 次幂,换算成计算机能够精确识别的整数,然后再除以 10 的 n 次幂,大部分编程语言都是这样处理精度差异的,我们就借用过来处理一下 JS 中的浮点数精度误差。

如果下次再有人问你 0.1 + 0.2 等于几,你可要小心回答咯!!

Javascript 相关文章推荐
解析js中获得父窗口链接getParent方法以及各种打开窗口的方法
Jun 19 Javascript
《JavaScript函数式编程》读后感
Aug 07 Javascript
jQuery实现日期联动效果实例
Jul 26 Javascript
判断js的Array和Object的实现方法
Aug 29 Javascript
Angularjs中ng-repeat-start与ng-repeat-end的用法实例介绍
Dec 31 Javascript
浅谈事件冒泡、事件委托、jQuery元素节点操作、滚轮事件与函数节流
Jul 22 jQuery
详解如何在微信小程序中愉快地使用sass
Jul 30 Javascript
vue中render函数的使用详解
Oct 12 Javascript
layui的布局和表格的渲染以及动态生成表格的方法
Sep 18 Javascript
jQuery开发仿QQ版音乐播放器
Jul 10 jQuery
vue-cli或vue项目利用HBuilder打包成移动端app操作
Jul 29 Javascript
JavaScript如何实现防止重复的网络请求的示例
Jan 28 Javascript
javascript/jquery获取地址栏url参数的方法
Mar 05 #Javascript
js离开或刷新页面检测(且兼容FF,IE,Chrome)
Mar 05 #Javascript
js特殊字符过滤的示例代码
Mar 05 #Javascript
jquerymobile局部渲染的各种刷新方法小结
Mar 05 #Javascript
JqueryMobile动态生成listView并实现刷新的两种方法
Mar 05 #Javascript
jquery mobile动态添加元素之后不能正确渲染解决方法说明
Mar 05 #Javascript
thinkphp中常用的系统常量和系统变量
Mar 05 #Javascript
You might like
PHP转盘抽奖接口实例
2015/02/09 PHP
PHP基于自定义函数实现的汉字转拼音功能实例
2017/09/30 PHP
阿里云Win2016安装Apache和PHP环境图文教程
2018/03/11 PHP
php 使用ActiveMQ发送消息,与处理消息操作示例
2020/02/23 PHP
Centos7.7 64位利用本地完整安装包安装lnmp/lamp套件教程
2021/03/09 Servers
firefox中JS读取XML文件
2006/12/21 Javascript
jQuery Ajax请求状态管理器打包
2012/05/03 Javascript
jQuery数据缓存功能的实现思路及简单模拟
2013/05/27 Javascript
jQuery的cookie插件实现保存用户登陆信息
2014/04/15 Javascript
Bootstrap导航条可点击和鼠标悬停显示下拉菜单
2016/11/25 Javascript
JS库之wow.js使用方法
2017/09/14 Javascript
nodejs多版本管理总结
2018/04/03 NodeJs
Angular(5.2->6.1)升级小结
2018/12/27 Javascript
Javascript迭代、递推、穷举、递归常用算法实例讲解
2019/02/01 Javascript
深入学习TypeScript 、React、 Redux和Ant-Design的最佳实践
2019/06/17 Javascript
layui 上传文件_批量导入数据UI的方法
2019/09/23 Javascript
vue框架制作购物车小球动画效果实例代码
2019/09/26 Javascript
jquery将信息遍历到界面上实例代码
2020/01/21 jQuery
python实现用户登陆邮件通知的方法
2015/07/09 Python
python结合shell查询google关键词排名的实现代码
2016/02/27 Python
Python实现控制台中的进度条功能代码
2017/12/22 Python
对python字典元素的添加与修改方法详解
2018/07/06 Python
python hbase读取数据发送kafka的方法
2018/12/27 Python
python安装scipy的步骤解析
2019/09/28 Python
python 计算积分图和haar特征的实例代码
2019/11/20 Python
python集合能干吗
2020/07/19 Python
python学习笔记之多进程
2020/08/06 Python
凯特方迪化妆品官网:Kat Von D Beauty
2016/11/15 全球购物
英国女性时尚品牌:Apricot
2018/12/04 全球购物
美国正宗设计师眼镜在线零售商:EYEZZ
2019/03/23 全球购物
应届生体育教师自荐信
2013/10/03 职场文书
行政管理专业推荐信
2013/11/02 职场文书
工作求职自荐信
2014/06/13 职场文书
小学感恩节活动总结
2015/03/24 职场文书
小学教师读书笔记
2015/07/01 职场文书
Java实现简易的分词器功能
2021/06/15 Java/Android