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 相关文章推荐
cssQuery()的下载与使用方法
Jan 12 Javascript
jQuery 表单验证扩展代码(一)
Oct 11 Javascript
Javascript和HTML5利用canvas构建Web五子棋游戏实现算法
Jul 17 Javascript
javascript date格式化示例
Sep 25 Javascript
Js参数值中含有单引号或双引号问题的解决方法
Nov 06 Javascript
JQuery以JSON方式提交数据到服务端示例代码
May 05 Javascript
搭建pomelo 开发环境
Jun 24 Javascript
javascript中函数作为参数调用的方法
Feb 09 Javascript
利用vue和element-ui设置表格内容分页的实例
Mar 02 Javascript
总结JavaScript在IE9之前版本中内存泄露问题
Apr 28 Javascript
JS实现的合并两个有序链表算法示例
Feb 25 Javascript
扫微信小程序码实现网站登陆实现解析
Aug 20 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&amp;&amp;mysql)六
2006/10/09 PHP
PHP数组及条件,循环语句学习
2012/11/11 PHP
zf框架的校验器InArray使用示例
2014/03/13 PHP
php集成套件服务器xampp安装使用教程(适合第一次玩PHP的新手)
2015/06/03 PHP
PHP入门教程之日期与时间操作技巧总结(格式化,验证,获取,转换,计算等)
2016/09/11 PHP
利用PHP_XLSXWriter代替PHPExcel的方法示例
2017/07/16 PHP
为超链接加上disabled后的故事
2010/12/10 Javascript
JS获得QQ号码的昵称,头像,生日的简单实例
2013/12/04 Javascript
Jquery简单分页实现方法
2015/07/24 Javascript
javascript 用函数实现继承详解
2016/05/28 Javascript
JS脚本实现动态给标签控件添加事件的方法
2016/06/02 Javascript
js移动焦点到最后位置的简单方法
2016/11/25 Javascript
Bootstrap BootstrapDialog使用详解
2017/02/17 Javascript
JS批量替换内容中关键词为超链接
2017/02/20 Javascript
说说AngularJS中的$parse和$eval的用法
2017/09/14 Javascript
zTree jQuery 树插件的使用(实例讲解)
2017/09/25 jQuery
vue实现form表单与table表格的数据关联功能示例
2019/01/29 Javascript
vue实现点击隐藏与显示实例分享
2019/02/13 Javascript
vue router动态路由设置参数可选问题
2019/08/21 Javascript
原生JavaScript之es6中Class的用法分析
2020/02/23 Javascript
vue+element实现图片上传及裁剪功能
2020/06/29 Javascript
Vue 的 v-model用法实例
2020/11/23 Vue.js
jQuery实现查看图片功能
2020/12/01 jQuery
Python脚本实现Web漏洞扫描工具
2016/10/25 Python
Python解析excel文件存入sqlite数据库的方法
2016/11/15 Python
python 捕获 shell/bash 脚本的输出结果实例
2017/01/04 Python
python3.4用循环往mysql5.7中写数据并输出的实现方法
2017/06/20 Python
python判断字符串是否是json格式方法分享
2017/11/07 Python
APIStar:一个专为Python3设计的API框架
2018/09/26 Python
python与C、C++混编的四种方式(小结)
2019/07/15 Python
解决pycharm每次打开项目都需要配置解释器和安装库问题
2020/02/26 Python
Python中bisect的用法及示例详解
2020/07/20 Python
我的理想演讲稿
2014/04/30 职场文书
预备党员思想汇报1000字
2014/10/07 职场文书
财务工作检讨书
2014/10/29 职场文书
公司员工辞职信范文
2015/05/12 职场文书