JavaScript浮点数及运算精度调整详解


Posted in Javascript onOctober 21, 2016

JavaScript 只有一种数字类型 Number,而且在Javascript中所有的数字都是以IEEE-754标准格式表示的。浮点数的精度问题不是JavaScript特有的,因为有些小数以二进制表示位数是无穷的。

十进制       二进制
0.1              0.0001 1001 1001 1001 …
0.2              0.0011 0011 0011 0011 …
0.3              0.0100 1100 1100 1100 …
0.4              0.0110 0110 0110 0110 …
0.5              0.1
0.6              0.1001 1001 1001 1001 …

所以比如 1.1,其程序实际上无法真正的表示 ‘1.1′,而只能做到一定程度上的准确,这是无法避免的精度丢失:1.09999999999999999

在JavaScript中问题还要复杂些,这里只给一些在Chrome中测试数据:

console.log(1.0-0.9 == 0.1)  //false 
console.log(1.0-0.8 == 0.2)  //false 
console.log(1.0-0.7 == 0.3)  //false 
console.log(1.0-0.6 == 0.4)  //true 
console.log(1.0-0.5 == 0.5)  //true 
console.log(1.0-0.4 == 0.6)  //true 
console.log(1.0-0.3 == 0.7)  //true 
console.log(1.0-0.2 == 0.8)  //true 
console.log(1.0-0.1 == 0.9)  //true

那如何来避免这类 1.0-0.9 != 0.1 的非bug型问题发生呢?下面给出一种目前用的比较多的解决方案, 在判断浮点运算结果前对计算结果进行精度缩小,因为在精度缩小的过程总会自动四舍五入:

(1.0-0.9).toFixed(digits) // toFixed() 精度参数digits须在0与20之间 
console.log(parseFloat((1.0-0.9).toFixed(10)) === 0.1)  //true 
console.log(parseFloat((1.0-0.8).toFixed(10)) === 0.2)  //true 
console.log(parseFloat((1.0-0.7).toFixed(10)) === 0.3)  //true 
console.log(parseFloat((11.0-11.8).toFixed(10)) === -0.8)  //true

写成一个方法:

//通过isEqual工具方法判断数值是否相等 
function isEqual(number1, number2, digits){ 
 digits = digits == undefined? 10: digits; // 默认精度为10 
 return number1.toFixed(digits) === number2.toFixed(digits); 
} 
console.log(isEqual(1.0-0.7, 0.3)); //true 
//原型扩展方式,更喜欢面向对象的风格 
Number.prototype.isEqual = function(number, digits){ 
 digits = digits == undefined? 10: digits; // 默认精度为10 
 return this.toFixed(digits) === number.toFixed(digits); 
} 
console.log((1.0-0.7).isEqual(0.3)); //true

接下来,再来试试浮点数的运算,

console.log(1.79+0.12) //1.9100000000000001 
console.log(2.01-0.12)  //1.8899999999999997 
console.log(1.01*1.3)  //1.3130000000000002 
console.log(0.69/10)   //0.06899999999999999

解决方案:

//加法函数,用来得到精确的加法结果 
//说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显。这个函数返回较为精确的加法结果。 
//调用:accAdd(arg1,arg2) 
//返回值:arg1加上arg2的精确结果 
function accAdd(arg1,arg2){ 
 var r1,r2,m; 
 try{r1=arg1.toString().split(".")[1].length}catch(e){r1=0} 
 try{r2=arg2.toString().split(".")[1].length}catch(e){r2=0} 
 m=Math.pow(10,Math.max(r1,r2)) 
 return (arg1*m+arg2*m)/m 
} 
//给Number类型增加一个add方法,调用起来更加方便。 
Number.prototype.add = function (arg){ 
 return accAdd(arg,this); 
} 
 
//减法函数,用来得到精确的减法结果 
//说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显。这个函数返回较为精确的减法结果。 
//调用:accSub(arg1,arg2) 
//返回值:arg1减去arg2的精确结果 
function accSub(arg1,arg2){ 
 var r1,r2,m,n; 
 try{r1=arg1.toString().split(".")[1].length}catch(e){r1=0} 
 try{r2=arg2.toString().split(".")[1].length}catch(e){r2=0} 
 m=Math.pow(10,Math.max(r1,r2)); 
 //last modify by deeka 
 //动态控制精度长度 
 n=(r1>=r2)?r1:r2; 
 return ((arg1*m-arg2*m)/m).toFixed(n); 
}
//除法函数,用来得到精确的除法结果 
//说明:javascript的除法结果会有误差,在两个浮点数相除的时候会比较明显。这个函数返回较为精确的除法结果。 
//调用:accDiv(arg1,arg2) 
//返回值:arg1除以arg2的精确结果 
function accDiv(arg1,arg2){ 
 var t1=0,t2=0,r1,r2; 
 try{t1=arg1.toString().split(".")[1].length}catch(e){} 
 try{t2=arg2.toString().split(".")[1].length}catch(e){} 
 with(Math){ 
  r1=Number(arg1.toString().replace(".","")) 
  r2=Number(arg2.toString().replace(".","")) 
  return (r1/r2)*pow(10,t2-t1); 
 } 
} 
//给Number类型增加一个div方法,调用起来更加方便。 
Number.prototype.div = function (arg){ 
 return accDiv(this, arg); 
} 
 
