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 相关文章推荐
用js实现控制内容的向上向下滚动效果
Jun 26 Javascript
很多人都是用下面的js刷新站IP和PV
Sep 05 Javascript
JavaScript 基础知识 被自己遗忘的
Oct 15 Javascript
jquery定时滑出可最小化的底部提示层特效代码
Oct 02 Javascript
JavaScript实现简单的时钟实例代码
Nov 23 Javascript
jQuery实现类似淘宝网图片放大效果的方法
Jul 08 Javascript
JavaScript html5 canvas绘制时钟效果(二)
Mar 27 Javascript
jquery与js实现全选功能的区别
Jun 11 jQuery
详解vuex结合localstorage动态监听storage的变化
May 03 Javascript
JS判断字符串是否为整数的方法--简单的正则判断
Jul 23 Javascript
element中的$confirm的使用
Apr 26 Javascript
浅谈JavaScript中等号、双等号、 三等号的区别
Aug 06 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
第十四节--命名空间
2006/11/16 PHP
PHP连接MySQL数据的操作要点
2015/03/20 PHP
document.documentElement &amp;&amp; document.documentElement.scrollTop
2007/12/01 Javascript
使用jQuery实现的网页版的个人简历(可换肤)
2013/04/19 Javascript
node.js中的emitter.on方法使用说明
2014/12/10 Javascript
javascript正则表达式之search()用法实例
2015/01/19 Javascript
javascript实现点击商品列表checkbox实时统计金额的方法
2015/05/15 Javascript
浅析JavaScript 调试方法和技巧
2015/10/22 Javascript
javascript图片延迟加载实现方法及思路
2015/12/31 Javascript
JavaScript读二进制文件并用ajax传输二进制流的方法
2016/07/18 Javascript
jQuery 更改checkbox的状态,无效的解决方法
2016/07/22 Javascript
node.js学习之base64编码解码
2016/10/21 Javascript
JavaScript中无法通过div.style.left获取值的解决方法
2017/02/19 Javascript
ES6新特性三: Generator(生成器)函数详解
2017/04/21 Javascript
js实现图片旋转 js滚动鼠标中间对图片放大缩小
2017/07/05 Javascript
vue axios 表单提交上传图片的实例
2018/03/16 Javascript
bootstrap下拉框动态赋值方法
2018/08/10 Javascript
解决angular 使用原生拖拽页面卡顿及表单控件输入延迟问题
2020/04/21 Javascript
JavaScript位置参数实现原理及过程解析
2020/09/14 Javascript
TF-IDF与余弦相似性的应用(一) 自动提取关键词
2017/12/21 Python
Django高级编程之自定义Field实现多语言
2019/07/02 Python
详解python 降级到3.6终极解决方案
2020/02/06 Python
使用Keras加载含有自定义层或函数的模型操作
2020/06/10 Python
Python3 ffmpeg视频转换工具使用方法解析
2020/08/10 Python
pip/anaconda修改镜像源,加快python模块安装速度的操作
2021/03/04 Python
HTML5 3D书本翻页动画的实现示例
2019/08/28 HTML / CSS
亚历山大·王官网:Alexander Wang
2017/06/23 全球购物
班长岗位职责
2013/11/10 职场文书
物流管理专业职业生涯规划书
2014/01/06 职场文书
作弊检讨书1000字
2014/02/01 职场文书
职业培训师职业生涯规划
2014/02/18 职场文书
物业公司的岗位任命书
2014/06/06 职场文书
高一军训的心得体会
2014/09/01 职场文书
励志广播稿300字(5篇)
2014/09/15 职场文书
丧事答谢词
2015/01/05 职场文书
学校元旦晚会开场白
2015/05/29 职场文书