为什么 0.1 + 0.2 在 JavaScript 中返回不可预测的浮点结果,而 0.2 + 0.3 则不会?

2023-12-25

0.1 + 0.2
// => 0.30000000000000004

0.2 + 0.2
// => 0.4

0.3 + 0.2
// => 0.5

我知道这与浮点有关,但这里到底发生了什么?

根据 @Eric Postpischil 的评论,这不是重复的:

那只涉及为什么“噪音”会出现在一项附加内容中。这个 询问为什么“噪音”出现在一项添加中而没有出现在 其他。另一个问题中没有回答这个问题。因此,这 不是重复的。其实造成差异的原因并不是因为 浮点运算本身,但归因于 ECMAScript 2017 7.1.12.1 步骤 5


When converting Number values to strings in JavaScript, the default is to use just enough digits to uniquely distinguish the Number value https://stackoverflow.com/a/49386744/298225.1 This means that when a number is displayed as “0.1”, that does not mean it is exactly 0.1, just that it is closer to 0.1 than any other Number value is, so displaying just “0.1” tells you it is this unique Number value, which is 0.1000000000000000055511151231257827021181583404541015625. We can write this in hexadecimal floating-point notation as 0x1.999999999999ap-4. (The p-4 means to multiply the preceding hexadecimal numeral, by two the power of −4, so mathematicians would write it as 1.99999999999916 • 2−4.)

这是您编写时产生的值0.1, 0.2, and 0.3在源代码中,它们被转换为 JavaScript 的数字格式:

  • 0.1 → 0x1.999999999999ap-4 = 0.1000000000000000055511151231257827021181583404541015625。
  • 0.2 → 0x1.999999999999ap-3 = 0.200000000000000011102230246251565404236316680908203125。
  • .3 → 0x1.3333333333333p-2 = 0.299999999999999988897769753748434595763683319091796875。

When we evaluate 0.1 + 0.2, we are adding 0x1.999999999999ap-4 and 0x1.999999999999ap-3. To do that manually, we can first adjust latter by multiplying its significand (fraction part) by 2 and subtracting one from its exponent, producing 0x3.3333333333334p-4. (You have to do this arithmetic in hexadecimal. A16 • 2 = 1416, so the last digit is 4, and the 1 is carried. Then 916 • 2 = 1216, and the carried 1 makes it 1316. That produces a 3 digit and a 1 carry.) Now we have 0x1.999999999999ap-4 and 0x3.3333333333334p-4, and we can add them. This produces 4.ccccccccccccep-4. That is the exact mathematical result, but it has too many bits for the Number format. We can only have 53 bits in the significand. There are 3 bits in the 4 (1002) and 4 bits in each of the trailing 13 digits, so that is 55 bits total. The computer has to remove 2 bits and round the result. The last digit, E16, is 11102, so the 10 bits have to go. These bits are exactly ½ of the previous bit, so it is a tie between rounding up or down. The rule for breaking ties says to round so the last bit is even, so we round up to make the 11 bits become 100. The E16 becomes 1016, causing a carry to the next digit. The result is 4.cccccccccccd0p-4, which equals 0.3000000000000000444089209850062616169452667236328125.

Now we can see why printing .1 + .2 shows “0.30000000000000004” instead of “0.3”. For the Number value 0.299999999999999988897769753748434595763683319091796875, JavaScript shows “0.3”, because that Number is closer to 0.3 than any other Number is. It differs from 0.3 by about 1.1 at the 17th digit after the decimal point, whereas the result of the addition we have differs from 0.3 by about 4.4 at the 17th digit. So:

  • 源代码0.3产生 0.299999999999999988897769753748434595763683319091796875 并打印为“0.3”。
  • 源代码0.1 + 0.2生成 0.3000000000000000444089209850062616169452667236328125 并打印为“0.30000000000000004”。

现在考虑0.2 + 0.2。结果是 0.40000000000000002220446049250313080847263336181640625。这是最接近 0.4 的数字,因此 JavaScript 将其打印为“0.4”。

最后,考虑0.3 + 0.2。我们添加 0x1.999999999999ap-3 和 0x1.3333333333333p-2。我们再次调整第二个操作数,生成 0x2.6666666666666p-3。然后相加得到 0x4.0000000000000p-3,即 0x1p-1,即 1/2 或 0.5。所以它被打印为“0.5”。

