【累积计划】JavaScript:0.1 + 0.2 != 0.3 我不背这个锅! !
前言
大家好,我是 家乡
.
这篇文章是 【前端不秃】☀️ 累积计划·一期 中间 2022-09-13
知识点指向北方。
以下指南仅代表个人意见。如果有任何错误,请纠正我并停止Q。
插曲
这个问题在面试中经常被问到 “0.1 + 0.2 等于 0.3 吗?”
,一个看似不起眼的问题,其实可以准确的获取被访者的电脑技能。以下是之前获得的答案列表:
(1) 等于 - -> 弱
(2) “0.1 + 0.2”不等于 JavaScript 中的“0.3”——->较弱
(3) 不等于——->在
(4) 不相等,因为巴拉巴拉……--> 中高
其实以上问题不只是JavaScript编程语言会遇到,几乎所有现代编程语言都会遇到以上问题,包括 爪哇
, 红宝石
, Python
, 去
, C
, C#
还有很多。
# Python
打印(.1 + .2)#0.30000000000000004
复制代码 // 去
fmt.Println( .1 + .2) // 0.3
var a float64 = .1
var b float64 = .2
fmt.Println(a + b) // 0.30000000000000004
fmt.Printf("%.54f\n", .1 + .2) // 0.29999999999999988897769753748434595763683319091796875
复制代码
所以不要说只有 JavaScript 才能计算出问题。
无与伦比的精度
计算机编程中的浮点数和我们平时看到的小数是有一定区别的。这也是新手最容易进入的误区。在数学层面,我们可以用一些特定的符号来表示一些特别复杂的数字,比如 圆周率 ,但从计算机编程的角度来看,无限精度和长度的数字是不可行的,因为计算机计算希望通过更短更快的系统来表达更大更高精度的数字。 实数 .
二进制浮点运算的 IEEE 754 标准 它是目前最广泛的浮点数运算标准。它指定了四种表示浮点数的方法,以及算术格式、交换格式、摄取规则、操作和异常处理。
计算机编程中一般有两种 32 位浮点数。 漂浮
单精度浮点数和 64 位 双倍的
双精度浮点数,因此不可能用有限位数表示无限个小数。
举一个比较简单的例子:
在我们的十进制世界里,其实是有这样的数字的,比如:
a = 10 / 3 = 3.33333333333333333...
b = 10 / 6 = 1.6666666666666...
现在你有32个网格,每个网格只能放一个,也就是说你只能保存两个值3.3x32 & 1.6x32,这会问你10 / 3 + 10 / 6 = a + b?当然不是,对吧,为什么呢?因为你的 a 和 b 是近似的。至于如何省略32位后的值,每个人都有自己的想法,需要一个机构或组织来确定,所以有 IEEE 754
.
32个点阵可分为:1个符号位、8位指数、23位尾
根据
电脑底层是使用 二进制 0 和 1
表示整数和小数,我们平时使用的数字基本都是 十进制
是的,所有十进制整数(不包括无理数&无限数)都可以完全无损失地转换成有限二进制数,但是对于十进制小数,计算机处理起来比较麻烦,比如十进制0.1转换成二进制的时候小数,会有一系列无限循环的二进制数,所以因为 长度有限
, 电脑只能使用 近似
来表示十进制0.1的二进制数,和我上面说的例子一样。
这种小数的二进制转换不同于整数。需要单独处理小数部分,有点麻烦。在这里你可以通过 二进制转换 分别转换 0.1
, 0.2
,结果如下:
从图中可以看出,0.1&0.2的符号位、指数和尾数为:
- 0.1
- 二进制浮点数转换为十进制后为:
0.100000001490116119384765625
- 符号位:0
- 8位指数:01111011
- 23位尾数:10011001100110011001101
- 0.2
- 二进制浮点数转换为十进制后为:
0.20000000298023223876953125
- 符号位:0
- 8位指数:01111100
- 23位尾数:10011001100110011001101
两者的8位指数不同,但23位尾数相同,都是 0011
一直循环的一个无限数,然后由于长度和精度限制只显示一部分 近似
结果。
将两者相加的结果是 0.300000004470348358154296875
,那么近似值加上近似值的结果也一定是近似值。当一个近似值与二进制数 0.3 进行比较时,当然会返回 false。这是单精度结果,双精度浮点存储在 3 到 4 之间会有更多的 0。
如果计算机中的浮点数可以表示无限循环的小数,则很有可能解决这个问题。
总结
0.1 + 0.2 !== 0.3,因为这两个二进制数是两个 0011 无限循环的近似值,就像我们的十进制 3.3333 是无限的一样,我们可以使用 无尽的
表示数字是多少,但计算机无法准确表达,这是浮点计算造成精度损失的根本原因。
由 IEEE 754 标准定义 近似
要表示这个二进制数的无限循环,就意味着计算机存储的十进制很可能是一个不准确的数字。
然后将两个近似值相加,得到的值一定是近似值。 0.3 的近似值不等于完整的 0.3。
如何在 JavaScript 中解决这个问题
结尾
下次见~我的朋友,我是
家乡
, ➕me VX, 你加入“前端不秃”群,这是一个大家一起成长、一起学习的社区!在这里你可以:讨论技术问题,了解前端信息,查询公司应聘情况,获得内部推荐机会,聊一些事情。vx:
家乡-468
【拉你一个人】公众号:
光头 光头
【关注回复“进群”】博客: 家乡的博客 【点击查看】
Gao Zanhaowen
- 分享11个好看的PC界面! !
- 敢在我的工作站上安装摄像头吗?吃我一套JS➕CSS组合拳! !
- 前端老司机70+实用网站分享(推荐收藏!)
- 【吉特】什么! ?快到 2023 年了,我仍然无法弄清楚 git rebase 和 git merge! ?
- 我用前端【最新】技术栈【Vue3 + TS + Vite + Pania + Windicss + NavieUI】完成了一个生产标准项目
过去的评论
- ♂️ 砸了30w+的矿石礼盒,闯关了……【掘金·幸运轮vue3版】
- 熟练使用NodeJs,帮助老板解决个人需求!老板娘喊道:“妞!牛! !”
- eslint + prettier + husky + lint-staged 受限项目的最佳实践!
- 【小程序】微信小程序优化指南3天总结(最爱吃灰!)
- 【VUE】从源码角度讲解MVVM!实现 v 模型!这真的很容易!
- 【CSS】5分钟全面了解W3C&IE盒子模型!
- [CSS] 有趣的 BFC:块格式化上下文!
- 【CSS】说说CSS像素、设备像素、设备无关像素、dpr、ppi的区别
- 【性能】7分钟给你看【有大】正在使用的Chrome Runtime Performance Debug!
- 【源码角度】7分钟带你看懂ESLint核心原理!
- 【JavaScript】教你写出高质量的JavaScript异步代码!
- …………… 看更多……………
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议。转载请附上原文出处链接和本声明。
这篇文章的链接: https://homecpp.art/4513/8163/1742
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明