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获取location.href的参数实例代码
Aug 02 Javascript
JavaScript自定义日期格式化函数详细解析
Jan 14 Javascript
字段太多jquey快速清空表单内容方法
Aug 21 Javascript
JavaScript操作Cookie详解
Feb 28 Javascript
浅析BootStrap Treeview的简单使用
Oct 12 Javascript
JavaScript 中 avalon绑定属性总结
Oct 19 Javascript
js实现文字选中分享功能
Jan 25 Javascript
如何编写一个d.ts文件的步骤详解
Apr 13 Javascript
JavaScript实现封闭区域布尔运算的示例代码
Jun 25 Javascript
浅探express路由和中间件的实现
Sep 30 Javascript
微信小程序用户盒子、宫格列表的实现
Jul 01 Javascript
Vue深入理解插槽slot的使用
Aug 05 Vue.js
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/04/20 PHP
php用户名的密码加密更安全的方法
2019/06/21 PHP
Laravel 不同生产环境服务器的判断实践
2019/10/15 PHP
PHP开发API接口签名生成及验证操作示例
2020/05/27 PHP
JS input 数字验证代码
2009/07/30 Javascript
nodejs实现获取某宝商品分类
2015/05/28 NodeJs
JQuery日期插件datepicker的使用方法
2016/03/03 Javascript
用jQuery向div中添加Html文本内容的简单实现
2016/07/13 Javascript
vue.js 1.x与2.0中js实时监听input值的变化
2017/03/15 Javascript
AjaxUpLoad.js实现文件上传功能
2018/03/02 Javascript
vue-cli 脚手架基于Nightwatch的端到端测试环境的过程
2018/09/30 Javascript
vue 微信分享回调iOS和安卓回调出现错误的解决
2020/09/07 Javascript
JavaScript中跨域问题的深入理解
2021/03/04 Javascript
Python的Django框架中的URL配置与松耦合
2015/07/15 Python
Python编程中对文件和存储器的读写示例
2016/01/25 Python
Python的时间模块datetime详解
2017/04/17 Python
Jupyter安装nbextensions,启动提示没有nbextensions库
2020/04/23 Python
pandas object格式转float64格式的方法
2018/04/10 Python
Python使用Flask-SQLAlchemy连接数据库操作示例
2018/08/31 Python
python抓取网页内容并进行语音播报的方法
2018/12/24 Python
Python使用folium excel绘制point
2019/01/03 Python
解决django同步数据库的时候app models表没有成功创建的问题
2019/08/09 Python
Python破解BiliBili滑块验证码的思路详解(完美避开人机识别)
2020/02/17 Python
Django使用Celery加redis执行异步任务的实例内容
2020/02/20 Python
python实现图像拼接
2020/03/05 Python
详解Windows下PyCharm安装Numpy包及无法安装问题解决方案
2020/06/18 Python
python安装读取grib库总结(推荐)
2020/06/24 Python
戴尔美国官网:Dell
2016/08/31 全球购物
女士鞋子、包包和服装在线,第一款10美元:ShoeDazzle
2019/07/26 全球购物
mysql有关权限的表都有哪几个
2015/04/22 面试题
大学生专业个人学习的自我评价
2013/10/26 职场文书
毕业自荐信
2013/12/16 职场文书
竞选班干部演讲稿
2014/04/24 职场文书
2014年乡镇领导个人整改措施
2014/09/19 职场文书
劳动模范获奖感言
2015/07/31 职场文书
感恩教师主题班会
2015/08/12 职场文书