老生常谈之 JavaScript 中 0.1 + 0.2 != 0.3 的原因

2023-11-23 14:12

本文主要是介绍老生常谈之 JavaScript 中 0.1 + 0.2 != 0.3 的原因,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

先来一个模棱两可的说法:因为精度丢失、存储溢出的问题

先复习一下二进制的转换方法:

  1. 整数:除以基数,取余,自底向上
  2. 小数:乘以基数,取整,自顶向下
    二进制转换

接着,复习一下双精度浮点数(double)

  1. Number 类型使用IEEE754 标准 64位 存储
  • 符号位:1位,0 表示正数,1 表示负数
  • 指数位:11位,固定值(1023)+ 指数实际值
    • (2 ^ (e-1)) - 1 => (2 ^ (11 - 1)) - 1 = 1023
    • 这一步看不懂,可先跳过,待会解释
  • 小数位:52位
  1. 双精度浮点数即为每个数值分配 64位存储空间,以科学计数法的方式存储

中间插播一个小内容:怎么理解指数位

1、IEEE 754 标准中的双精度浮点数采用了带有偏移量的指数表示
2、具体来说,双精度浮点数的指数部分是一个11位的二进制数,其中最小值是全0(00000000000),最大值是全1(11111111111)。这11位的二进制数会被解释为一个无符号整数,然后从中减去一个偏移值来得到最终的指数。
3、IEEE 754 双精度浮点数的指数偏移值是 2 ( k − 1 ) − 1 2^{(k-1)} - 1 2(k1)1,其中 k 是指数部分的位数。对于双精度浮点数,k 是11,所以偏移值是 2 ( 11 − 1 ) − 1 = 1023 2^{(11-1)} - 1 = 1023 2(111)1=1023
4、例如,如果指数部分的二进制表示是 01111111111,那么对应的无符号整数是 2 10 − 1 = 1023 2^{10} - 1 = 1023 2101=1023。然后,减去偏移值 1023,最终得到实际的指数值为0。
5、这个偏移量的使用允许浮点数表示非常大和非常小的数,因为指数的范围可以从负数到正数。同时,由于使用偏移值,指数部分的二进制表示中并不包含真实的指数值,而是需要通过减去偏移值来得到真实的指数。

了解上面两个知识点之后,开始进入正文
第一步:0.1 转换二进制为:0.00011001…1001(循环)
第二步:二进制转换为科学计数法 = 1.1001 * 2^ (-4)
第三步:计算指数位 1023 + (-4) = 1019 = 01111111011
第四步:计算小数位,为1001无限循环
因此,0.1 = 符号位0 + 指数位01111111011 + 小数位1001…

由于小数位只有52为,因此第53位为1,截取保存的时候进了1,所以发生了精度丢失。 即后四位小数为 1001 + 1 = 1010

针对于0.2也进行同样分析,相加的时候同样也出现了截取保存的情况,即出现第二次精度丢失,所以最终转换为10进制的时候为 0.30000000000000004

综上所述:
1、由于js采用二进制处理数据,用IEEE 754双精度浮点数标准来存储 Number 类型
2、精度丢失非JS问题,而是IEEE 754标准存储位有限
3、过程中出现了两次精度丢失问题,一次在存储,一次在相加

解决方案:
1、两个数分别乘以100,得到结果再除以100

这篇关于老生常谈之 JavaScript 中 0.1 + 0.2 != 0.3 的原因的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/418505

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

流媒体平台/视频监控/安防视频汇聚EasyCVR播放暂停后视频画面黑屏是什么原因?

视频智能分析/视频监控/安防监控综合管理系统EasyCVR视频汇聚融合平台,是TSINGSEE青犀视频垂直深耕音视频流媒体技术、AI智能技术领域的杰出成果。该平台以其强大的视频处理、汇聚与融合能力,在构建全栈视频监控系统中展现出了独特的优势。视频监控管理系统EasyCVR平台内置了强大的视频解码、转码、压缩等技术,能够处理多种视频流格式,并以多种格式(RTMP、RTSP、HTTP-FLV、WebS

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟 开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚 第一站:海量资源,应有尽有 走进“智听