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

news2025/1/12 10:57:29

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

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

  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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1240553.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QTableWidget——编辑单元格

文章目录 前言熟悉QTableWiget,通过实现单元格的合并、拆分、通过编辑界面实现表格内容及属性的配置、实现表格的粘贴复制功能熟悉QTableWiget的属性 一、[单元格的合并、拆分](https://blog.csdn.net/qq_15672897/article/details/134476530?spm1001.2014.3001.55…

ios qt开发要点

目前关于ios qt的开发资料比较少,这里整理了几个比较重要的开发要点,基于MacOS14 Xcode15 Qt15.5 cmake iphone真机。 cmake报错,报错信息如下 CMake Error at /Users/user/Qt/5.15.5/ios/lib/cmake/Qt5Core/Qt5CoreConfig.cmake:91 (m…

C++初阶 | [四] 类和对象(下)

摘要:初始化列表,explicit关键字,匿名对象,static成员,友元,内部类,编译器优化 类是对某一类实体(对象)来进行描述的,描述该对象具有哪些属性、哪些方法,描述完成后就形成…

shell脚本之循环语句(for、while、untli)

循环语句: 一定要有跳出循环条件 循环条件: 1.已知循环的次数(新来十个人,就要新建十个账号 2.未知循环的次数,但是要有跳出循环条件(对象生气,要道歉到原谅为止) for&#xff…

SpringBoot_websocket实战

SpringBoot_websocket实战 前言1.websocket入门1.1 websocket最小化配置1.1.1 后端配置1.1.2 前端配置 1.2 websocket使用sockjs1.2.1 后端配置1.2.2 前端配置 1.3 websocket使用stomp协议1.3.1 后端配置1.3.2 前端配置 2.websocket进阶2.1 websocket与stomp有什么区别2.2 webs…

【ThingJS】类型转换以及注册

前言 目前国家提倡加快数字化发展,建设数字中国,并于今年2月份中共中央、国务院印发的《数字中国建设整体布局规划》中明确,数字中国建设按照“2522”的整体框架进行布局。其中提到“构建以数字孪生流域为核心的智慧水利体系”,可…

HarmonyOS(三)—— 应用程序入口—UIAbility

前言 学习过android的同学都是知道Activity,Activity是Android组件中最基本也是最为常见用的四大组件之一,用户可以用来交互为了完成某项任务。 Activity中所有操作都与用户密切相关,是一个负责与用户交互的组件,可以通过setCon…

Mac自带的看图如何连续查看多张图片

一、问题 mac看访达里的图片时,双击打开一张图片,然后按上下左右键都没法切换到另外的图片。而且也没找到像window一样单击缩略图可以看到预览图。其实是自己不懂得怎么使用,哈哈哈😂 二、方法 2.1、图标方式 可以看到缩略图&a…

原理Redis-QuickList

QuickList **问题1:**ZipList虽然节省内存,但申请内存必须是连续空间,如果内存占用较多,申请内存效率很低。怎么办? 为了缓解这个问题,我们必须限制ZipList的长度和entry大小。 **问题2:**但是…

【NLP】GPT 模型如何工作

介绍 2021 年,我使用 GPT 模型编写了最初的几行代码,那时我意识到文本生成已经达到了拐点。我要求 GPT-3 总结一份很长的文档,并尝试了几次提示。我可以看到结果比以前的模型先进得多,这让我对这项技术感到兴奋,并渴望…

[数据结构]-AVL树

前言 作者:小蜗牛向前冲 名言:我可以接受失败,但我不能接受放弃 如果觉的博主的文章还不错的话,还请点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、AVL树基…

陪玩圈子系统APP小程序H5,详细介绍,源码交付,支持二开!

陪玩圈子系统,页面展示,源码交付,支持二开! 陪玩后端下载地址:电竞开黑陪玩系统小程序,APP,H5: 本系统是集齐开黑,陪玩,陪聊于一体的专业APP,小程序&#xff…

Github Copilot AI编码完成工具

目录 一、GitHub Copilot 1、简介 2、工作原理 3、功能 二、GitHub Copilot X 1、什么是 GitHub Copilot X 2、GitHub Copilot X 的功能 三、支持、使用 1、支持 2、使用 四、实际研究、验证(代码方向) 1、代码生成 2、代码提示 3、生成测试用例 4、代码解释 5…

排序算法--归并排序

实现逻辑 ① 将序列每相邻两个数字进行归并操作,形成floor(n/2)个序列,排序后每个序列包含两个元素 ② 将上述序列再次归并,形成floor(n/4)个序列,每个序列包含四个元素 ③ 重复步骤②,直到所有元素排序完毕 void pri…

Rust并发编程:理解线程与并发

大家好!我是lincyang。 今天我们来深入探讨Rust中的并发编程,特别是线程的使用和并发的基本概念。 Rust中的线程 Rust使用线程来实现并发。线程是操作系统可以同时运行的最小指令集。在Rust中,创建线程非常简单,但与此同时&…

SHAP - 机器学习模型可解释性工具

github地址:shap/docs/index.rst at master shap/shap (github.com) SHAP使用文档:欢迎使用 SHAP 文档 — SHAP 最新文档 SHAP介绍 SHAP(SHapley Additive exPlanations)是一种用于解释预测结果的方法,它基于Shapley…

ADB命令介绍

📢专注于分享软件测试干货内容,欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!📢交流讨论:欢迎加入我们一起学习!📢资源分享:耗时200小时精选的「软件测试」资…

系列七、ThreadLocal为什么会导致内存泄漏

一、ThreadLocal为什么会导致内存泄露 1.1、ThreadLocalMap的基本结构 ThreadLocalMap是ThreadLocal的内部类,没有实现Map接口,用独立的方式实现了Map的功能,其内部的Entry也是独立实现的。源码如下: 1.2、ThreadLocal引用示意图…

逸学java【初级菜鸟篇】9.3 Stream流

hi,我是逸尘,一起学java吧 得益于Lambda所带来的函数式编程,引入了一个全新的Stream流概念(就是都基本使用lambda的形式)。 流处理 我们首先理解什么是流处理,它类似于sql语句,可以执行非常复…

cocos2dx ​​Animate3D(二)

Twirl 扭曲旋转特效 // 持续时间(时间过后不会回到原来的样子) // 整个屏幕被分成几行几列 // 扭曲中心位置 // 扭曲的数量 // 振幅 static Twirl* create(float duration, const Size& gridSize, const Vec2& position, unsigned int twirls, float amplitude)…