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 相关文章推荐
addRule在firefox下的兼容写法
Nov 30 Javascript
JQuery中的$.getJSON 使用说明
Mar 10 Javascript
jquery弹出层类代码分享
Dec 27 Javascript
使用JavaScript 编写简单计算器
Nov 24 Javascript
浅谈Unicode与JavaScript的发展史
Jan 19 Javascript
新手快速学习JavaScript免费教程资源汇总
Jun 25 Javascript
基于jQuery和CSS3制作响应式水平时间轴附源码下载
Dec 20 Javascript
jQuery实现自动输入email、时间和域名的方法
Aug 24 Javascript
javascript九宫格图片随机打乱位置的实现方法
Mar 15 Javascript
Vue的click事件防抖和节流处理详解
Nov 13 Javascript
详解小程序如何动态绑定点击的执行方法
Nov 26 Javascript
Vue ​v-model相关知识总结
Jan 28 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长字符串定义方法
2012/07/12 PHP
限制ckeditor上传图片文件大小的方法
2013/11/15 PHP
PHP实现模仿socket请求返回页面的方法
2014/11/04 PHP
php中动态变量用法实例
2015/06/10 PHP
PHP的mysqli_set_charset()函数讲解
2019/01/23 PHP
PHP xpath提取网页数据内容代码解析
2020/07/16 PHP
Javascript中的方法链(Method Chaining)介绍
2015/03/15 Javascript
JavaScript使用function定义对象并调用的方法
2015/03/23 Javascript
JavaScript读二进制文件并用ajax传输二进制流的方法
2016/07/18 Javascript
AngularJS使用ng-repeat指令实现下拉框
2016/08/23 Javascript
JS动态遍历json中所有键值对的方法(不知道属性名的情况)
2016/12/28 Javascript
原生js实现可拖拽效果
2017/02/28 Javascript
详解如何在 vue 项目里正确地引用 jquery 和 jquery-ui的插件
2017/06/01 jQuery
jQuery实现的弹幕效果完整实例
2017/09/06 jQuery
nodejs操作mongodb的填删改查模块的制作及引入实例
2018/01/02 NodeJs
JS中常用的消息框总结
2018/02/24 Javascript
VUE DOM加载后执行自定义事件的方法
2018/09/07 Javascript
jquery的$().each和$.each的区别
2019/01/18 jQuery
layUI实现三级导航菜单效果
2019/07/26 Javascript
js动态获取时间的方法分析
2019/08/02 Javascript
vue 实现LED数字时钟效果(开箱即用)
2019/12/08 Javascript
extjs图表绘制之条形图实现方法分析
2020/03/06 Javascript
python操作数据库之sqlite3打开数据库、删除、修改示例
2014/03/13 Python
Python切换pip安装源的方法详解
2016/11/18 Python
Django之创建引擎索引报错及解决详解
2019/07/17 Python
No module named ‘win32gui‘ 的解决方法(踩坑之旅)
2021/02/18 Python
Html5基于canvas实现电子签名并生成PDF文档
2020/12/07 HTML / CSS
美国保健品专家:Life Extension
2018/05/04 全球购物
西班牙Polo衫品牌:Polo Club
2020/08/09 全球购物
化工专业推荐信范文
2013/11/28 职场文书
上课迟到检讨书
2014/02/19 职场文书
结婚喜宴主持词
2014/03/14 职场文书
幼儿园教学工作总结2015
2015/05/12 职场文书
婚礼嘉宾致辞
2015/07/28 职场文书
浪漫婚礼主持词开场白
2015/11/24 职场文书
2016年12月份红领巾广播稿
2015/12/21 职场文书