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无缝滚动代码
Jan 03 Javascript
javascript编程起步(第四课)
Feb 27 Javascript
Cookie 注入是怎样产生的
Apr 08 Javascript
锋利的jQuery 要点归纳(三) jQuery中的事件和动画(下:动画篇)
Mar 24 Javascript
jQuery-Tools-overlay 使用介绍
Jul 14 Javascript
javascript事件函数中获得事件源的两种不错方法
Mar 17 Javascript
JS获取网页图片name属性的方法
Apr 01 Javascript
JQuery插件ajaxfileupload.js异步上传文件实例
May 19 Javascript
JavaScript中的cacheStorage使用详解
Jul 29 Javascript
vue中axios的二次封装实例讲解
Oct 14 Javascript
flexible.js实现移动端rem适配方案
Apr 07 Javascript
JavaScript实现简单的弹窗效果
May 19 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
JS幻灯片可循环播放可平滑旋转带滚动导航(自写)
2013/08/05 Javascript
JS二维数组的定义说明
2014/03/03 Javascript
extJS中常用的4种Ajax异步提交方式
2014/03/07 Javascript
js数组的操作指南
2014/12/28 Javascript
JavaScript判断一个字符串是否包含指定子字符串的方法
2015/03/18 Javascript
js插件YprogressBar实现漂亮的进度条效果
2015/04/20 Javascript
简介JavaScript中strike()方法的使用
2015/06/08 Javascript
javascript禁止访客复制网页内容的实现代码
2015/08/05 Javascript
分享两段简单的JS代码防止SQL注入
2016/04/12 Javascript
Java框架SSH结合Easyui控件实现省市县三级联动示例解析
2016/06/12 Javascript
js实现简易垂直滚动条
2017/02/22 Javascript
Angular 4依赖注入学习教程之ValueProvider的使用(七)
2017/06/04 Javascript
jQuery复合事件用法示例
2017/06/10 jQuery
JavaScript中call和apply方法的区别实例分析
2018/08/03 Javascript
微信小程序实现星级评价
2019/11/20 Javascript
微信小程序缓存支持二次开发封装实现解析
2019/12/16 Javascript
手把手教您实现react异步加载高阶组件
2020/04/07 Javascript
详解在Vue.js编写更好的v-for循环的6种技巧
2020/04/14 Javascript
[04:10]2018年度CS GO玩家最喜爱的主播-完美盛典
2018/12/16 DOTA
在漏洞利用Python代码真的很爽
2007/08/26 Python
Python简明入门教程
2015/08/04 Python
Python2.7编程中SQLite3基本操作方法示例
2017/08/09 Python
pandas Dataframe行列读取的实例
2018/06/08 Python
Python解决两个整数相除只得到整数部分的实例
2018/11/10 Python
python 实现在无序数组中找到中位数方法
2020/03/03 Python
基于Python生成个性二维码过程详解
2020/03/05 Python
python GUI库图形界面开发之PyQt5布局控件QGridLayout详细使用方法与实例
2020/03/06 Python
Python多线程threading创建及使用方法解析
2020/06/17 Python
python爬虫请求头的使用
2020/12/01 Python
html5本地存储 localStorage操作使用详解
2016/09/20 HTML / CSS
大三学生入党思想汇报
2014/01/02 职场文书
大学生村官工作感言
2014/01/10 职场文书
岳父生日宴会答谢词
2014/01/13 职场文书
纪委书记群众路线整改措施思想汇报
2014/10/09 职场文书
用Python将库打包发布到pypi
2021/04/13 Python
《王国之心》迎来了发售的20周年, 野村哲发布贺图
2022/04/11 其他游戏