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 相关文章推荐
jQuery 瀑布流 绝对定位布局(二)(延迟AJAX加载图片)
May 23 Javascript
jquery动态添加option示例
Dec 30 Javascript
Node.js中的模块机制学习笔记
Nov 04 Javascript
javascript基础知识
Jun 07 Javascript
fullpage.js全屏滚动插件使用实例
Sep 06 Javascript
详解使用angular-cli发布i18n多国语言Angular应用
May 20 Javascript
Angular2学习教程之TemplateRef和ViewContainerRef详解
May 25 Javascript
基于openlayers4实现点的扩散效果
Aug 17 Javascript
vue通过路由实现页面刷新的方法
Jan 25 Javascript
原生JS+HTML5实现跟随鼠标一起流动的粒子动画效果
May 03 Javascript
javascript实现智能手环时间显示
Sep 18 Javascript
在Vue里如何把网页的数据导出到Excel的方法
Sep 30 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 获取远程文件内容的函数代码
2010/03/24 PHP
php+jquery+html实现点击不刷新加载更多的实例代码
2016/08/12 PHP
php无限级分类实现方法分析
2016/10/19 PHP
[原创]php token使用与验证示例【测试可用】
2017/08/30 PHP
thinkphp5.1框架中容器(Container)和门面(Facade)的实现方法分析
2019/08/05 PHP
TP5框架实现签到功能的方法分析
2020/04/05 PHP
javascript 函数使用说明
2010/04/07 Javascript
js中格式化日期时间型数据函数代码
2010/11/08 Javascript
javascript实现验证身份证号的有效性并提示
2015/04/30 Javascript
Javascript中判断对象是否为空
2015/06/10 Javascript
详解js中call与apply关键字的作用
2016/11/21 Javascript
vue如何将v-for中的表格导出来
2018/05/07 Javascript
详解如何构建一个Angular6的第三方npm包
2018/09/07 Javascript
微信小程序自定义导航栏
2018/12/31 Javascript
Element Dropdown下拉菜单的使用方法
2020/07/26 Javascript
vue中template的三种写法示例
2020/10/21 Javascript
[02:43]DOTA2英雄基础教程 半人马战行者
2014/01/13 DOTA
python 制作自定义包并安装到系统目录的方法
2018/10/27 Python
python3多线程知识点总结
2019/09/26 Python
Python连接字符串过程详解
2020/01/06 Python
django queryset相加和筛选教程
2020/05/18 Python
python利用paramiko实现交换机巡检的示例
2020/09/22 Python
顶级宝石首饰网络零售商:Angara
2016/10/25 全球购物
俄罗斯大型在线书店:Читай-город
2019/10/10 全球购物
意大利奢侈品牌在线精品店:Jole.it
2020/11/23 全球购物
某公司Java工程师面试题笔试题
2016/03/27 面试题
影视制作岗位职责
2013/12/04 职场文书
初二物理教学反思
2014/01/29 职场文书
加强作风建设工作总结
2014/10/23 职场文书
2014年组织部工作总结
2014/11/14 职场文书
2015年宣传工作总结
2015/04/08 职场文书
同学聚会通知短信
2015/04/20 职场文书
python - timeit 时间模块
2021/04/06 Python
python基础之while循环语句的使用
2021/04/20 Python
Python Django 后台管理之后台模型属性详解
2021/04/25 Python
Java使用jmeter进行压力测试
2021/07/09 Java/Android