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设置控件的隐藏与显示的两种方法
Aug 21 Javascript
探讨:JavaScript ECAMScript5 新特性之get/set访问器
May 05 Javascript
js判断某个字符出现的次数的简单实例
Jun 03 Javascript
AngularJS基础 ng-csp 指令详解
Aug 01 Javascript
AngularJS基础 ng-if 指令用法
Aug 01 Javascript
javascript实现根据函数名称字符串动态执行函数的方法示例
Dec 28 Javascript
jQuery插件MovingBoxes实现左右滑动中间放大图片效果
Feb 28 Javascript
Webpack打包慢问题的完美解决方法
Mar 16 Javascript
Vue.js中的组件系统
May 30 Javascript
Vue+Typescript中在Vue上挂载axios使用时报错问题
Aug 07 Javascript
layui关闭层级、简单监听的实例
Sep 06 Javascript
微信小程序分享小程序码的生成(带参数)以及参数的获取
Mar 25 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
Smarty+QUICKFORM小小演示
2007/02/25 PHP
php防止恶意刷新与刷票的方法
2014/11/21 PHP
php gd等比例缩放压缩图片函数
2016/06/12 PHP
Yii框架使用魔术方法实现跨文件调用功能示例
2017/05/20 PHP
JS动画效果代码3
2008/04/03 Javascript
跨浏览器的 mouseenter mouseleave 以及 compareDocumentPosition的使用说明
2010/05/04 Javascript
js 中{},[]中括号,大括号使用详解
2011/05/12 Javascript
基于IE下ul li 互相嵌套时的bug,排查,解决过程以及心得介绍
2013/05/07 Javascript
简单几行JS Code实现IE邮件转发新浪微博
2013/07/03 Javascript
jquery及原生js获取select下拉框选中的值示例
2013/10/25 Javascript
javascript实现信息的显示和隐藏如注册页面
2013/12/03 Javascript
利用javascript实现全部删或清空所选的操作
2014/05/27 Javascript
Jquery节点遍历next与nextAll方法使用示例
2014/07/22 Javascript
浅谈EasyUI中Treegrid节点的删除
2015/03/01 Javascript
jquery+easeing实现仿flash的载入动画
2015/03/10 Javascript
详解Bootstrap插件
2016/04/25 Javascript
javascript简单实现跟随滚动条漂浮的返回顶部按钮效果
2016/08/19 Javascript
jQuery使用ajax方法解析返回的json数据功能示例
2017/01/10 Javascript
利用SpringMVC过滤器解决vue跨域请求的问题
2018/02/10 Javascript
js Element Traversal规范中的元素遍历方法
2018/04/19 Javascript
vuex + axios 做登录验证 并且保存登录状态的实例
2018/09/16 Javascript
Python实现图像几何变换
2015/07/06 Python
Python 控制终端输出文字的实例
2019/07/12 Python
使用 django orm 写 exists 条件过滤实例
2020/05/20 Python
Prometheus开发中间件Exporter过程详解
2020/11/30 Python
CSS3中的content属性使用示例
2015/07/20 HTML / CSS
日本亚马逊官方网站:Amazon.co.jp
2020/04/14 全球购物
weblogic面试题
2016/03/07 面试题
Java里面StringBuilder和StringBuffer有什么区别
2016/06/06 面试题
求职信范文英文版
2014/01/05 职场文书
电脑租赁公司创业计划书
2014/01/08 职场文书
捐款倡议书格式范文
2014/05/14 职场文书
任命书怎么写
2014/06/04 职场文书
2015年度个人工作总结报告
2015/10/24 职场文书
Vue实现导入Excel功能步骤详解
2021/07/03 Vue.js
用JS创建一个录屏功能
2021/11/11 Javascript