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 相关文章推荐
用javascript实现无刷新更新数据的详细步骤 asp
Dec 26 Javascript
jquery 模式对话框终极版实现代码
Sep 28 Javascript
让firefox支持IE的一些方法的javascript扩展函数代码
Jan 02 Javascript
Jquery插件easyUi表单验证提交(示例代码)
Dec 30 Javascript
javascript学习笔记整理(概述、变量、数据类型简介)
Oct 25 Javascript
node.js回调函数之阻塞调用与非阻塞调用
Nov 13 Javascript
JS动态创建元素的两种方法
Apr 20 Javascript
JQuery和HTML5 Canvas实现弹幕效果
Jan 04 Javascript
微信小程序 scroll-view实现上拉加载与下拉刷新的实例
Jan 21 Javascript
vue中当图片地址无效的时候,显示默认图片的方法
Sep 18 Javascript
webpack4与babel配合使es6代码可运行于低版本浏览器的方法
Oct 12 Javascript
详解vue中使用protobuf踩坑记
May 07 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
根德YB400的电路分析
2021/03/02 无线电
浅析PHP水印技术
2007/02/14 PHP
smarty内置函数config_load用法实例
2015/01/22 PHP
如何打开php的gd2库
2017/02/09 PHP
浅谈thinkphp5 instance 的简单实现
2017/07/30 PHP
laravel excel 上传文件保存到本地服务器功能
2019/11/14 PHP
jQuery.extend 函数的详细用法
2012/06/27 Javascript
JSON+HTML实现国家省市联动选择效果
2014/05/18 Javascript
js简单实现交换Li的值
2014/05/22 Javascript
JS判断浏览器是否支持某一个CSS3属性的方法
2014/10/17 Javascript
JS实现Fisheye效果动感放大菜单代码
2015/10/21 Javascript
微信小程序 页面跳转传参详解
2016/10/28 Javascript
Highcharts+NodeJS搭建数据可视化平台示例
2017/01/01 NodeJs
js中数组插入、删除元素操作的方法
2017/02/15 Javascript
Vue.js表单标签中的单选按钮、复选按钮和下拉列表的取值问题
2017/11/22 Javascript
基于node打包可执行文件工具_Pkg使用心得分享
2018/01/24 Javascript
Express的HTTP重定向到HTTPS的方法
2018/06/06 Javascript
Nodejs让异步变成同步的方法
2019/03/02 NodeJs
在JavaScript中如何访问暂未存在的嵌套对象
2019/06/18 Javascript
基于vue和websocket的多人在线聊天室
2020/02/01 Javascript
[46:00]DOTA2上海特级锦标赛主赛事日 - 2 胜者组第一轮#4EG VS Fnatic第一局
2016/03/03 DOTA
python使用rsa加密算法模块模拟新浪微博登录
2014/01/22 Python
Python实现全排列的打印
2018/08/18 Python
python清除字符串前后空格函数的方法
2018/10/21 Python
Python3爬取英雄联盟英雄皮肤大图实例代码
2018/11/14 Python
Python爬虫实现爬取百度百科词条功能实例
2019/04/05 Python
python 实现返回一个列表中出现次数最多的元素方法
2019/06/11 Python
Python爬虫之爬取淘女郎照片示例详解
2020/07/28 Python
AP澳洲中文网:澳洲正品直邮,包税收件无忧
2019/07/12 全球购物
Agoda中文官网:安可达(低价预订全球酒店)
2021/01/18 全球购物
高考自主招生自荐信
2013/10/20 职场文书
行政文员岗位职责
2013/11/08 职场文书
劳动实践课感言
2014/02/01 职场文书
医学生毕业自我鉴定
2014/03/26 职场文书
分居协议书范本(律师见证版)
2014/11/26 职场文书
原生Js 实现的简单无缝滚动轮播图的示例代码
2021/05/10 Javascript