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 相关文章推荐
在网页中控制wmplayer播放器
Jul 01 Javascript
msn上的tab功能Firefox对childNodes处理的一个BUG
Jan 21 Javascript
javascript处理table表格的代码
Dec 06 Javascript
Array的push与unshift方法性能比较分析
Mar 05 Javascript
javascript写的简单的计算器,内容很多,方法实用,推荐
Dec 29 Javascript
javascript中的事件代理初探
Mar 08 Javascript
jquery实现顶部向右伸缩的导航区域代码
Sep 02 Javascript
PHP获取当前页面完整URL的方法
Dec 02 Javascript
vue2.0实现倒计时的插件(时间戳 刷新 跳转 都不影响)
Mar 30 Javascript
JS中将多个逗号替换为一个逗号的实现代码
Jun 23 Javascript
BootStrap模态框和select2合用时input无法获取焦点的解决方法
Sep 01 Javascript
js封装成插件_Canvas统计图插件编写实例
Sep 12 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
解决dede生成静态页和动态页转换的一些问题,及火车采集入库生成动态的办法
2007/03/29 PHP
PHP 杂谈《重构-改善既有代码的设计》之四 简化条件表达式
2012/04/09 PHP
PHP数据类型之布尔型的介绍
2013/04/28 PHP
对淘宝URL中ID提取的PHP代码
2013/09/01 PHP
php共享内存段示例分享
2014/01/20 PHP
Symfony生成二维码的方法
2016/02/04 PHP
php实现压缩合并js的方法【附demo源码下载】
2016/09/22 PHP
php微信开发之关键词回复功能
2018/06/13 PHP
动态创建样式表在各浏览器中的差异测试代码
2011/09/13 Javascript
JSON无限折叠菜单编写实例
2013/12/16 Javascript
angular.bind使用心得
2015/10/26 Javascript
js实现鼠标左右移动,图片也跟着移动效果
2017/01/25 Javascript
jquery加载单文件vue组件的方法
2017/06/20 jQuery
JavaScript中发出HTTP请求最常用的方法
2018/07/12 Javascript
微信小程序实现登录遮罩效果
2018/11/01 Javascript
微信小程序实现元素渐入渐出动画效果封装方法
2019/05/18 Javascript
JS实现移动端可折叠导航菜单(现代都市风)
2020/07/07 Javascript
[48:38]DOTA2亚洲邀请赛 3.31 小组赛 B组 Mineski vs Secret
2018/03/31 DOTA
Python简单网络编程示例【客户端与服务端】
2017/05/26 Python
详解Python map函数及Python map()函数的用法
2017/11/16 Python
nginx黑名单和django限速,最简单的防恶意请求方法分享
2019/08/09 Python
Python pandas如何向excel添加数据
2020/05/22 Python
Python爬虫获取页面所有URL链接过程详解
2020/06/04 Python
快速解决pymongo操作mongodb的时区问题
2020/12/05 Python
CSS3 滤镜 webkit-filter详细介绍及使用方法
2012/12/27 HTML / CSS
Why do we need Unit test
2013/01/03 面试题
机电专业体育教师求职信
2013/09/21 职场文书
小学教研工作制度
2014/01/15 职场文书
大学生军训自我鉴定
2014/02/12 职场文书
《灰椋鸟》教学反思
2014/04/27 职场文书
优秀乡村医生事迹材料
2014/05/28 职场文书
单位单身证明样本
2014/10/11 职场文书
教师评职称工作总结2015
2015/04/20 职场文书
员工规章制度范本
2015/08/07 职场文书
商务信函英语问候语
2015/11/10 职场文书
基于Python实现股票收益率分析
2022/04/02 Python