JavaScript解决浮点数计算不准确问题的方法分析


Posted in Javascript onJuly 09, 2018

本文实例讲述了JavaScript解决浮点数计算不准确问题的方法。分享给大家供大家参考,具体如下:

最近在学习electron框架,想利用这个框架做一个简单的计算器demo。当我对小数进行运算时,发现了一个问题。

0.1+0.2=?

输出结果是:0.30000000000000004

为什么会这样呢?

其实对于浮点数的四则运算,几乎所有的编程语言都会有类似精度误差的问题,只不过在 C++/C#/Java 这些语言中已经封装好了方法来避免精度的问题,而 JavaScript 是一门弱类型的语言,从设计思想上就没有对浮点数有个严格的数据类型,所以精度误差的问题就显得格外突出。

首先我们分析一下为什么会出现这个精度误差?

首先,我们要站在计算机的角度思考 0.1 + 0.2 这个看似小儿科的问题。我们知道,能被计算机读懂的是二进制,而不是十进制,所以我们先把 0.1 和 0.2 转换成二进制看看:

0.1 => 0.0001 1001 1001 1001..(无限循环)
0.2 => 0.0011 0011 0011 0011…(无限循环)

上面我们发现0.1和0.2转化为二进制之后,变成了一个无限循环的数字,这在现实生活中,无限循环我们可以理解,但计算机是不允许无限循环的,对于无限循环的小数,计算机会进行舍入处理。进行双精度浮点数的小数部分最多支持52位,所以两者相加之后得到这么一串 0.0100110011001100110011001100110011001100110011001100 因浮点数小数位的限制而截断的二进制数字,这时候,我们再把它转换为十进制,就成了 0.30000000000000004。

知道了浮点数产生的原因,那么如何处理这个问题呢?

方法1:通过toFixed(num)方法来保留小数。因为这个方法是根据四舍五入来保留小数的,所以最后的计算结果不精确。

方法2:把要计算的数字升级(乘以10的n次幂)成计算机能够精确识别的整数,计算完以后再降级,推荐使用这一种方法。具体代码如下(主要有3个方法):

