问题

用js进行浮点数计算,结果可能会“超出预期”,大部分计算结果还是对的,但是我们可不想在计算这么严谨的事情上还有意外的惊喜。比如:

  • 0.3 + 0.6 = 0.8999999999999999
  • 0.3 - 0.2 = 0.09999999999999998
  • 0.3 * 1.5 = 0.44999999999999996
  • 0.3 / 0.1 = 2.9999999999999996

看完这几个计算结果,如果你没用过js,你可能会有点崩溃。我只能说,这就是js的魅力所在。

分析

在这之前,你需要知道以下几点:

  • js中数字类型只有Number;
  • js的Number是IEEE 754标准的64-bits的双精度数值

网上有很多关于此问题的解释,由于计算机是用二进制来存储和处理数字,不能精确表示浮点数,而js中没有相应的封装类来处理浮点数运算,直接计算会导致运算精度丢失。其实高级语言(c#,java)也存在此问题,只不过它们自己内部做了处理,把这种精度差异给屏蔽掉了。有些小数转换为二进制位数是无穷的(有循环),但是64位中小数最多只有52位,因此对于位数超过的相当于被截取了,导致了精度的丢失。这个地址可以用来浮点数和IEEE 754标准的64-bits的互转(背后是二进制的转换),用这个我们来验证下0.3-0.2。

  • 0.3转换后为0.299999999999999988897769753748
  • 0.2转换后为0.200000000000000011102230246252
  • 0.299999999999999988897769753748-0.200000000000000011102230246252=0.099999999999999977795539507496

这和js直接计算的结果0.09999999999999998想吻合。

分析下来,终于明白并不是js自身发育不良,只是没有及时补充营养,我们只能另想出路了。

解决方法

网上已经存在很多解决方法了,我这里也没有特别的方法,但是网上有很多方法只搞定了一半,仍然存在bug。大部分解决方法的思路是将浮点数计算转换为整数计算,整数计算当然是没有bug的啦。前面说网上部分方法只搞对了一半,对的一半是乘除法,加减法仍然有问题,因为加减法还存在浮点数的直接运算。

附:没有bug的代码。

function add(a, b) {
var c, d, e;
try {
c = a.toString().split(".")[1].length;
} catch (f) {
c = 0;
}
try {
d = b.toString().split(".")[1].length;
} catch (f) {
d = 0;
}
return e = Math.pow(10, Math.max(c, d)), (mul(a, e) + mul(b, e)) / e;
}
function sub(a, b) {
var c, d, e;
try {
c = a.toString().split(".")[1].length;
} catch (f) {
c = 0;
}
try {
d = b.toString().split(".")[1].length;
} catch (f) {
d = 0;
}
return e = Math.pow(10, Math.max(c, d)), (mul(a, e) - mul(b, e)) / e;
}
function mul(a, b) {
var c = 0,
d = a.toString(),
e = b.toString();
try {
c += d.split(".")[1].length;
} catch (f) {}
try {
c += e.split(".")[1].length;
} catch (f) {}
return Number(d.replace(".", "")) * Number(e.replace(".", "")) / Math.pow(10, c);
}
function div(a, b) {
var c, d, e = 0,
f = 0;
try {
e = a.toString().split(".")[1].length;
} catch (g) {}
try {
f = b.toString().split(".")[1].length;
} catch (g) {}
return c = Number(a.toString().replace(".", "")), d = Number(b.toString().replace(".", "")), mul(c / d, Math.pow(10, f - e));
}

JS浮点计算问题的更多相关文章

  1. JS 浮点计算BUG

    最近做项目的时候遇到一个比较纠结的js浮点计算问题. 当时是做利率计算,因为利率大多数涉及到小数点,精度要求也很高. 0.6+0.1+0.1=? 结果出现:0.7999999999999 网上查找了一 ...

  2. JS浮点计算精度问题分析与解决

    问题描述 在JS计算四则运算时会遇到精度丢失的问题,会引起诸多问题,看看以下例子: 例如:在chrome控制台输入 0.1 + 0.7 输出结果是 0.7999999999999999 例如:0.1+ ...

  3. js JS 浮点计算BUG

    Number.prototype.toRound = function(d) { var s=this+"";if(!d)d=0; if(s.indexOf(".&quo ...

  4. JS中toFixed()方法的问题及解决方案

    最近发现JS当中toFixed()方法存在一些问题,采用原生的Number对象的原型对象上的toFixed()方法时,规则并不是所谓的“四舍五入”或者是“四舍六入五成双”,所谓“四舍六入五成双”,在百 ...

  5. js浮点数的计算

        js在计算浮点数时可能不够准确,会产生舍入误差的问题,这是使用基于IEEE745数值的浮点计算的通病,并非ECMAScript一家,其他使用相同数值格式的语言也存在这个问题.     这里讲一 ...

  6. js的基本概念详解

    来自<javascript高级程序设计 第三版:作者Nicholas C. Zakas>的学习笔记(三) 如果你刚学js,想快速了解到js的基本概念,以下将会是一篇不错的引导文章: 语法 ...

  7. Node.js理解

    JavaScript单线程的误解 在我接触JavaScript(无论浏览器还是NodeJS)的时间里,总是遇到有朋友有多线程的需求.而在NodeJS方面,有朋友甚至直接说到,NodeJS是单线程的,无 ...

  8. js 计算浮点数

    JS的浮点计算 最近遇到了数值计算的时候,计算结果出现了类似于199.9999999999999999999的情况,但是被用来计算的两个数值都只是两位数. 就像这样      --------> ...

  9. js高级程序设计

    defer 异步脚本,脚本延迟到文档完全被解析和显示之后再执行.只对外部脚本文件有效.按顺序执行脚本.但在实际情况下,并不一定会按照顺序执行最好只有一个延迟脚本.支持H5的浏览器会忽略给脚本设置 de ...

随机推荐

  1. cmake 安装 mysql5.5 版本

    1.安装确保以下系统相关库文件 gcc gcc-c++ autoconf automake zlib* libxml* ncurses-devel libmcrypt* libtool*(libtoo ...

  2. 【基础练习】【BFS+A*】codevs1225八数码难题题解

    题目描写叙述 Description Yours和zero在研究A*启示式算法.拿到一道经典的A*问题,可是他们不会做,请你帮他们. 问题描写叙述 在3×3的棋盘上,摆有八个棋子,每一个棋子上标有1至 ...

  3. 传递任意数量的实参*parameter&使用任意数量的关键字实参**parameter

    1.*形参名(*parameter) 有时候我们不知道知道函数需要接受多少个实参,所以我们可以在形参名前加一个*,是让python创建一个名为parameter的空元组,并将收到的所有值都封装到这个元 ...

  4. docker实用命名

    删除tag/镜像: #删除tag docker rmi index-dev.qiniu.io/cs-kirk/nginx:latest docker rmi index-dev.qiniu.io/cs ...

  5. AWS系列-使用Could Events定时对EC2打快照

    第1章 使用Could Events定时对EC2打快照 1.1 打开控制台搜索CloudWatch 在搜索栏输入CloudWatch,点击进入CloudWatch控制台 1.2 选择进入Events ...

  6. 解决ScrollView滑动RecyclerView的卡顿

    我们不的不了解ViewConfiguration这个类,官方是这么解释的Contains methods to standard constants used in the UI for timeou ...

  7. Gson 解析JSON数据

    {"province":[{"name":"安徽省","city":[{"name":"安 ...

  8. keepalive和脑裂问题

    keepalive keepalive起初专门为lvs负载均衡软件设计的,用来管理监控lvs集群系统中各个服务节点的状态,后来又加入了可以实现高可用的vrrp功能. keepalive软件通过vrrp ...

  9. poj2396 Budget&&ZOJ1994 Budget[有源汇上下界可行流]

    Budget Time Limit: 5 Seconds      Memory Limit: 32768 KB      Special Judge We are supposed to make ...

  10. Spring + MyBatis中常用的数据库连接池配置总结

    Spring在第三方依赖包中包含了两个数据源的实现类包,其一是Apache的DBCP,其二是 C3P0.可以在Spring配置文件中利用这两者中任何一个配置数据源. DBCP数据源 DBCP类包位于  ...