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 相关文章推荐
jQuery asp.net 用json格式返回自定义对象
Apr 07 Javascript
Javascript 类、命名空间、代码组织代码
Jul 31 Javascript
判断ie的两种简单方法
Aug 12 Javascript
原生js编写设为首页兼容ie、火狐和谷歌
Jun 05 Javascript
jquery图片滚动放大代码分享(2)
Aug 28 Javascript
纯JS打造网页中checkbox和radio的美化效果
Oct 13 Javascript
vue增删改查的简单操作
Jul 15 Javascript
使用vue如何构建一个自动建站项目
Feb 05 Javascript
JS实现可视化文件上传
Sep 08 Javascript
Vue 重置组件到初始状态的方法示例
Oct 10 Javascript
vue全局自定义指令-元素拖拽的实现代码
Apr 14 Javascript
如何在微信小程序里面退出小程序的方法
Apr 28 Javascript
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
ThinkPHP写第一个模块应用
2012/02/20 PHP
PHP SESSION的增加、删除、修改、查看操作
2015/03/20 PHP
PHP 以POST方式提交XML、获取XML,解析XML详解及实例
2016/10/26 PHP
PHP使用gearman进行异步的邮件或短信发送操作详解
2020/02/27 PHP
疯掉了,尽然有js写的操作系统
2007/04/23 Javascript
js escape,unescape解决中文乱码问题的方法
2010/05/26 Javascript
基于jquery的滚动条滚动固定div(附演示下载)
2012/10/29 Javascript
jQuery子属性过滤选择器用法分析
2015/02/10 Javascript
jQuery实现带滑动条的菜单效果代码
2015/08/26 Javascript
轻松实现javascript图片轮播特效
2016/01/13 Javascript
js滑动提示效果代码分享
2016/03/10 Javascript
Bootstrap Metronic完全响应式管理模板学习笔记
2016/07/08 Javascript
zepto与jquery的区别及zepto的不同使用8条小结
2016/07/28 Javascript
浅谈JS验证表单文本域输入空格的问题
2017/02/14 Javascript
Vue2单一事件管理组件通信
2017/05/09 Javascript
JS简单实现自定义右键菜单实例
2017/05/31 Javascript
vue.js评论发布信息可插入QQ表情功能
2017/08/08 Javascript
用最少的JS代码写出贪吃蛇游戏
2018/01/12 Javascript
vue中img src 动态加载本地json的图片路径写法
2019/04/25 Javascript
发布订阅模式在vue中的实际运用实例详解
2019/06/09 Javascript
JavaScript静态作用域和动态作用域实例详解
2019/06/17 Javascript
如何对react hooks进行单元测试的方法
2019/08/14 Javascript
深入理解javascript中的this
2021/02/08 Javascript
[01:33]一分钟玩转DOTA2第三弹:DOTA2&DotA快捷操作大对比
2014/06/04 DOTA
[02:18]《我与DAC》之工作人员:为了热爱DOTA2的玩家们
2018/03/28 DOTA
使用Python的Flask框架构建大型Web应用程序的结构示例
2016/06/04 Python
python先序遍历二叉树问题
2017/11/10 Python
在keras里面实现计算f1-score的代码
2020/06/15 Python
Unineed旗下时尚轻奢网站:FABHunt
2019/05/13 全球购物
Yahoo-PHP面试题3
2012/01/14 面试题
给女儿的表扬信
2014/01/18 职场文书
敬业奉献模范事迹材料
2014/12/24 职场文书
活动总结书怎么写
2015/05/11 职场文书
2015年学校办公室工作总结
2015/05/26 职场文书
同乡会致辞
2015/07/30 职场文书
mysql联合索引的使用规则
2021/06/23 MySQL