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浮点数运算出现Bug的方法
Mar 12 Javascript
JavaScript中的关键字"VAR"使用详解 分享
Jul 31 Javascript
js的.innerHTML = ""IE9下显示有错误的解决方法
Sep 16 Javascript
深入理解Javascript动态方法调用与参数修改的问题
Dec 10 Javascript
jquery.hotkeys监听键盘按下事件keydown插件
May 11 Javascript
bootstrap IE8 兼容性处理
Mar 22 Javascript
浅谈 Vue 项目优化的方法
Dec 16 Javascript
使用vue-route 的 beforeEach 实现导航守卫(路由跳转前验证登录)功能
Mar 22 Javascript
vue-cli 如何打包上线的方法示例
May 08 Javascript
vue通信方式EventBus的实现代码详解
Jun 10 Javascript
Ant Design Pro 下实现文件下载的实现代码
Dec 03 Javascript
Vue自动构建发布脚本的方法示例
Jul 24 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中实现记住密码自动登录的代码
2011/03/02 PHP
那些年一起学习的PHP(二)
2012/03/21 PHP
解析PHP多种序列化与反序列化的方法
2013/06/06 PHP
安装ImageMagick出现error while loading shared libraries的解决方法
2014/09/23 PHP
linux中cd命令使用详解
2015/01/08 PHP
PHP+MySQL实现无极限分类栏目的方法
2015/12/23 PHP
php强大的时间转换函数strtotime
2016/02/18 PHP
学习PHP的数组总结【经验】
2016/05/05 PHP
php数据库操作model类(使用__call方法)
2016/11/16 PHP
php策略模式简单示例分析【区别于工厂模式】
2019/09/25 PHP
Javascript中的常见排序算法
2007/03/27 Javascript
js移除事件 js绑定事件实例应用
2012/11/28 Javascript
javascript 实现键盘上下左右功能的小例子
2013/09/15 Javascript
通过实例理解javascript中没有函数重载的概念
2015/06/03 Javascript
js实现跨域访问的三种方法
2015/12/09 Javascript
JavaScript实现审核流程状态的动态显示进度条
2017/03/15 Javascript
了解javascript中let和var及const关键字的区别
2019/05/24 Javascript
Python实现针对中文排序的方法
2017/05/09 Python
python简单商城购物车实例代码
2018/03/15 Python
解决Python3中的中文字符编码的问题
2018/07/18 Python
python抓取网页内容并进行语音播报的方法
2018/12/24 Python
PyQt5组件读取参数的实例
2019/06/25 Python
详解用Python为直方图绘制拟合曲线的两种方法
2019/08/21 Python
python 爬虫 实现增量去重和定时爬取实例
2020/02/28 Python
Python使用socketServer包搭建简易服务器过程详解
2020/06/12 Python
Python3爬虫mitmproxy的安装步骤
2020/07/29 Python
澳大利亚礼品卡商店:Gift Card Store
2019/06/24 全球购物
公司总经理工作职责管理办法
2014/02/28 职场文书
新品发布会主持词
2014/04/02 职场文书
三年级班级文化建设方案
2014/05/04 职场文书
公司向个人借款协议书范本
2014/10/09 职场文书
2014年物业管理工作总结
2014/11/21 职场文书
2015年招聘工作总结
2014/12/12 职场文书
幼儿教师年度个人总结
2015/02/05 职场文书
2015年世界粮食日演讲稿
2015/03/20 职场文书
Spring中bean集合注入的方法详解
2022/07/07 Java/Android