理解“无意义的”JavaScript特性

概要

JavaScript可能是世界上最流行的客户端语言,但它远非完美,也不是没有怪癖。Juan Diego Rodriguez研究了几个“荒谬的”JavaScript怪癖,并解释了它们是如何进入语言的,以及如何在自己的代码中避免它们。

特性 

为什么JavaScript有这么多怪癖!? 

例如:

  • 为什么0.2 + 0.1等于0.30000000000000004?
  • 为什么"" == false "的值为真?

JavaScript中有很多令人难以置信的决定,看起来毫无意义;有些是误解,而另一些则是设计上的直接失误。无论如何,了解这些奇怪的东西是什么以及它们为什么出现在语言中是值得的。我将分享我所认为的关于JavaScript的一些最奇怪的事情,并解释它们的意义。 

0.1 + 0.2和浮点格式

我们中的许多人都嘲笑JavaScript,在主机上编写0.1 + 0.2,却发现它无法得到0.3,而是一个有趣的0.30000000000000004值。

 0.1 + 0.2 = 0.30000000000000004

许多开发人员可能不知道的是,这种奇怪的结果并不是JavaScript的错!JavaScript只是遵循IEEE浮点算术标准,几乎所有其他计算机和编程语言都使用该标准来表示数字。 

浮点算术到底是什么呢?

计算机必须表示各种大小的数字,从行星之间的距离到原子之间的距离。在纸上,很容易写下一个大的数字或一个小的数量,而不用担心它会占用多少空间。计算机没有这种奢侈,因为它们必须将各种数字保存为二进制和内存中的一小块空间。

以8位整数为例。在二进制中,它可以保存0到255之间的整数。 

这里的关键字是整数。它不能表示它们之间的任何小数。为了解决这个问题,我们可以在8位的某个地方添加一个虚数小数点,这样小数点前的位就用来表示整数部分,其余的用来表示小数部分。因为这个点总是在同一个虚位上,所以它被称为定点小数。但是它带来了很大的代价,因为范围从0到255正好减少到0到15.9375。 

更高的精度意味着牺牲射程,反之亦然。我们还必须考虑到计算机需要满足大量不同需求的用户。如果测量值有一点点偏差,比如百分之一厘米,建桥的工程师不会太担心。但是,另一方面,同样的百分之一厘米最终可能会花费更多的钱来制造一个微芯片。所需的精度是不同的,错误的后果也会有所不同。 

另一个需要考虑的问题是数字存储在内存中的大小,因为将长数字存储在兆字节这样的大小是不可行的。

浮点格式的产生是由于需要精确而高效地表示大小数量。它分为三个部分:

  1. 表示数字是正还是负的单个位(0表示正,1表示负)。
  2. 包含数字的数字的有效尾数。
  3. 指数指定相对于尾数开头的十进制(或二进制)点的位置,类似于科学记数法的工作原理。因此,点可以移动到任何位置,因此是浮点数。

8位浮点格式可以表示0.0078到480(及其负数)之间的数字,但请注意,浮点表示不能表示该范围内的所有数字。这是不可能的,因为8位只能表示256个不同的值。不可避免地,许多数字不能准确地表示。山脉上有一些缺口。当然,计算机使用更多的位来提高精度和范围,通常使用32位和64位,但不可能准确地表示所有的数字,如果考虑到我们获得的范围和我们节省的内存,这是一个很小的代价。

确切的动态要复杂得多,但现在,我们只需要理解,虽然这种格式允许我们在很大范围内表达数字,但当它们变得太大时,它会失去精度(可表示值之间的差距变得更大)。例如,JavaScript数字以双精度浮点格式表示,即每个数字在内存中以64位表示,剩下53位表示尾数。这意味着JavaScript只能安全地表示-(253 - 1)和253 - 1之间的整数,而不会失去精度。超过这个数,算术就没有意义了。这就是为什么我们有这个数字。MAX_SAFE_INTEGER静态数据属性,表示JavaScript中的最大安全整数,即(253 - 1)或9007199254740991。 

但是0.3明显低于MAX_SAFE_INTEGER阈值,那么为什么我们不能在添加0.1和0.2时得到它呢?浮点格式难以处理一些小数。这不是浮点格式的问题,但肯定是任何数字系统的问题。

为了理解这个,我们把1 / 3表示成以10为底。 

0.3

0.33

0.3333333 [...]

不管我们试着写多少个数字,结果永远不会正好是三分之一。同样地,我们也不能精确地用2进制或二进制表示一些小数。以0.2为例。我们可以把它写成以10为基底的形式,但如果我们把它写成二进制的话,最后会得到一个循环的1001,它是无限重复的。 