//乘法函数,用来得到精确的乘法结果 
//说明:javascript的乘法结果会有误差,在两个浮点数相乘的时候会比较明显。这个函数返回较为精确的乘法结果。 
//调用:accMul(arg1,arg2) 
//返回值:arg1乘以arg2的精确结果 
function accMul(arg1,arg2) { 
 var m=0,s1=arg1.toString(),s2=arg2.toString(); 
 try{m+=s1.split(".")[1].length}catch(e){} 
 try{m+=s2.split(".")[1].length}catch(e){} 
 return Number(s1.replace(".",""))*Number(s2.replace(".",""))/Math.pow(10,m) 
} 
//给Number类型增加一个mul方法,调用起来更加方便。 
Number.prototype.mul = function (arg){ 
 return accMul(arg, this); 
} 
<br>//验证一下: 
console.log(accAdd(1.79, 0.12)); //1.91 
console.log(accSub(2.01, 0.12)); //1.89 
console.log(accDiv(0.69, 10));  //0.069<br>console.log(accMul(1.01, 1.3));  //1.313

改造之后,可以愉快地进行浮点数加减乘除操作了~以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Iframe 自适应高度并实时监控高度变化的js代码
Oct 30 Javascript
jquery中输入验证中一个不错的效果
Aug 21 Javascript
一些常用的JavaScript函数(json)附详细说明
May 25 Javascript
javascript 正则表达式相关应介绍
Nov 27 Javascript
判断是否安装flash player及当前版本的JS代码
Aug 08 Javascript
用js传递value默认值的示例代码
Sep 11 Javascript
最流行的Node.js精简型和全栈型开发框架介绍
Feb 26 Javascript
JS+CSS实现带有碰撞缓冲效果的竖向导航条代码
Sep 15 Javascript
通过点击jqgrid表格弹出需要的表格数据
Dec 02 Javascript
JS实现DOM删除节点操作示例
Apr 04 Javascript
layui的面包屑或者表单不显示的解决方法
Sep 05 Javascript
vue列表数据发生变化指令没有更新问题及解决方法
Jan 16 Javascript
利用Node.JS实现邮件发送功能
Oct 21 #Javascript
bootstrap中使用google prettify让代码高亮的方法
Oct 21 #Javascript
BootStrap网页中代码显示用法详解
Oct 21 #Javascript
网页瀑布流布局jQuery实现代码
Oct 21 #Javascript
js运动事件函数详解
Oct 21 #Javascript
javascript轮播图算法
Oct 21 #Javascript
使用BootStrap和Metroui设计的metro风格微网站或手机app界面
Oct 21 #Javascript
You might like
php中显示数组与对象的实现代码
2011/04/18 PHP
phalcon框架使用指南
2016/02/23 PHP
PHP聊天室简单实现方法详解
2018/12/08 PHP
PHP内置函数生成随机数实例
2019/01/18 PHP
JavaScript 学习 - 提高篇
2007/02/02 Javascript
JQuery文字列表向上滚动的代码
2013/11/13 Javascript
jQuery实现强制cookie过期方法汇总
2015/05/22 Javascript
jQuery遍历DOM元素与节点方法详解
2016/04/14 Javascript
JavaScript的继承实现小结
2017/05/07 Javascript
基于iScroll实现下拉刷新和上滑加载效果
2017/07/18 Javascript
微信小程序基于picker实现级联菜单
2019/02/15 Javascript
JS精确判断数据类型代码实例
2019/12/18 Javascript
详解搭建一个vue-cli的移动端H5开发模板
2020/01/17 Javascript
vue实现给div绑定keyup的enter事件
2020/07/31 Javascript
利用node.js开发cli的完整步骤
2020/12/29 Javascript
vue3弹出层V3Popup实例详解
2021/01/04 Vue.js
Python内置函数——__import__ 的使用方法
2017/11/24 Python
详解tensorflow载入数据的三种方式
2018/04/24 Python
python实现逆序输出一个数字的示例讲解
2018/06/25 Python
python 如何去除字符串头尾的多余符号
2019/11/19 Python
使用Python串口实时显示数据并绘图的例子
2019/12/26 Python
Python爬虫requests库多种用法实例
2020/05/28 Python
PyQt5实现画布小程序
2020/05/30 Python
Python 抓取数据存储到Redis中的操作
2020/07/16 Python
想学画画?python满足你!
2020/12/24 Python
HTML5实现动画效果的方式汇总
2016/02/29 HTML / CSS
HomeAway澳大利亚:预订你的度假屋,公寓、度假村、别墅等
2019/02/20 全球购物
女孩每月服装订阅盒:kidpik
2019/04/17 全球购物
函授毕业生自我鉴定范文
2014/03/25 职场文书
春节联欢会策划方案
2014/05/16 职场文书
2015年个人实习工作总结
2015/05/28 职场文书
任长霞观后感
2015/06/16 职场文书
2016年班主任培训心得体会
2016/01/07 职场文书
2016读书月活动心得体会
2016/01/14 职场文书
接收函
2019/04/22 职场文书
PyTorch 如何自动计算梯度
2021/05/23 Python