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 相关文章推荐
将字符串转换成gb2312或者utf-8编码的参数(js版)
Apr 10 Javascript
一个js过滤空格的小函数
Oct 10 Javascript
javascript url几种编码方式详解
Jun 06 Javascript
socket.io学习教程之深入学习篇(三)
Apr 29 Javascript
Vue.js实现在下拉列表区域外点击即可关闭下拉列表的功能(自定义下拉列表)
May 30 Javascript
基于JavaScript实现五子棋游戏
Aug 26 Javascript
jQuery幻灯片插件owlcarousel参数说明中文文档
Feb 27 jQuery
setTimeout时间设置为0详细解析
Mar 13 Javascript
vue中更改数组中属性,在页面中不生效的解决方法
Oct 30 Javascript
记一次react前端项目打包优化的方法
Mar 30 Javascript
vue中v-for循环选中点击的元素并对该元素添加样式操作
Jul 17 Javascript
Vue 实现对quill-editor组件中的工具栏添加title
Aug 03 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
浅谈电磁辐射对健康的影响
2021/03/01 无线电
php简单统计字符串单词数量的方法
2015/06/19 PHP
jQuery使用手册之 事件处理
2007/03/24 Javascript
基于JQUERY的两个ListBox子项互相调整的实现代码
2011/05/07 Javascript
js replace替换所有匹配的字符串
2014/02/13 Javascript
js创建一个input数组并绑定click事件的方法
2014/06/12 Javascript
jquery实现具有嵌套功能的选项卡
2016/02/12 Javascript
jQuery DataTables插件自定义Ajax分页实例解析
2020/04/28 Javascript
ionic实现滑动的三种方式
2016/08/27 Javascript
Vue中fragment.js使用方法详解
2017/03/09 Javascript
angular框架实现全选与单选chekbox的自定义
2017/07/06 Javascript
AngularJs每天学习之总体介绍
2017/08/07 Javascript
11个教程中不常被提及的JavaScript小技巧(推荐)
2019/04/17 Javascript
了解javascript中变量及函数的提升
2019/05/27 Javascript
node.js实现http服务器与浏览器之间的内容缓存操作示例
2020/02/11 Javascript
[01:54]TI4西雅图DOTA2选手欢迎晚宴 现场报道
2014/07/08 DOTA
[03:42]2018完美盛典-《加冕》
2018/12/16 DOTA
python调用cmd复制文件代码分享
2013/12/27 Python
Python中atexit模块的基本使用示例
2015/07/08 Python
Python设计模式之抽象工厂模式
2016/08/25 Python
Python正则表达式常用函数总结
2017/06/24 Python
python 上下文管理器使用方法小结
2017/10/10 Python
详解Django中间件的5种自定义方法
2018/07/26 Python
Python range、enumerate和zip函数用法详解
2019/09/11 Python
python3.7 利用函数os pandas利用excel对文件名进行归类
2019/09/29 Python
解决python彩色螺旋线绘制引发的问题
2019/11/23 Python
Python基于Tensor FLow的图像处理操作详解
2020/01/15 Python
Django ORM 查询表中某列字段值的方法
2020/04/30 Python
深入了解Python enumerate和zip
2020/07/16 Python
解决Pycharm双击图标启动不了的问题(JetBrains全家桶通用)
2020/08/07 Python
南非领先的在线旅行社:Travelstart南非
2016/09/04 全球购物
js实现弹框效果
2021/03/24 Javascript
销售主管岗位职责
2014/02/08 职场文书
2016年中秋节晚会领导致辞
2015/11/26 职场文书
MySQL中几种插入和批量语句实例详解
2021/09/14 MySQL
Golang解析JSON对象
2022/04/30 Golang