另一种看待它的方式:

  • 源代码的值0.1 and 0.2分别略高于 0.1 和 0.2,将它们相加会产生高于 0.3 的数字,并且错误会加剧,因此总错误足以将结果推离 0.3,足以使 JavaScript 显示错误。
  • 添加时0.2 + 0.2,没有引入新的错误。
  • 源代码的价值0.3略低于0.3。当添加到0.2,略高于 0.2,误差被消除,结果正好是 0.5。

Footnote

1 This rules comes from step 5 in clause 7.1.12.1 of the ECMAScript 2017 Language Specification.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 0.1 + 0.2 在 JavaScript 中返回不可预测的浮点结果,而 0.2 + 0.3 则不会? 的相关文章

  • 使用 jquery 远程图像属性

    目前我正在尝试获取远程图像宽度 高度 我正在开发一个链接共享模块 就像当你在 Facebook 上粘贴链接时 你可以看到标题 描述和图像 所以我尝试使用 php getimagesize 来获取图像宽度 高度 但速度非常慢 所以我正在考虑使
  • Javascript 函数查找数字的倍数

    创建一个名为的函数multiplesOf 它将接受两个参数 第一个参数是数字数组 第二个参数是数字 该函数应返回一个新数组 该数组由参数数组中的每个数字组成 该数字是参数数字的倍数 So multiplesOf 5 6 7 8 9 10 3
  • 如何更改 Google Maps v3 API for Directions 中的开始和结束标记图像

    我使用 DirectionsRender 绘制了一条路线 但我不知道如何用我自己的标记替换通用的 Google 标记 我知道并在正常的谷歌地图情况下使用它 但发现很难用开始和结束的方向标记来做到这一点 如果这是一个愚蠢的问题 感谢您的任何建
  • 在打字稿中导入 json

    我是 typescript 的新手 在我的项目中 我们使用 typescript2 在我的要求之一中 我需要导入 json 文件 所以我创建了 d ts 文件如下 test d ts declare module json const va
  • Draggable JS Bootstrap 模式 - 性能问题

    对于工作中的项目 我们在 JavaScript 中使用 Bootstrap Modal 窗口 我们想让一些窗口可移动 但我们遇到了 JQuery 的性能问题 myModal draggable handle modal header Exa
  • React-Redux:state.setIn() 和 state.set() 有什么区别?

    我见过使用setIn and set 在一些react redux代码中 state setIn state set 我在这里找到了一些文档https facebook github io immutable js https facebo
  • 尝试将数据存储在点击器网站中

    我正在尝试存储一个名为的变量score无论何时刷新 您都会一次又一次地使用它 我不明白的是它的代码是什么 我尝试了一些方法 但似乎都不起作用 这是我的答题器网站 但是当我尝试使用 JavaScript 来存储它时 它不起作用window o
  • 如何解决 Typescript 构建中的错误“找不到模块 'jquery'”

    我目前在 ts 文件的顶部有这个import require jquery 我这样做是因为我试图在我的打字稿文件中使用 jquery 但我似乎无法编译它 因为它返回标题中所述的错误 我正在使用 ASP NET CORE 脚本文件夹 tsco
  • 将 UMD Javascript 模块导入浏览器

    你好 我正在对 RxJS 进行一些研究 我可以通过在浏览器中引用它来使用该库 如下所示 它使用全局对象命名空间变量 Rx 导入 我可以制作可观察的东西并做所有有趣的事情 当我将 src 更改为指向最新的 UMD 文件时 一切都会崩溃 如下所
  • 有没有办法在 onclick 触发时禁用 iPad/iPhone 上的闪烁/闪烁?

    所以我有一个有 onclick 事件的区域 在常规浏览器上单击时 它不会显示任何视觉变化 但在 iPad iPhone 上单击时 它会闪烁 闪烁 有什么办法可以阻止它在 iPad iPhone 上执行此操作吗 这是一个与我正在做的类似的示例
  • Vuejs 2:去抖动不适用于手表选项

    当我在 VueJs 中反跳此函数时 如果我提供毫秒数作为原语 它就可以正常工作 但是 如果我将其提供为对 prop 的引用 它会忽略它 这是道具的缩写版本 props debounce type Number default 500 这是不
  • 从数据库检查数据的异步解决方案各种循环子句

    我想要做的是异步检查数据库并从中获取结果 在我的应用程序中我试图实现Asynchronously将此步骤解决为 从数据库中检查手机号码JsonArray循环子句的种类 Create JsonArray从结果 打印创建的数组 我学到了足够多的
  • 使用 Vue 的多模式组件

    我在 Vue 中实现动态模式组件时遇到问题 A common approach I follow to display a set of data fetched from the db is I dump each of the rows
  • 我可以使用 AVX FMA 单元进行位精确的 52 位整数乘法吗?

    AXV2 doesn t have any integer multiplications with sources larger than 32 bit It does offer 32 x 32 gt 32 http www felix
  • 对于只触及我的工作表的 Google 表格脚本,收到“此应用程序未经验证”

    我正在编写一个 Google Sheets 脚本 我只想访问与 gs 文件关联的同一电子表格中的数据 似乎我应该有权在自己的电子表格中运行脚本 但是每当我运行一个函数时 我都会得到一个This app isn t verified信息 我该
  • 如何隐藏/禁用 Highcharts.js 中的图例框?

    我想问是否可以使用 HighCharts js 库隐藏图表中的所有图例框 var chart object chart renderTo render to type graph type colors graph colors title
  • Javascript Replace() 和 $1 问题

    我正在尝试创建一个脚本来搜索文本中的模式并在它找到的字符串周围包裹一个标签 shop attributes td each function this html function i html return html replace E 0
  • 从 FileReader 设置背景图像样式

    我正在寻找一种解决方案 允许我从文件上传输入中获取文件并通过设置 document body style backgroundImage 来预览它 以下代码用于在 Image 元素中显示预览 function setImage id tar
  • 使用 MongoDB 和 Nodejs 插入和查询日期

    我需要一些帮助在 mongodb 和 nodejs 中按日期查找记录 我将日期添加到抓取脚本中的 json 对象 如下所示 jsonObj last updated new Date 该对象被插入到 mongodb 中 我可以看到如下 la
  • Vue.js[vuex] 如何从突变中调度?

    我有一个要应用于 json 对象的过滤器列表 我的突变看起来像这样 const mutations setStars state payload state stars payload this dispatch filter setRev