0.001 1001 1001 1001 1001 1001 10 [...]

显然,我们不能有一个无限大的数字,所以在某些时候,尾数必须被截断,使得在这个过程中不失去精度是不可能的。如果我们尝试将0.2从双精度浮点数转换回10进制,我们将看到内存中保存的实际值: 

0.200000000000000011102230246251565404236316680908203125

 不是0.2!我们不能表示大量的小数值——不仅在JavaScript中,而且在几乎所有的计算机中。那么为什么运行0.2 + 0.2可以正确地计算出0.4呢?在这种情况下,不精度非常小,Javascript会将其舍入(在第16位小数处),但有时不精度足以逃避舍入机制,就像0.2 + 0.1的情况一样。如果我们尝试将0.1和0.2的实际值相加,就可以看到下面发生了什么。

这是写入0.1时保存的实际值:

0.1000000000000000055511151231257827021181583404541015625 

如果我们手动将0.1和0.2的实际值加起来,我们将看到罪魁祸首: 

0.3000000000000000444089209850062616169452667236328125 

该值四舍五入为0.30000000000000004。您可以检查保存在float.exposed中的实际值。 

总结 

浮点数有其众所周知的缺陷,但它的优点大于缺点,它是世界各地的标准。从这个意义上说,当所有现代系统在不同架构中都给我们相同的0.30000000000000004结果时,这实际上是一种解脱。这可能不是你期望的结果,但这是一个你可以预测的结果。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【并发编程】手写线程池阻塞队列

📝个人主页:五敷有你 🔥系列专栏:并发编程 ⛺️稳重求进,晒太阳 示意图 步骤1:自定义任务队列 变量定义 用Deque双端队列来承接任务用ReentrantLock 来做锁并声明两个条件变量 Condition fullWai…

PDF文件格式(一):交叉引用流

在PDF-1.5版本之前,对象的交叉引用信息是存储在交叉引用表(cross-reference table)中的。在PDF-1.5版本之后,引进了交叉引用流(cross-reference stream)对象,可以用它来存储对象的交叉引用信息,就像交叉引用表的功能一样。 采用交…

鸿蒙开发系列教程(十一)--布局应用:层叠布局

