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+css+ul模拟列表菜单具体实现思路
Apr 15 Javascript
javascript之typeof、instanceof操作符使用探讨
May 19 Javascript
JSCode all of Brower 全局屏蔽网页右键功能 具体实现
Jun 05 Javascript
Javascript学习笔记之 对象篇(三) : hasOwnProperty
Jun 24 Javascript
JavaScript 里的类数组对象
Apr 08 Javascript
javascript类型系统——日期Date对象全面了解
Jul 13 Javascript
分享JavaScript监听全部Ajax请求事件的方法
Aug 28 Javascript
基于JavaScript实现自动更新倒计时效果
Dec 19 Javascript
bootstrap laydate日期组件使用详解
Jan 04 Javascript
jQuery简单获取DIV和A标签元素位置的方法
Feb 07 Javascript
vue弹窗消息组件的使用方法
Sep 24 Javascript
Vuex的actions属性的具体使用
Apr 14 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
ftp类(myftp.php)
2006/10/09 PHP
php实现mysql数据库备份类
2008/03/20 PHP
php简单浏览目录内容的实现代码
2013/06/07 PHP
php颜色转换函数hex-rgb(将十六进制格式转成十进制格式)
2013/09/23 PHP
PHP中生成UUID自定义函数分享
2015/06/10 PHP
PHP超全局数组(Superglobals)介绍
2015/07/01 PHP
表单提交错误后返回内容消失问题的解决方法(PHP网站)
2015/10/20 PHP
不错的一个日期输入 动态
2006/11/06 Javascript
js 匿名调用实现代码
2009/06/19 Javascript
JS获取图片高度宽度的方法分享
2015/04/17 Javascript
jsonp跨域请求数据实现手机号码查询实例分析
2015/12/12 Javascript
JS实现禁止用户使用Ctrl+鼠标滚轮缩放网页的方法
2017/04/28 Javascript
Javascript ES6中对象类型Sets的介绍与使用详解
2017/07/17 Javascript
Vue响应式原理深入解析及注意事项
2017/12/11 Javascript
JavaScript正则表达式函数总结(常用)
2018/02/22 Javascript
解决vue页面DOM操作不生效的问题
2018/03/17 Javascript
vue实现同一个页面可以有多个router-view的方法
2018/09/20 Javascript
原生JS实现顶部导航栏显示按钮+搜索框功能
2019/12/25 Javascript
javascript设计模式 ? 状态模式原理与用法实例分析
2020/04/22 Javascript
解决vue中el-tab-pane切换的问题
2020/07/19 Javascript
antd vue table跨行合并单元格,并且自定义内容实例
2020/10/28 Javascript
[04:13]2014DOTA2国际邀请赛 专访DC目前形势不容乐观
2014/07/12 DOTA
Django 模型类(models.py)的定义详解
2019/07/19 Python
基于python解线性矩阵方程(numpy中的matrix类)
2019/10/21 Python
python3.6中anaconda安装sklearn踩坑实录
2020/07/28 Python
如何一键升级Python所有包
2020/11/05 Python
45个非常奇妙的CSS3 特性应用示例
2012/01/01 HTML / CSS
如何实现一个自定义类的序列化
2012/05/22 面试题
学生实习推荐信范文
2013/11/26 职场文书
后勤岗位职责
2013/11/26 职场文书
《一件运动衫》教学反思
2014/02/19 职场文书
委托书怎么写
2014/07/31 职场文书
2014年度安全工作总结
2014/12/04 职场文书
会计工作总结范文2014
2014/12/23 职场文书
go:垃圾回收GC触发条件详解
2021/04/24 Golang
大型强子对撞机再次重启探索“第五种自然力”
2022/04/29 数码科技