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+JS实现仿百度搜索结果中关键字变色效果
Aug 02 Javascript
JS实现多物体缓冲运动实例代码
Nov 29 Javascript
jquery插件corner实现圆角边框的方法
Mar 09 Javascript
jQuery获得document和window对象宽度和高度的方法
Mar 25 Javascript
JavaScript如何获取数组最大值和最小值
Nov 18 Javascript
Bootstrap所支持的表单控件实例详解
May 16 Javascript
Vuex简单入门
Apr 19 Javascript
Canvas放置反弹效果随机图形(实例)
Aug 17 Javascript
JavaScript实现AOP详解(面向切面编程,装饰者模式)
Dec 19 Javascript
小程序实现展开/收起的效果示例
Sep 22 Javascript
使用layui日期控件laydate对开始和结束时间进行联动控制的方法
Sep 06 Javascript
viewer.js一个强大的基于jQuery的图像查看插件(支持旋转、缩放)
Apr 01 jQuery
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
967 个函式
2006/10/09 PHP
php 过滤英文标点符号及过滤中文标点符号代码
2014/06/12 PHP
smarty中常用方法实例总结
2015/08/07 PHP
Yii框架中用response保存cookie,用request读取cookie的原理解析
2019/09/04 PHP
javascript 复杂的嵌套环境中输出单引号和双引号
2009/05/26 Javascript
用jquery生成二级菜单的实例代码
2013/06/24 Javascript
JavaScript 32位整型无符号操作示例
2013/12/08 Javascript
jQuery的cookie插件实现保存用户登陆信息
2014/04/15 Javascript
zepto中使用swipe.js制作轮播图附swipeUp,swipeDown不起效果问题
2015/08/27 Javascript
JS获取当前脚本文件的绝对路径
2016/03/02 Javascript
深入解析Javascript闭包的功能及实现方法
2016/07/10 Javascript
JavaScript实现通过select标签跳转网页的方法
2016/09/29 Javascript
JS实现鼠标移上去显示图片或微信二维码
2016/12/14 Javascript
浅谈angular4生命周期钩子
2017/09/05 Javascript
jQuery实现倒计时功能 jQuery实现计时器功能
2017/09/19 jQuery
js指定日期增加指定月份的实现方法
2018/12/19 Javascript
JS中封装axios来管控api的2种方式
2019/09/11 Javascript
详解vue或uni-app的跨域问题解决方案
2020/02/21 Javascript
js函数柯里化的方法和作用实例分析
2020/04/11 Javascript
python编程羊车门问题代码示例
2017/10/25 Python
对Python 数组的切片操作详解
2018/07/02 Python
python批量赋值操作实例
2018/10/22 Python
python3使用QQ邮箱发送邮件
2020/05/20 Python
python基于itchat模块实现微信防撤回
2019/04/29 Python
让你Python到很爽的加速递归函数的装饰器
2019/05/26 Python
Python数据存储之 h5py详解
2019/12/26 Python
python操作gitlab API过程解析
2019/12/27 Python
jupyter实现重新加载模块
2020/04/16 Python
Pycharm 跳转回之前所在页面的操作
2021/02/05 Python
主管职责范文
2013/11/09 职场文书
医院节能减排方案
2014/06/13 职场文书
安全生产一岗双责责任书
2014/07/28 职场文书
联谊活动总结
2014/08/28 职场文书
走群众路线学习心得体会
2014/10/31 职场文书
病人慰问信范文
2015/02/15 职场文书
利用Selenium添加cookie实现自动登录的示例代码(fofa)
2021/05/08 Python