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效果 slideToggle() 方法(在隐藏和显示之间切换)
Jun 28 Javascript
兼容IE、FireFox、Chrome等浏览器的xml处理函数js代码
Nov 30 Javascript
IE网页js语法错误2行字符1、FF中正常的解决方法
Sep 09 Javascript
详解AngularJS中自定义指令的使用
Jun 17 Javascript
JavaScript中使用sencha gridpanel 编辑单元格、改变单元格颜色
Nov 26 Javascript
thinkphp实现无限分类(使用递归)
Dec 19 Javascript
基于jquery实现最简单的选项卡切换效果
May 08 Javascript
提高JavaScript执行效率的23个实用技巧
Mar 01 Javascript
JavaScript之RegExp_动力节点Java学院整理
Jun 29 Javascript
BootStrap Table实现server分页序号连续显示功能(当前页从上一页的结束序号开始)
Sep 12 Javascript
实例分析JS与Node.js中的事件循环
Dec 12 Javascript
基于vue-cli3创建libs库的实现方法
Dec 04 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
40年前的这部特摄片恐龙特级克塞号80后的共同回忆
2020/03/08 日漫
php实现smarty模板无限极分类的方法
2015/12/07 PHP
php远程下载类分享
2016/04/13 PHP
简单PHP会话(session)说明介绍
2016/08/21 PHP
ThinkPHP5&5.1实现验证码的生成、使用及点击刷新功能示例
2020/02/07 PHP
js实时监听文本框状态的方法
2011/04/26 Javascript
基于JavaScript 数据类型之Boolean类型分析介绍
2013/04/19 Javascript
js实现无需数据库的县级以上联动行政区域下拉控件
2013/08/14 Javascript
js的toUpperCase方法用法实例
2015/01/27 Javascript
基于JavaScript代码实现随机漂浮图片广告
2016/01/05 Javascript
JavaScript实现下拉菜单的显示和隐藏
2016/01/05 Javascript
Bootstrap的class样式小结
2016/12/01 Javascript
Angular2利用组件与指令实现图片轮播组件
2017/03/27 Javascript
JS对象与json字符串相互转换实现方法示例
2018/06/14 Javascript
Vue v-for循环之@click点击事件获取元素示例
2019/11/09 Javascript
JavaScript如何判断input数据类型
2020/02/06 Javascript
Python使用urllib模块的urlopen超时问题解决方法
2014/11/08 Python
Python批量发送post请求的实现代码
2018/05/05 Python
Python使用Pandas库常见操作详解
2020/01/16 Python
Python实现数字的格式化输出
2020/08/01 Python
pycharm-professional-2020.1下载与激活的教程
2020/09/21 Python
html5 跨文档消息传输示例探讨
2013/04/01 HTML / CSS
全球知名旅游社区法国站点:TripAdvisor法国
2016/08/03 全球购物
Banggood官网:面向全球客户的综合商城
2017/04/19 全球购物
澳洲小众品牌的集合网站:BNKR
2018/02/23 全球购物
Hunkemöller西班牙:欧洲最大的内衣连锁店
2018/08/15 全球购物
俄罗斯游戏商店:Buka
2020/03/01 全球购物
实习自荐信
2013/10/13 职场文书
人事专员工作职责
2014/02/22 职场文书
市场部经理岗位职责
2015/02/02 职场文书
户外拓展训练感想
2015/08/07 职场文书
心得体会该怎么写呢?
2019/06/27 职场文书
【HBU】数据库第四周 单表查询
2021/04/05 SQL Server
企业版Windows 11有哪些新功能? Win11适用于企业的功能介绍
2021/11/21 数码科技
Win11快速关闭所有广告推荐
2022/04/19 数码科技
Nginx 常用配置
2022/05/15 Servers