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 相关文章推荐
javascript与CSS复习(三)
Jun 29 Javascript
一些常用且实用的原生JavaScript函数
Sep 08 Javascript
Javascript WebSocket使用实例介绍(简明入门教程)
Apr 16 Javascript
js数组操作常用方法
May 08 Javascript
JavaScript中的document.referrer在各种浏览器测试结果
Jul 18 Javascript
jquery获取当前元素索引值用法实例
Jun 10 Javascript
基于BootStrap Metronic开发框架经验小结【五】Bootstrap File Input文件上传插件的用法详解
May 12 Javascript
微信小程序之电影影评小程序制作代码
Aug 03 Javascript
jquery获取select选中值的文本,并赋值给另一个输入框的方法
Aug 21 jQuery
微信小程序封装自定义弹窗的实现代码
May 08 Javascript
使用kbone解决Vue项目同时支持小程序问题
Nov 08 Javascript
JS字符串补全方法padStart()和padEnd()
May 27 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
Amazon Prime Video平台《无限住人 -IMMORTAL-》2020年开始TV放送!
2020/03/06 日漫
浅谈PHP调用Webservice思路及源码分享
2014/06/04 PHP
PHP统一页面编码避免乱码问题
2015/04/09 PHP
php中file_get_contents()函数用法实例
2019/02/21 PHP
Yii框架操作cookie与session的方法实例详解
2019/09/04 PHP
javascript onmouseout 解决办法
2010/07/17 Javascript
关闭页面window.location事件未执行的原因及解决方法
2014/09/01 Javascript
JavaScript返回0-1之间随机数的方法
2015/04/06 Javascript
JavaScript中对DOM节点的访问、创建、修改、删除
2015/11/16 Javascript
jQuery移动web开发中的页面初始化与加载事件
2015/12/03 Javascript
简单谈谈JavaScript的同步与异步
2015/12/31 Javascript
纯JavaScript手写图片轮播代码
2016/10/20 Javascript
jquery处理checkbox(复选框)是否被选中实例代码
2017/06/12 jQuery
js自定义弹框插件的封装
2020/08/24 Javascript
AngularJS实现的输入框字数限制提醒功能示例
2017/10/26 Javascript
基于vue2.0实现简单轮播图
2017/11/27 Javascript
微信小程序progress组件使用详解
2018/01/31 Javascript
vue 页面加载进度条组件实例
2018/02/05 Javascript
vue百度地图 + 定位的详解
2019/05/13 Javascript
JavaScript实现的弹出遮罩层特效经典示例【基于jQuery】
2019/07/10 jQuery
ES6中Symbol、Set和Map用法详解
2019/08/20 Javascript
vue-cli2与vue-cli3在一台电脑共存的实现方法
2019/09/25 Javascript
vue项目启动出现cannot GET /服务错误的解决方法
2020/04/26 Javascript
javascript this指向相关问题及改变方法
2020/11/19 Javascript
[03:33]TI9战队采访 - Infamous
2019/08/20 DOTA
十个Python程序员易犯的错误
2015/12/15 Python
对python中raw_input()和input()的用法详解
2018/04/22 Python
美国礼品卡商城: Gift Card Mall
2017/08/25 全球购物
意大利消费电子产品购物网站:SLG Store
2019/12/26 全球购物
入团者的自我评价分享
2013/12/02 职场文书
人力资源专员岗位职责
2014/01/30 职场文书
新学期标语
2014/06/30 职场文书
镇党委书记群众路线整改措施思想汇报
2014/10/13 职场文书
婚宴新郎致辞
2015/07/28 职场文书
python实现简易自习室座位预约系统
2021/06/30 Python
Nginx静态压缩和代码压缩提高访问速度详解
2022/05/30 Servers