/*判断obj是否为一个整数*/
function isInteger(obj){
  return Math.floor(obj) === obj;
}
/**
* 将一个浮点数转换成整数,返回整数和倍数
* 如 3.14 》》314 倍数是100
*
*/
function toInteger(floatNum){
  var ret = {times:1,num:0};
  //是整数
  if(isInteger(floatNum)){
    ret.num = floatNum;
    return ret;
  }
  var strfi = floatNum + '';
  //查找小数点的下标
  var dotPos = strfi.indexOf('.');
  console.log('dotPos===='+dotPos);
  //获取小数的位数
  var len = strfi.substr(dotPos+1).length;
  console.log('len===='+len);
  //Math.pow(10,len)指定10的len次幂。
  var time = Math.pow(10,len);
  //将浮点数转化为整数
  var intNum = parseInt(floatNum*time + 0.5,10);
  console.log('intNum===='+intNum);
  ret.times = time;
  ret.num = intNum;
  return ret;
}
/**
*进行运算
*三个参数分别是要运算的两个数和运算符
*/
function operation(a,b,op){
  var o1 = toInteger(a);
  var o2 = toInteger(b);
  var n1 = o1.num;
  var n2 = o2.num;
  var t1 = o1.times;
  var t2 = o2.times;
  var max = t1 > t2 ? t1 : t2;
  var result = null;
  switch(op){
    case 'add':
      if(t1 === t2){
        result = n1 + n2;
      }else if(t1 > t2){
        result = n1 + n2 * (t1/t2);
      }else{
        result = n1 * (t2/t1) + n2;
      }
      return result / max;
      break;
    case 'subtract':
      if(t1 === t2){
        result = n1 - n2;
      }else if(t1 > t2){
        result = n1 - n2 * (t1/t2);
      }else{
        result = n1 * (t2/t1) - n2;
      }
      return result / max;
      break;
    case 'multiply':
      result = (n1 * n2)/(t1 * t2);
      return result;
      break;
    case 'divide':
      result = (n1 / n2)/(t2 / t1);
      return result;
      break;
  }
}

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
Javascript动态绑定事件的简单实现代码
Dec 25 Javascript
JQuery给元素添加/删除节点比如select
Apr 02 Javascript
JQuery操作iframe父页面与子页面的元素与方法(实例讲解)
Nov 20 Javascript
JS连连看源码完美注释版(推荐)
Dec 09 Javascript
原生javascript实现的分页插件pagenav
Aug 28 Javascript
基于jQuery实现的无刷新表格分页实例
Feb 17 Javascript
javascript鼠标滑过显示二级菜单特效
Nov 18 Javascript
vue单页开发父子组件传值思路详解
May 18 Javascript
JavaScript动态添加数据到表单并提交的几种方式
Jun 26 Javascript
解决微信授权成功后点击按返回键出现空白页和报错的问题
Jun 08 Javascript
JS this关键字在ajax中使用出现问题解决方案
Jul 17 Javascript
全面解析Vue中的$nextTick
Dec 24 Vue.js
Vue自定义指令封装节流函数的方法示例
Jul 09 #Javascript
JavaScript实现创建自定义对象的常用方式总结
Jul 09 #Javascript
vue-cli配置环境变量的方法
Jul 09 #Javascript
JS逻辑运算符短路操作实例分析
Jul 09 #Javascript
微信小程序中时间戳和日期的相互转换问题
Jul 09 #Javascript
使用async await 封装 axios的方法
Jul 09 #Javascript
bootstrap 弹出框modal添加垂直方向滚轴效果
Jul 09 #Javascript
You might like
php分页思路以及在ZF中的使用
2012/05/30 PHP
php管理nginx虚拟主机shell脚本实例
2014/11/19 PHP
php无限分类使用concat如何实现
2015/11/05 PHP
Zend Framework处理Json数据方法详解
2016/12/09 PHP
phpstudy2020搭建站点的实现示例
2020/10/30 PHP
JavaScipt中的Math.ceil() 、Math.floor() 、Math.round() 三个函数的理解
2010/04/29 Javascript
javascript preload&lazy load
2010/05/13 Javascript
基于jQuery的树控件实现代码(asp.net+json)
2010/07/11 Javascript
基于JQuery实现滚动到页面底端时自动加载更多信息
2014/01/31 Javascript
jQuery显示和隐藏 常用的状态判断方法
2015/01/29 Javascript
JavaScript汉诺塔问题解决方法
2015/04/21 Javascript
微信小程序 wxapp地图 map详解
2016/10/31 Javascript
jquery购物车结算功能实现方法
2020/10/29 Javascript
微信小程序进行微信支付的步骤昂述
2016/12/01 Javascript
Vue2递归组件实现树形菜单
2017/04/10 Javascript
vue2实现移动端上传、预览、压缩图片解决拍照旋转问题
2017/04/13 Javascript
微信小程序 自动登陆PHP源码实例(源码下载)
2017/05/08 Javascript
vue Render中slots的使用的实例代码
2017/07/19 Javascript
解决vuejs 使用value in list 循环遍历数组出现警告的问题
2018/09/26 Javascript
[01:35]2018完美盛典章节片——共竞
2018/12/17 DOTA
Python判断有效的数独算法示例
2019/02/23 Python
python 使用turtule绘制递归图形(螺旋、二叉树、谢尔宾斯基三角形)
2019/05/30 Python
Python 抓取微信公众号账号信息的方法
2019/06/14 Python
Python中常用的高阶函数实例详解
2020/02/21 Python
anaconda安装pytorch1.7.1和torchvision0.8.2的方法(亲测可用)
2021/02/01 Python
Canvas 文本转粒子效果的实现代码
2019/02/14 HTML / CSS
加拿大知名的国际儿童品牌:Hatley
2016/11/09 全球购物
Halston Heritage官网:简洁的日装,稍显奢华的晚装
2018/11/20 全球购物
体育教育专业毕业生自荐信
2013/11/15 职场文书
金融专业个人求职信范文
2013/11/28 职场文书
党校培训自我鉴定
2014/02/01 职场文书
驾驶员培训方案
2014/05/01 职场文书
毕业典礼演讲稿
2014/05/13 职场文书
2014年党员自我评议总结
2014/09/23 职场文书
党员思想汇报材料
2014/12/19 职场文书
2015年营销工作总结范文
2015/04/23 职场文书