或许很多人都遇到过,js 对小数的加、减、乘、除时经常得到一些奇怪的结果!

比如 :0.1 + 0.2 = 0.3  ?

这么一个简单的计算,当你用js 计算时会发现结果是: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。

找到原因了,那应该怎么处理呢?

方法一:指定要保留的小数位数(0.1+0.2).toFixed(1) = 0.3;这个方法toFixed是进行四舍五入的也不是很精准,对于计算金额这种严谨的问题,不推荐使用,而且不通浏览器对toFixed的计算结果也存在差异。

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

eg: (0.1*10 + 0.2*10) / 10 == 0.3

对于方法二可以对四则运算分别作封装:

/* ===== 浮点型数据的加、减、乘、除 ===== */
add(arg1, arg2) { // 加法
let 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 (arg1 * m + arg2 * m) / m
},
sub(arg1, arg2) { // 减法
let r1, r2, m, n
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))
n = (r1 >= r2) ? r1 : r2
return ((arg1 * m - arg2 * m) / m).toFixed(n)
},
mul(arg1, arg2) { // 乘法
let m = 0
let s1 = arg1.toString()
let 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)
},
div(arg1, arg2) { // 除法
let t1 = 0
let t2 = 0
let r1
let r2
try {
t1 = arg1.toString().split('.')[1].length
} catch (e) {
}
try {
t2 = arg2.toString().split('.')[1].length
} catch (e) {
}
r1 = Number(arg1.toString().replace('.', ''))
r2 = Number(arg2.toString().replace('.', ''))
return (r1 / r2) * Math.pow(10, t2 - t1)
},
/* ===== 浮点型数据的加、减、乘、除 ===== */

js 浮点数计算精度不准确问题的更多相关文章

  1. 关于js浮点数计算精度不准确问题的解决办法

    今天在计算商品价格的时候再次遇到js浮点数计算出现误差的问题,以前就一直碰到这个问题,都是简单的使用tofixed方法进行处理一下,这对于一个程序员来说是及其不严谨的.因此在网上收集了一些处理浮点数精 ...

  2. 学以致用:手把手教你撸一个工具库并打包发布,顺便解决JS浮点数计算精度问题

    本文讲解的是怎么实现一个工具库并打包发布到npm给大家使用.本文实现的工具是一个分数计算器,大家考虑如下情况: \[ \sqrt{(((\frac{1}{3}+3.5)*\frac{2}{9}-\fr ...

  3. js浮点数加减乘除精度不准确

    做个记录,以备不时之需 //加法 Number.prototype.add = function(arg){ var r1,r2,m; try{r1=this.toString().split(&qu ...

  4. 如何避开JavaScript浮点数计算精度问题(如0.1+0.2!==0.3)

    不知道大家在使用JS的过程中有没有发现某些浮点数运算的时候,得到的结果存在精度问题:比如0.1 + 0.2 = 0.30000000000000004以及7 * 0.8 = 5.60000000000 ...

  5. js浮点数计算问题 + 金额大写转换

    一 js浮点数计算问题解决方案: 1.使用 NumberObject.toFixed(num) 方法 toFixed() 方法可把 Number 四舍五入为指定小数位数的数字. 2.较精度计算浮点数 ...

  6. java用double和float进行小数计算精度不准确

    java用double和float进行小数计算精度不准确 大多数情况下,使用double和float计算的结果是准确的,但是在一些精度要求很高的系统中或者已知的小数计算得到的结果会不准确,这种问题是非 ...

  7. jmeter 中 浮点数计算精度问题

    jmeter 中 浮点数计算精度问题解决方法: 编写 beanshell 时使用 java.math.BigDecimal 方法构造,使用 BigDecimal 并且一定要用 String 来够造. ...

  8. JS数字计算精度误差的解决方法

    本篇文章主要是对javascript避免数字计算精度误差的方法进行了介绍,需要的朋友可以过来参考下,希望对大家有所帮助. 如果我问你 0.1 + 0.2 等于几?你可能会送我一个白眼,0.1 + 0. ...

  9. 黄聪:JS数学计算精度修正

    问题描述 如果我问你,4330.61乘以100等于多少,我猜你肯定跟我说:“肯定是 433061”啊! 是啊,要我我也是这么回答,来来来我们来看看浏览器怎么说吧,如下图   浏览器告诉我,他就是算不对 ...

随机推荐

  1. Comet OJ - Contest #13-C2

    Comet OJ - Contest #13-C2 C2-佛御石之钵 -不碎的意志-」(困难版) 又是一道并查集.最近做过的并查集的题貌似蛮多的. 思路 首先考虑,每次处理矩形只考虑从0变成1的点.这 ...

  2. Elasticsearch由浅入深(十一)索引管理

    索引的基本操作 创建索引 PUT /{index} { "settings": {}, "mappings": { "properties" ...

  3. 初探Java设计模式5:一文了解Spring涉及到的9种设计模式

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  4. 在 Queue 中 poll()和 remove()有什么区别?

    remove() ,如果队列为空的时候,则会抛出异常 而poll()只会返回null    

  5. markdown文本内跳转

    Markdown文本内跳转 构建茅的过程中使用markdown语法,类似于markdown向外跳转链接,目的地地址写成#. 在markdown文本中写入: 目录 跳转 跳转部分按照html文本的写法 ...

  6. python笔记 面向对象编程从入门到高级

    目录: 一.概念 二.方法    2.1组合 2.2继承 2.3多态 2.4封装 2.5归一化设计 三.面向对象高级   3.1   反射(自省) 3.2   内置方法__getatter__, __ ...

  7. laravel框架模型model的创建与使用方法

    这篇文章给大家介绍的内容是关于laravel框架模型model的创建与使用方法,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 1.创建model 2. 1 2 3 4 5 6 7 8 ...

  8. UWP 使用Launcher 启动迅雷

    不得不说UWP有些地方真的不方便! 另外也要夸一下迅雷,还是蛮不错的! 代码 await Launcher.LaunchUriAsync(new Uri("magnet:?xt") ...

  9. Jmeter参数化之数据库读取数据

    以读取mysql数据库为例 1.下载一个mysql驱动包,最好去mysql官网下载 下载网址:https://dev.mysql.com/downloads/connector/j/ Select O ...

  10. 使用python远程连接数据库

    根据web连接服务的原理,我们可以通过一台电脑连接我们另一台电脑上的数据库 一.开启数据库的权限1.Mysql:1)修改访问权限首先修改可以访问的ip,把‘localhost’全部修改为‘%’,打开c ...