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 返回时间戳所对应的具体时间
Jul 20 Javascript
javascript使用正则表达式检测IP地址
Dec 03 Javascript
基于jQuery实现搜索关键字自动匹配功能
Mar 26 Javascript
基于jquery插件实现拖拽删除图片功能
Aug 27 Javascript
Bootstrap在线电子商务网站实战项目5
Oct 14 Javascript
vue-auto-focus: 控制自动聚焦行为的 vue 指令方法
Aug 25 Javascript
JavaScript读写二进制数据的方法详解
Sep 09 Javascript
JavaScript原型式继承实现方法
Nov 06 Javascript
element-ui中按需引入的实现
Dec 25 Javascript
JavaScript监听触摸事件代码实例
Dec 30 Javascript
详解微信小程序「渲染层网络层错误」的解决方法
Jan 06 Javascript
二维码条形码生成的JavaScript脚本库
Jul 07 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
深入mysql_fetch_row()与mysql_fetch_array()的区别详解
2013/06/05 PHP
PHP图片库imagemagick安装方法
2014/09/23 PHP
php中文验证码实现方法
2015/06/18 PHP
laravel 解决强制跳转 https的问题
2019/10/22 PHP
cookie中的path与domain属性详解
2013/12/18 Javascript
JS中产生20位随机数以0-9为例也可以是a-z A-Z
2014/08/01 Javascript
基于jQuery的select下拉框选择触发事件实例分析
2016/11/18 Javascript
javascript基础知识讲解
2017/01/11 Javascript
让微信小程序支持ES6中Promise特性的方法详解
2017/06/13 Javascript
jQuery实现广告条滚动效果
2017/08/22 jQuery
AngularJS双向数据绑定原理之$watch、$apply和$digest的应用
2018/01/30 Javascript
jQuery中的类名选择器(.class)用法简单示例
2018/05/14 jQuery
layui动态渲染生成左侧3级菜单的方法(根据后台返回数据)
2019/09/23 Javascript
vuecli项目构建SSR服务端渲染的实现
2020/10/30 Javascript
Vue 3.0中jsx语法的使用
2020/11/13 Javascript
Bottle框架中的装饰器类和描述符应用详解
2017/10/28 Python
Python实现的选择排序算法示例
2017/11/29 Python
Python实现进程同步和通信的方法
2018/01/02 Python
利用pandas读取中文数据集的方法
2018/07/25 Python
删除DataFrame中值全为NaN或者包含有NaN的列或行方法
2018/11/06 Python
Python TCP通信客户端服务端代码实例
2019/11/21 Python
keras小技巧——获取某一个网络层的输出方式
2020/05/23 Python
Python实例教程之检索输出月份日历表
2020/12/16 Python
CSS+jQuery实现的在线答题功能
2015/04/25 HTML / CSS
Blue Nile台湾:钻石珠宝商,订婚首饰、结婚戒指和精品首饰
2017/11/24 全球购物
台湾东南旅游社网站:东南旅游
2019/02/11 全球购物
Scotch Porter官方网站:男士美容产品
2020/08/31 全球购物
康拓普公司Java笔面试
2016/09/23 面试题
食堂员工工作职责
2013/12/18 职场文书
践行三严三实心得体会
2014/10/13 职场文书
车间主任岗位职责
2015/02/03 职场文书
2015年度物业公司工作总结
2015/04/27 职场文书
责任书范本大全
2015/05/11 职场文书
农村婚礼司仪主持词
2015/06/29 职场文书
2015年教师节主持词
2015/07/03 职场文书
Python 详解通过Scrapy框架实现爬取百度新冠疫情数据流程
2021/11/11 Python