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 相关文章推荐
Javascript技术技巧大全(五)
Jan 22 Javascript
msn上的tab功能Firefox对childNodes处理的一个BUG
Jan 21 Javascript
javascript生成不重复的随机数
Jul 17 Javascript
Javascript前端经典的面试题及答案
Mar 14 Javascript
jquery引入外部CDN 加载失败则引入本地jq库
May 23 jQuery
使用wxapp-img-loader自定义组件实现微信小程序图片预加载功能
Oct 18 Javascript
利用原生的JavaScript实现简单拼图游戏
Nov 18 Javascript
javascript+HTML5 canvas绘制时钟功能示例
May 15 Javascript
解决axios post 后端无法接收数据的问题
Oct 29 Javascript
jQuery实现弹幕特效
Nov 29 jQuery
原生javascript制作的拼图游戏实现方法详解
Feb 23 Javascript
js 实现验证码输入框示例详解
Sep 23 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获取开始与结束日期之间所有日期的方法
2016/11/29 PHP
PHP魔术方法之__call与__callStatic使用方法
2017/07/23 PHP
PHP正则匹配到2个字符串之间的内容方法
2018/12/24 PHP
javascript(jquery)利用函数修改全局变量的代码
2009/11/02 Javascript
CSS和Javascript简单复习资料
2010/06/29 Javascript
Wordpress ThickBox 点击图片显示下一张图的修改方法
2010/12/11 Javascript
P3P Header解决Cookie跨域的问题
2013/03/12 Javascript
点击A元素触发B元素的事件在IE8下会识别成A元素
2014/09/04 Javascript
javascript实现rgb颜色转换成16进制格式
2015/07/10 Javascript
JavaScript+html5 canvas绘制的圆弧荡秋千效果完整实例
2016/01/26 Javascript
javascript实现根据汉字获取简拼
2016/09/25 Javascript
vue-router跳转页面的方法
2017/02/09 Javascript
十大热门的JavaScript框架和库
2017/03/21 Javascript
vue使用axios实现文件上传进度的实时更新详解
2017/12/20 Javascript
通过vue-cli来学习修改Webpack多环境配置和发布问题
2017/12/22 Javascript
基于webpack-hot-middleware热加载相关错误的解决方法
2018/02/22 Javascript
浅谈React中的元素、组件、实例和节点
2018/02/27 Javascript
vue 组件中slot插口的具体用法
2018/04/03 Javascript
layui从数据库中获取复选框的值并默认选中方法
2018/08/15 Javascript
Vue 实例事件简单示例
2019/09/19 Javascript
Layui带搜索的下拉框的使用以及动态数据绑定方法
2019/09/28 Javascript
js实现鼠标拖曳效果
2020/12/30 Javascript
JavaScript WeakMap使用详解
2021/02/05 Javascript
Python基于贪心算法解决背包问题示例
2017/11/27 Python
使用python为mysql实现restful接口
2018/01/05 Python
python2.7读取文件夹下所有文件名称及内容的方法
2018/02/24 Python
sublime python3 输入换行不结束的方法
2018/04/19 Python
matplotlib 生成的图像中无法显示中文字符的解决方法
2020/06/10 Python
Python drop方法删除列之inplace参数实例
2020/06/27 Python
如何用Python编写一个电子考勤系统
2021/02/08 Python
阿姆斯特丹城市卡:Amsterdam Pass
2019/12/01 全球购物
电大自我鉴定
2013/10/27 职场文书
列车长先进事迹材料
2014/01/25 职场文书
幼儿园父亲节活动方案
2014/03/11 职场文书
2015年学生会纪检部工作总结
2015/03/31 职场文书
阿里云服务器Ubuntu 20.04上安装Odoo 15
2022/05/20 Servers