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 相关文章推荐
Web Inspector:关于在 Sublime Text 中调试Js的介绍
Apr 18 Javascript
初步认识JavaScript函数库jQuery
Jun 18 Javascript
jquery自定义表格样式
Nov 23 Javascript
Kindeditor在线文本编辑器如何过滤HTML
Apr 14 Javascript
浅析JavaScript中命名空间namespace模式
Jun 22 Javascript
vue.js初学入门教程(2)
Nov 07 Javascript
前端开发不得不知的10个最佳ES6特性
Aug 30 Javascript
在 Typescript 中使用可被复用的 Vue Mixin功能
Apr 17 Javascript
vue中的$emit 与$on父子组件与兄弟组件的之间通信方式
May 13 Javascript
JavaScript中import用法总结
Jan 20 Javascript
浅谈Ant Design Pro 菜单自定义 icon
Nov 17 Javascript
vue el-upload上传文件的示例代码
Dec 21 Vue.js
利用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下载远程图片函数 可伪造来路
2013/06/25 PHP
php生成excel文件的简单方法
2014/02/08 PHP
round robin权重轮循算法php实现代码
2016/05/28 PHP
PHP 等比例缩放图片详解及实例代码
2016/09/18 PHP
JavaScript constructor和instanceof,JSOO中的一对欢喜冤家
2009/05/25 Javascript
使用jquery实现div的tab切换实例代码
2013/05/27 Javascript
js控制表单操作的常用代码小结
2013/08/15 Javascript
jQuery 中国省市两级联动选择附图
2014/05/14 Javascript
JavaScript模拟push
2016/03/06 Javascript
Javascript的this用法
2017/01/16 Javascript
用nodejs实现json和jsonp服务的方法
2017/08/25 NodeJs
koa上传excel文件并解析的实现方法
2018/08/09 Javascript
VUE搭建手机商城心得和遇到的坑
2019/02/21 Javascript
Element-UI+Vue模式使用总结
2020/01/02 Javascript
JS实现随机点名器
2020/04/12 Javascript
基于javascript处理nginx请求过程详解
2020/07/07 Javascript
Python实现的生成自我描述脚本分享(很有意思的程序)
2014/07/18 Python
Python使用Selenium+BeautifulSoup爬取淘宝搜索页
2018/02/24 Python
Python日期时间模块datetime详解与Python 日期时间的比较,计算实例代码
2018/09/14 Python
python数据类型之间怎么转换技巧分享
2019/08/20 Python
零基础小白多久能学会python
2020/06/22 Python
加拿大女装网上购物:Reitmans
2016/10/20 全球购物
菲律宾旅游网站:Expedia菲律宾
2017/10/11 全球购物
伊芙丽官方旗舰店:中国淑女一线品牌
2017/12/01 全球购物
eDreams意大利:南欧领先的在线旅行社
2018/11/23 全球购物
韩国保养品、日本药妆购物网:小三美日
2018/12/30 全球购物
缓解脚、腿和背部疼痛:Z-CoiL鞋
2019/03/12 全球购物
sort命令的作用和用法
2013/08/25 面试题
2014年学生会生活部工作总结
2014/11/07 职场文书
公积金贷款承诺书
2015/04/30 职场文书
反腐倡廉学习心得体会范文
2015/08/15 职场文书
校园安全学习心得体会
2016/01/18 职场文书
如何写好活动总结
2019/06/21 职场文书
详解nginx.conf 中 root 目录设置问题
2021/04/01 Servers
Python打包为exe详细教程
2021/05/18 Python
关于Python中进度条的六个实用技巧分享
2022/04/05 Python