随机推荐

  • 通过控制台使用文件流写入字节输出进度时出现内存不足异常

    我有以下代码 在写入大文件时抛出内存不足异常 我有什么遗漏的吗 我不确定为什么它会抛出内存不足错误 因为我认为文件流最多只能使用 4096 字节作为缓冲区 老实说 我不完全确定缓冲区意味着什么 任何建议将不胜感激 public static
  • Erlang 是集群计算世界的 C 语言吗?

    Erlang 似乎在网络上的级别和性能都很低 但没有非常丰富的类型系统或其他函数式语言提供的许多东西 所以在我看来它将成为集群编程的最低级别开发语言 直到出现其他东西并提 供像样的集群虚拟机和高级构造 对此有什么想法吗 C是集群计算的C 至
  • Flex/Actionscript 白色至透明

    我正在尝试使用动作脚本在我的 Flex 3 应用程序中编写一些内容 它将拍摄图像 当用户单击按钮时 它将去除所有白色 ish 像素并将它们转换为透明 我说白色 ish 是因为我尝试过纯白色 但边缘有很多伪影 使用以下代码我已经有点接近了 t
  • 如何将 HTML 页面滚动到给定的锚点

    我想让浏览器将页面滚动到给定的锚点 只需使用 JavaScript 我已经指定了一个name or id我的 HTML 代码中的属性 a a or h1 h1 我希望获得与您导航到相同的效果http server com path anch
  • Linux 内核崩溃消息中的“代码”是什么?

    Linux 内核加载失败后 我有以下堆栈跟踪和崩溃信息 3 684670 cut here 3 695507 Bad FPU state detected at fpu clear 0x91 0xc2 reinitializing FPU
  • PhpExcel中获取单元格背景颜色

    我在我的项目中使用Excel5 我已经尝试过以下代码 objPHPExcel gt getActiveSheet gt getStyle A1 gt getFill gt getStartColor gt getARGB and objPH
  • 删除 PHP 多维数组中的父级

    删除多维数组中匹配键的父级的最佳方法是什么 例如 假设我们有以下数组 我想找到 text a 然后删除其父数组 0 array Array 0 gt Array text gt a height gt 30 1 gt Array text
  • 禁用识别监听器的“就绪”声音

    我实现了一个识别监听器 http developer android com reference android speech RecognitionListener html在选项卡式片段活动内部 发生的情况是 当用户滚动时 实现侦听器的
  • Delphi:取消选择树视图中的选定项目

    有一个树视图 MultiSelect true 如果选择所有项目 则无法取消选择或再次选择 但其他项目除外 我想我需要做TreeView1 Selected Selected false on TForm1 TreeView1Click 但
  • sqlalchemy 没有指定驱动程序,但是指定了驱动程序

    根据这个link http docs sqlalchemy org en latest dialects mssql html module sqlalchemy dialects mssql pyodbc sqlalchemy 现在需要指
  • Django模板:如何显示其键中有一个点的字典? d['键名']

    我有一本这样的字典 dict name keyname with manydots 问题 我不能做 dict name keyname with manydots 我知道用 Django 模板不可能做到这一点 但是你发现的最好的解决方法是什
  • 如何从 Heroku 错误获取 Rails Heroku 日志回溯

    我在 Heroku Bamboo 堆栈上使用 Rails 3 2 3 我昨晚从日志中收到此错误 但无法准确诊断其发生的位置和原因 如何从 Heroku 日志中获取错误的完整回溯 app web 2 Unexpected error whil
  • 如何在 C# 中将固定字节/char[100] 转换为托管 char[]?

    在 C 中将固定字节或 char 100 转换为托管 char 的最佳方法是什么 我最终不得不使用指针算术 我想知道是否有更简单的方法 比如 memcpy 或其他方法 using System using System Collection
  • 使用故事板将数据从注释传递到详细视图 iOS

    我正在尝试将当前通过 Google Places API 加载到注释中的数据传递到我通过带有 segue 的故事板创建的详细视图控制器 单击每个注释上的详细信息披露后 我可以正确加载详细视图控制器 但我现在正在尝试传递数据 void map
  • IdentityServer4中的签名凭证是什么?

    我们正在使用 NET Core Web 应用程序实现 Identity Server 4 我浏览了身份服务器文档 配置身份服务器 使用 DI 时有以下行 AddTemporarySigningCredential 我试图理解这个签名凭证是什
  • 循环内的堆栈分配

    在 C 语言中 当你编写这样的代码时 void some function void while something char buf 4096 是否分配buf调用函数时会发生什么 或者循环的每次迭代都会发生单独的分配 如果我声明以下内容
  • 如何在 Android 中暂停录音?

    我的目标是暂停录制文件 我在 Android 开发者网站上看到它 但 Media Recorder 没有暂停选项 Java 支持以编程方式合并两个音频文件 但在 android 中它不起作用 从 Java 加入两个 WAV 文件 https
  • MapQuest API 密钥不再有效

    我们已经使用 MapQuest API 密钥几年了 但在过去 24 小时左右的某个时刻 地图已停止工作 我们收到错误 此密钥未获得此服务的授权 我登录后发现我们的旧密钥已被删除 并自动为新的 Open Maps API 生成了一个新密钥 我
  • Spark sql中如何使用outer apply

    我是 Spark sql 的新手 我正在将现有的 sql 查询转换为 Spark sql 我现有的 sql 查询包含需要在 Spark sql 中工作的外部应用函数 Spark sql 中的外部应用的替代方案是什么 非常感谢任何帮助 提前致
  • 为什么 0.1 + 0.2 在 JavaScript 中返回不可预测的浮点结果,而 0.2 + 0.3 则不会?

    0 1 0 2 gt 0 30000000000000004 0 2 0 2 gt 0 4 0 3 0 2 gt 0 5 我知道这与浮点有关 但这里到底发生了什么 根据 Eric Postpischil 的评论 这不是重复的 那只涉及为什么