js 计算误差的原因 及 加减乘除计算方法

先附上代码,后面有原因分析及解决方案,感兴趣可以自行查看:

//加法
function Add(arg1, arg2) {
  var r1, r2, m;
  try {
    r1 = arg1.toString().split(".")[1].length;
  } catch (e) {
    r1 = 0;
  }
  try {
    r2 = arg2.toString().split(".")[1].length;
  } catch (e) {
    r2 = 0;
  }
  m = Math.pow(10, Math.max(r1, r2));
  return (Mul(arg1, m) + Mul(arg2, m)) / m;
}
//减法
function Sub(arg1, arg2) {
  var r1, r2, m;
  try {
    r1 = arg1.toString().split(".")[1].length;
  } catch (e) {
    r1 = 0;
  }
  try {
    r2 = arg2.toString().split(".")[1].length;
  } catch (e) {
    r2 = 0;
  }
  m = Math.pow(10, Math.max(r1, r2));
  return (Mul(arg1, m) - Mul(arg2, m)) / m;
}
//乘法
function Mul(arg1, arg2) {
  var m = 0,
    s1 = arg1.toString(),
    s2 = arg2.toString();
  try {
    m += s1.split(".")[1].length;
  } catch (e) {}
  try {
    m += s2.split(".")[1].length;
  } catch (e) {}
  return (
    (Number(s1.replace(".", "")) * Number(s2.replace(".", ""))) /
    Math.pow(10, m)
  );
}

function Div(arg1, arg2) {
  var t1 = 0,
    t2 = 0,
    r1,
    r2;
  try {
    t1 = arg1.toString().split(".")[1].length;
  } catch (e) {}
  try {
    t2 = arg2.toString().split(".")[1].length;
  } catch (e) {}
  with(Math) {
    r1 = Number(arg1.toString().replace(".", ""));
    r2 = Number(arg2.toString().replace(".", ""));
    return (r1 / r2) * pow(10, t2 - t1);
  }
}



问题描述:

在做公司库存数量的逻辑时踩到的大坑,如果对于浮点数,直接在JavaScript中进行加减乘除四则运算会出现很大的误差。问题产生的原因在于,计算机中是将十进制的数据转化为二进制来进行计算的,而对于浮点型的数据,转化成二进制之后可能会变成一个无限循环的数字,而计算机中是不允许无限循环的存在的,那就要做截断,而截断后的数据运算之后再转成十进制就可能会产生极大的误差。

其实并不是只JS存在这种问题,Java、C++也都如此,只不过他们内部都有封装好的方法来解决这个问题。JS是一门弱语言,没有做类似的操作。




原因分析:

浮点数是相对于定点数来说的。

计算机中小数的表示法,有定点和浮点两种。

定点,即小数点固定,比如:302876512411.25 小数点固定在数字的个位数右边
浮点,即小数点不固定(浮动),3.028e+11 小数点不固定在个位数和小数之间,而是根据指数值进行前后浮动

可以这么理解,科学记数法就是浮点数的表示方式

那么,我们为什么要使用浮点数呢?

我们可以先考虑下,为什么要使用科学记数法?

302876512411.25
3.028e+11

科学记数法的核心就是:通过移动小数点,只在小数点前保留一位数字,其他都算作小数,并使用指数记录小数点移动的位数

好处是,通过指数就可以很直观的看出数值的大小(而不用个十百千万的数)

其实它还有另一个好处,如果省略小数点后几位的话,它会显得很廋,不像原值那么臃肿(缺点是精度丢失)




解决方案:

看到网上也有用toFixed()方法来解决的,但是这种四舍五入的方式在高精度需求下也显得不那么严谨。

最常用的方法就是把需要计算的数字升级(乘以10的n次幂)成计算机能够精确识别的整数,等计算完毕再降级(除以10的n次幂),这是大部分编程语言处理精度差异的通用方法。 

欢迎留言交流,QQ:1960816818

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天府之绝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值