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 相关文章推荐
Stop SQL Server
Jun 21 Javascript
Jquery uploadify图片上传插件无法上传的解决方法
Dec 16 Javascript
简单的代码实现jquery定时器
Jan 03 Javascript
使用node.js 获取客户端信息代码分享
Nov 26 Javascript
jquery ajax分页插件的简单实现
Jan 27 Javascript
jquery自定义插件开发之window的实现过程
May 06 Javascript
jQuery Easyui datagrid/treegrid 清空数据
Jul 09 Javascript
bootstrap datetimepicker 日期插件在火狐下出现一条报错信息的原因分析及解决办法
Mar 08 Javascript
PHP自动加载autoload和命名空间的应用小结
Dec 01 Javascript
Node中使用ES6语法的基础教程
Jan 05 Javascript
基于ionic实现下拉刷新功能
May 10 Javascript
关于better-scroll插件的无法滑动bug(2021通过插件解决)
Mar 01 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
ThinkPHP模板判断输出Defined标签用法详解
2014/06/30 PHP
php打印输出棋盘的实现方法
2014/12/23 PHP
Yii2 RESTful中api的使用及开发实例详解
2016/07/06 PHP
PHP实现mysqli批量执行多条语句的方法示例
2017/07/22 PHP
PHP实现深度优先搜索算法(DFS,Depth First Search)详解
2017/09/16 PHP
cnblogs中在闪存中屏蔽某人的实现代码
2010/11/14 Javascript
JavaScript去掉数组中的重复元素
2011/01/13 Javascript
javascript 基础篇4 window对象,DOM
2012/03/14 Javascript
JavaScript操作XML文件之XML读取方法
2015/06/09 Javascript
javascript实现树形菜单的方法
2015/07/17 Javascript
如何通过js实现图片预览功能【附实例代码】
2016/03/30 Javascript
JavaScript易错知识点整理
2016/12/05 Javascript
浅谈$_FILES数组为空的原因
2017/02/16 Javascript
Vue加载json文件的方法简单示例
2019/01/28 Javascript
vue路由导航守卫和请求拦截以及基于node的token认证的方法
2019/04/07 Javascript
仿vue-cli搭建属于自己的脚手架的方法步骤
2019/04/17 Javascript
layui 实现二级弹窗弹出之后 关闭一级弹窗的方法
2019/09/18 Javascript
微信小程序事件流原理解析
2019/11/27 Javascript
基于Vue中的父子传值问题解决
2020/07/27 Javascript
[53:15]2018DOTA2亚洲邀请赛3月29日 小组赛A组 KG VS OG
2018/03/30 DOTA
Python脚本实现12306火车票查询系统
2016/09/30 Python
Python使用defaultdict读取文件各列的方法
2017/05/11 Python
Python3内置模块之base64编解码方法详解
2019/07/13 Python
解决pyshp UnicodeDecodeError的问题
2019/12/06 Python
PyCharm2019.3永久激活破解详细图文教程,亲测可用(不定期更新)
2020/10/29 Python
python简单实现插入排序实例代码
2020/12/16 Python
美国高级音响品牌:Master&Dynamic
2018/07/05 全球购物
说出一些常用的类,包,接口
2014/09/22 面试题
生产车间实习自我鉴定
2013/09/23 职场文书
服务口号大全
2014/06/11 职场文书
工作求职信
2014/07/04 职场文书
绿色小区申报材料
2014/08/22 职场文书
医院护士党的群众路线教育实践活动对照检查材料思想汇报
2014/10/04 职场文书
表扬稿格式范文
2015/01/16 职场文书
航班延误投诉信
2015/07/02 职场文书
大学生入党自我鉴定范文
2019/06/21 职场文书