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控制上传文件的大小
Oct 26 Javascript
Javascript 读后台cookie代码
Sep 15 Javascript
基于jquery的多彩百分比 动态进度条 投票效果显示效果实现代码
Aug 28 Javascript
javascript常见操作汇总
Sep 03 Javascript
jquery实现移动端点击图片查看大图特效
Sep 11 Javascript
js跨域请求数据的3种常用的方法
Dec 01 Javascript
写给小白的JavaScript引擎指南
Dec 04 Javascript
Javascript数组中push方法用法分析
Oct 31 Javascript
JS实现手写parseInt的方法示例
Sep 24 Javascript
layer弹出层显示在top顶层的方法
Sep 11 Javascript
vue 实现tab切换保持数据状态
Jul 21 Javascript
JavaScript 如何在浏览器中使用摄像头
Dec 02 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
php格式化工具Beautify PHP小小BUG
2008/04/24 PHP
php 在windows下配置虚拟目录的方法介绍
2013/06/26 PHP
PHP图片加水印实现方法
2016/05/06 PHP
详谈php中 strtr 和 str_replace 的效率问题
2017/05/14 PHP
php实现微信企业号支付个人的方法详解
2017/07/26 PHP
php实现登录页面的简单实例
2019/09/29 PHP
javascript 关于# 和 void的区别分析
2009/10/26 Javascript
jquery中:input和input的区别分析
2011/07/13 Javascript
仅Firefox中链接A无法实现模拟点击以触发其默认行为
2011/07/31 Javascript
js比较和逻辑运算符的介绍
2013/03/10 Javascript
jQuery中:first-child选择器用法实例
2014/12/31 Javascript
使用jQueryMobile实现滑动翻页效果的方法
2015/02/04 Javascript
jQuery实现首页图片淡入淡出效果的方法
2015/06/10 Javascript
关于foreach循环中遇到的问题小结
2017/05/08 Javascript
利用node.js如何搭建一个简易的即时响应服务器
2017/05/28 Javascript
jQuery zTree插件使用简单教程
2019/08/16 jQuery
vue 实现websocket发送消息并实时接收消息
2019/12/09 Javascript
[49:05]OG vs Newbee 2019DOTA2国际邀请赛淘汰赛 胜者组 BO3 第二场 8.21.mp4
2020/07/19 DOTA
python开发之tkinter实现图形随鼠标移动的方法
2015/11/11 Python
解决安装tensorflow遇到无法卸载numpy 1.8.0rc1的问题
2018/06/13 Python
python使用turtle库与random库绘制雪花
2018/06/22 Python
python字典key不能是可以是啥类型
2020/08/04 Python
python实现逻辑回归的示例
2020/10/09 Python
Python如何telnet到网络设备
2021/02/18 Python
HTML5的Video标签有部分MP4无法播放的问题解析(多图)
2017/08/18 HTML / CSS
Allen Edmonds官方网站:一家美国优质男士鞋类及配饰制造商
2019/03/12 全球购物
Nike香港官网:Nike HK
2019/03/23 全球购物
27个经典Linux面试题及答案,你知道几个?
2013/01/10 面试题
车间调度岗位职责
2013/11/30 职场文书
上课说话检讨书大全
2014/01/22 职场文书
中学生励志演讲稿
2014/04/26 职场文书
销售员岗位职责范本
2015/04/11 职场文书
市级三好生竞选稿
2015/11/21 职场文书
党员公开承诺书(2016最新版)
2016/03/24 职场文书
分享一些Java的常用工具
2021/06/11 Java/Android
Nginx动静分离配置实现与说明
2022/04/07 Servers