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的类型简单说明
Sep 03 Javascript
JavaScript高级程序设计(第3版)学习笔记5 js语句
Oct 11 Javascript
javascript精确统计网站访问量实例代码
Dec 19 Javascript
微信小程序 rpx 尺寸单位详细介绍
Oct 13 Javascript
vue中mint-ui环境搭建详细介绍
Apr 06 Javascript
Angular2使用jQuery的方法教程
May 28 jQuery
JS函数节流和函数防抖问题分析
Dec 18 Javascript
原生JS写Ajax的请求函数功能
Dec 22 Javascript
Vue 使用 Mint UI 实现左滑删除效果CellSwipe
Apr 27 Javascript
简单了解JavaScript异步
May 23 Javascript
JavaScript编码小技巧分享
Sep 17 Javascript
(开源)微信小程序+mqtt,esp8266温湿度读取
Apr 02 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
一个ORACLE分页程序,挺实用的.
2006/10/09 PHP
PHP 多维数组排序实现代码
2009/08/05 PHP
使用VisualStudio开发php的图文设置方法
2010/08/21 PHP
基于initPHP的框架介绍
2013/04/18 PHP
zend optimizer在wamp的基础上安装图文教程
2013/10/26 PHP
php 表单提交大量数据发生丢失的解决方法
2014/03/03 PHP
PHP连接SQLServer2005的方法
2015/01/27 PHP
PHP微信红包API接口
2015/12/05 PHP
php源码 fsockopen获取网页内容实例详解
2016/09/24 PHP
PHP实现转盘抽奖算法分享
2020/04/15 PHP
网易JS面试题与Javascript词法作用域说明
2010/11/09 Javascript
学习JavaScript的最佳方法分享
2011/10/21 Javascript
jquery 获取自定义属性(attr和prop)的实现代码
2012/06/27 Javascript
Jquery ajax执行顺序 返回自定义错误信息(实例讲解)
2013/11/06 Javascript
推荐10 个很棒的 jQuery 特效代码
2015/10/04 Javascript
javascript新闻跑马灯实例代码
2020/07/29 Javascript
DIV+CSS+jQ实现省市联动可扩展
2016/06/22 Javascript
AngularJs Managing Service Dependencies详解
2016/09/02 Javascript
用瀑布流的方式在网页上插入图片的简单实现方法
2016/09/23 Javascript
nodejs入门教程五:连接数据库的方法分析
2017/04/24 NodeJs
详解如何将angular-ui的图片轮播组件封装成一个指令
2017/05/09 Javascript
基于jQuery对象和DOM对象和字符串之间的转化实例
2017/08/08 jQuery
如何理解Vue的render函数的具体用法
2017/08/30 Javascript
vue实现提示保存后退出的方法
2018/03/15 Javascript
vue弹出框组件封装实例代码
2019/10/31 Javascript
JavaScript实现原型封装轮播图
2020/12/27 Javascript
python 叠加等边三角形的绘制的实现
2019/08/14 Python
如何使用Python脚本实现文件拷贝
2019/11/20 Python
python飞机大战pygame游戏背景设计详解
2019/12/17 Python
瑞士网球商店:Tennis-Point
2020/03/12 全球购物
下述程序的作用是计算机数组中的最大元素值及其下标
2012/11/26 面试题
元宵节主持词
2014/03/25 职场文书
安康杯竞赛活动总结
2014/05/05 职场文书
解除财产保全担保书
2014/05/20 职场文书
python引入其他文件夹下的py文件具体方法
2021/05/23 Python
HTML5 新增内容和 API详解
2021/11/17 HTML / CSS