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 Ajax请求状态管理器打包
May 03 Javascript
JavaScript实现x秒后自动跳转到一个页面
Jan 03 Javascript
toggle()隐藏问题的解决方法
Feb 17 Javascript
基于canvas实现的钟摆效果完整实例
Jan 26 Javascript
Bootstrap入门书籍之(四)菜单、按钮及导航
Feb 17 Javascript
JavaScript 对象字面量讲解
Jun 06 Javascript
微信小程序 页面传值详解
Mar 10 Javascript
JS移动端/H5同时选择多张图片上传并使用canvas压缩图片
Jun 20 Javascript
Vue Promise的axios请求封装详解
Aug 13 Javascript
js设计模式之单例模式原理与用法详解
Aug 15 Javascript
Vue实现页面添加水印功能
Nov 09 Javascript
javascript全局自定义鼠标右键菜单
Dec 08 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
火影忍者:这才是千手柱间和扉间的真正死因,角都就比较搞笑了!
2020/03/10 日漫
不用数据库的多用户文件自由上传投票系统(3)
2006/10/09 PHP
dedecms 批量提取第一张图片最为缩略图的代码(文章+软件)
2009/10/29 PHP
PHP编码规范之注释和文件结构说明
2010/07/09 PHP
解析PHP中empty is_null和isset的测试
2013/06/29 PHP
php实现遍历目录并删除指定文件中指定内容
2015/01/21 PHP
Thinkphp整合微信支付功能
2016/12/14 PHP
PHP对象的浅复制与深复制的实例详解
2017/10/26 PHP
PHP实现链表的定义与反转功能示例
2018/06/09 PHP
关于PhpStorm设置点击编辑文件自动定位源文件的实现方式
2020/12/30 PHP
正则表达式搭配js轻松处理json文本方便而老古
2013/02/17 Javascript
jQuery操作Select选择的Text和Value(获取/设置/添加/删除)
2013/03/06 Javascript
JS 新增Cookie 取cookie值 删除cookie 举例详解
2014/10/10 Javascript
javascript 开发之百度地图使用到的js函数整理
2017/05/19 Javascript
基于node.js制作简单爬虫教程
2017/06/29 Javascript
关于JS解构的5种有趣用法
2019/09/05 Javascript
jquery实现点击弹出对话框
2020/02/08 jQuery
[01:11:27]2018DOTA2亚洲邀请赛小组赛 A组加赛 Newbee vs Optic
2018/04/03 DOTA
Python实现合并字典的方法
2015/07/07 Python
浅谈python和C语言混编的几种方式(推荐)
2017/09/27 Python
对python opencv 添加文字 cv2.putText 的各参数介绍
2018/12/05 Python
python实现LRU热点缓存及原理
2019/10/29 Python
python如何基于redis实现ip代理池
2020/01/17 Python
TensorFlow基本的常量、变量和运算操作详解
2020/02/03 Python
Python3实现飞机大战游戏
2020/04/24 Python
python计算auc的方法
2020/09/09 Python
怎样实现H5+CSS3手指滑动切换图片的示例代码
2019/05/05 HTML / CSS
美国最好的保健品打折网店:Swanson
2017/08/04 全球购物
New Balance比利时官方网站:购买鞋子和服装
2021/01/15 全球购物
大学四年职业生涯规划书范文
2014/01/02 职场文书
母亲节感恩活动记录
2014/03/16 职场文书
2014办公室副主任四风对照检查材料思想汇报
2014/09/20 职场文书
见习报告格式要求
2014/11/04 职场文书
2015年公路路政个人工作总结
2015/07/24 职场文书
职场:企业印章管理制度(模板)
2019/10/18 职场文书
Python编写nmap扫描工具
2021/07/21 Python