层叠布局 (Stack) 层叠布局(StackLayout)用于在屏幕上预留一块区域来显示组件中的元素,提供元素可以重叠的布局。层叠布局通过stack容器组件实现位置的固定定位与层叠,容器中的子元素(子组件&…

Python进阶----在线翻译器(Python3的百度翻译爬虫)

目录 一、此处需要安装第三方库requests: 二、抓包分析及编写Python代码 1、打开百度翻译的官网进行抓包分析。 2、编写请求模块 3、输出我们想要的消息 三、所有代码如下: 一、此处需要安装第三方库requests: 在Pycharm平台终端或者命令提示符窗口中输入以下代…

JVM-JVM内存结构(二)

堆 堆(Heap) 通过new关键字&#xff0c;创建的对象都会使用堆内存特点&#xff1a; 他是线程共享的&#xff0c;堆中的对象需要考虑线程安全的问题有垃圾回收机制 堆内存溢出(OutOfMemoryError) 代码演示 List<String> list new ArrayList<>(); try{String …

【已解决】pt文件转onnx后再转rknn时得到推理图片出现大量锚框变花屏

前言 环境介绍&#xff1a; 1.编译环境 Ubuntu 18.04.5 LTS 2.RKNN版本 py3.8-rknn2-1.4.0 3.单板 迅为itop-3568开发板 一、现象 采用yolov5训练并将pt转换为onnx&#xff0c;再将onnx采用py3.8-rknn2-1.4.0推理转换为rknn&#xff0c;rknn模型能正常转换&#xff0c;…

阿里地址标准化相关能力

阿里云地址标准化服务入口 1地址标准化概念 阿地址标准化&#xff08;Address Purification&#xff09;是一站式闭环地址数据处理和服务平台产品&#xff0c;依托阿里云海量的地址语料库&#xff0c;针对各行业业务系统所登记的地址数据&#xff0c;进行纠错、补全、归一、结…

【QT】opcuaServer 的构建

【QT】opcuaServer 的构建 前言opcuaServer实现测试 前言 在博文【opcua】从编译文件到客户端的收发、断连、节点查询等实现 中&#xff0c;我们已经介绍了如何在QT 中创建opucaClient 。在本期的博文中&#xff0c;我们基于之前的部署环境&#xff0c;介绍一下如何构建opcuaS…

Windows 离线安装MySQL8教程

本文描述了在Windows 11 上离线安装MySQL8的方法本方法同样使用与Win10、Windows Server等本文仅供参考&#xff0c;请理解后安装和优化 一、下载文件 官方下载路径 https://cdn.mysql.com//Downloads/MySQL-8.0/mysql-8.0.36-winx64.zip百度网盘缓存 微信小程序搜索“数字…

arcgis各种版本下载

arcgic 下载&#xff01;&#xff01;&#xff01; ArcGIS是一款地理信息系统软件&#xff0c;由美国Esri公司开发。它提供了一系列完整的GIS功能&#xff0c;包括地图制作、空间数据管理、空间分析、空间信息整合、发布与共享等。ArcGIS是一个可扩展的GIS平台&#xff0c;提供…

复杂人像背景分割解决方案

随着人工智能和图像处理技术的不断发展&#xff0c;人像处理已成为企业宣传、产品展示、线上教育等领域不可或缺的一环。然而&#xff0c;面对复杂多变的人像背景&#xff0c;如何实现精准、高效的分割&#xff0c;一直是困扰企业的技术难题。为此&#xff0c;美摄科技凭借其领…

【Java程序设计】【C00240】基于Springboot的班级综合测评管理系统(有论文)

基于Springboot的班级综合测评管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的班级综合测评管理系统 本系统分为学生功能模块、管理员功能模块以及教师功能模块。 管理员功能模块&#xff1a;管理员功能…

LeetCode、17. 电话号码的字母组合【中等,dfs回溯】

文章目录 前言LeetCode、17. 电话号码的字母组合【中等&#xff0c;dfs回溯】题目与类型思路递归回溯优化&#xff1a;StringBuilder来回溯补充代码&#xff1a;2024.1.31&#xff08;简化&#xff09; 资料获取 前言 博主介绍&#xff1a;✌目前全网粉丝2W&#xff0c;csdn博…

艺术创作和生活的关系

艺术出现在生产劳作中并体现出人们生活、工作、学习中&#xff0c;使人们在不受限制随意发挥缔造发明能力的体现&#xff0c;独立的精神活动领域在它逐渐演变进步的历程中越来越明显&#xff0c;也是一个人精神思想生活中很重要的一部分。艺术随着社会发展而发展。一件完美的艺…

银行数据仓库体系实践(17)--数据应用之营销分析

营销是每个银行业务部门重要的工作任务&#xff0c;银行产品市场竞争激烈&#xff0c;没有好的营销体系是不可能有立足之地&#xff0c;特别是随着互联网金融发展,金融脱媒”已越来越普遍&#xff0c;数字化营销方兴未艾&#xff0c;银行的营销体系近些年也不断发展&#xff0c…

Pyhton专项进阶——http协议、cookie、session和认证-3

关于cookie的报文首部相关属性熟悉后&#xff0c;下面就是实际应用。 使用cookie实现用户登录验证&#xff08;初步&#xff09;&#xff1a; 思路&#xff08;一&#xff09;&#xff1a;显示登录页面&#xff0c;输入用户和密码&#xff0c;后端验证&#xff0c;如果验证通…

Docker下安装GitLab

极狐GitLab Docker 镜像 | 极狐GitLab 安装所需最小配置 内存至少4G 系统内核至少3.10以上 uname -r 命令可以查看系统内核版本 安装Docker 1.更新 yum源 yum update 2.安装依赖(如果在操作第三步的时候提示yum-config-manager 未找到命令 就安装下面依赖) yum instal…

[UI5 常用控件] 07.SplitApp,SplitContainer

文章目录 前言1. SplitApp1.1 组件结构1.2 Demo1.3 mode属性 2. SplitContainer 前言 本章节记录常用控件SplitApp&#xff0c;SplitContainer。主要功能是在左侧显示Master页面&#xff0c;右侧显示Detail页面。 Master页面和Detail页面可以由多个Page组成&#xff0c;并支持…

【51单片机】LED的三个基本项目(LED点亮&LED闪烁&LED流水灯)(3)

前言 大家好吖&#xff0c;欢迎来到 YY 滴单片机系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过单片机的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的…

ShardingSphere实现openGauss分布式架构

本文档采用openGauss结合ShardingSphere中间件的架构&#xff0c;实现openGauss数据库分布式OLAP场景的环境部署。 术语说明&#xff1a; 开源数据库引擎&#xff1a;openGauss shardingsphere Proxy&#xff1a;定位为透明化的数据库代理端&#xff0c;提供封装了数据库二进…