为什么0.1+0.2 !=0.3,怎么解决

简介: JS中数字运算时,有一个叫做 数字运算中的精度缺失的问题,这篇文章,就带着大家了解下JS运算中精度的缺失问题。首先我们先来看一个例子:这里0.1 + 0.2 != 0.3 这个就是我们要解决的问题了。

JS中数字运算时,有一个叫做 数字运算中的精度缺失的问题,这篇文章,就带着大家了解下JS运算中精度的缺失问题。

首先我们先来看一个例子:

img_d2bb1683d09bda99f19abc63898dc741.png

这里0.1 + 0.2 != 0.3 这个就是我们要解决的问题了。

要弄清这个问题的原因,首先我们需要了解下在计算机中数字是如何存储和运算的。在计算机中,数字无论是定点数还是浮点数都是以多位二进制的方式进行存储的。

在JS中数字采用的IEEE 754的双精度标准进行存储,我们可以无需知道他的存储形式,只需要简单的理解成就是存储一个数值所使用的二进制位数比较多而已,这样得到的数会更加精确。

这里为了简单直观,我们使用定点数来说明问题。在定点数中,如果我们以8位二进制来存储数字。

对于整数来说,十进制的35会被存储为: 00100011 其代表 2^5 + 2^1 + 2^0。

对于纯小数来说,十进制的0.375会被存储为: 0.011 其代表 1/2^2 + 1/2^3 = 1/4 + 1/8 = 0.375

而对于像0.1这样的数值用二进制表示你就会发现无法整除,最后算下来会是 0.000110011....由于存储空间有限,最后计算机会舍弃后面的数值,所以我们最后就只能得到一个近似值。

在JS中采用的IEEE 754的双精度标准也是一样的道理,我们且不管这个标准下的存储方式跟定点数存储有何不同,单单在这一点上他们都是相同的,也就是存储空间有限,当出现这种无法整除的小数的时候就会取一个近似值,在js中如果这个近似值足够近似,那么js就会认为他就是那个值。

比较拗口,举个例子:

img_5b37484a7eb140000d129000ef2ed1fb.png

所以我们现在应该可以理解,就是说由于0.1转换成二进制时是shenzhen.offcn.com无限循环的,所以在计算机中0.1只能存储成一个近似值。另外说一句,除了那些能表示成 x/2^n 的数可以被精确表示以外,其余小数都是以近似值得方式存在的。

在0.1 + 0.2这个式子中,0.1和0.2都是近似表示的,在他们相加的时候,两个近似值进行了计算,导致最后得到的值是0.30000000000000004,此时对于JS来说,其不够近似于0.3,于是就出现了0.1 + 0.2 != 0.3 这个现象。 当然,也并非所有的近似值相加都得不到正确的结果。

有时两个近似值进行计算的时候,得到的值是在JS的近似范围内的,于是就可以得到正确答案。至于哪些值计算后能得到正确结果,哪些不能,我们也不需要去记。

最好的方法就是我们想办法规避掉这类小数计算时的精度问题就好了,那么最常用的方法就是将浮点数转化成整数计算。因为整数都是可以精确表示的。

方法也很简单,举个例子:

img_2a400c7c9b37e05558f77fa98128bc83.png
相关文章
|
7月前
|
微服务
什么是服务雪崩,怎么解决这个问题?
什么是服务雪崩,怎么解决这个问题?
82 0
|
监控 Dubbo Cloud Native
如何解决服务雪崩?
一.什么是服务雪崩 (1)分布式系统环境下,通常会有很多层的服务调用。由于网络原因或自身的原因,服务一般无法保证100%可用。如果一个服务出现了问题,调用这个服务就会出现线程阻塞的情况,此时若有大量的请求涌入,就会出现多条线程阻塞等待,进而导致服务瘫痪。 (2)如下图,对于同步调用,当底层的库存服务不可用时,商品服务请求线程被阻塞,当有大批请求调用库存服务时,最终可能导致整个商品服务资源耗尽,无法继续对外提供服务。 (3)由于服务与服务之间的依赖性,故障会传播,不可用沿请求调用链向上传递,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩效应”。
如何解决服务雪崩?
|
Web App开发 Java 索引
遇到问题如何解决
转载请注明出处。
1468 0
|
消息中间件 缓存 NoSQL
面试官:缓存一致性问题怎么解决?
关于Redis的其他的一些面试问题已经写过了,比如常见的缓存穿透、雪崩、击穿、热点的问题,但是还有一个比较麻烦的问题就是如何保证缓存一致性。
面试官:缓存一致性问题怎么解决?
|
消息中间件 缓存 安全
缓存一致性问题,这么回答肯定没毛病!
方案分析更新缓存策略方式常见的有下面几种:先更新缓存,再更新数据库先更新数据库,再更新缓存先删除缓存,再更新数据库先更新数据库,再删除缓存下面一一介绍!方案一:更新缓存,更新数据库这种方式可轻易排除,因为如果先更新缓存成功,但是数据库更新失败,则肯定会造成数据不一致。方案二:更新数据库,更新缓存这种缓存更新策略俗称双写,存在问题是:并发更新数据库场景下,会将脏数据刷到缓存updateDB();updateRedis();复制代码举例:如果在两个操作之间数据库和缓存又被后面请求修改,此时再去更新缓存已经是过期数据了。方案三:删除缓存,更新数据库存在问题:更新数据库之前,若有查询请求,会将举例
|
API 调度 C语言
视频图像处理中的错帧同步是怎么实现的?
错帧同步,简单来说就是把当前的几帧缓冲到子线程中处理,主线程直接返回子线程之前的处理结果,属于典型的以空间换时间策略。
309 0
视频图像处理中的错帧同步是怎么实现的?
|
Java Maven
Slf4j 包老冲突,每次排查半天,是什么原因?怎么解决?
一、前言 在进行 Java 开发时,通常我们会选择 Slf4j 作为日志门面,但日志实现却不尽相同。如果系统运行中同时存在多个日志实现,就会出现类似下图的 Warning。
Slf4j 包老冲突,每次排查半天,是什么原因?怎么解决?
|
8月前
|
SQL 缓存 NoSQL
踩坑:以为是Redis缓存没想到却是Spring事务!
最近碰到了一个Bug,折腾了我好几天。并且这个Bug不是必现的,出现的概率比较低。一开始我以为是旧数据的问题,就让测试重新生成了一下数据,重新测试。由于后面几轮测试均未出现,我也就没太在意。
踩坑:以为是Redis缓存没想到却是Spring事务!