javascript Number.EPSILON有哪些可能的使用场景?

2admgd59  于 2023-10-14  发布在  Java
关注(0)|答案(2)|浏览(115)

我在MZO上看到了JavaScript的文档,我读到了这一部分:
Number.EPSILON属性表示1和大于1的最小浮点数之差。
我还在页面上看到了这个例子:

var result = Math.abs(0.2 - 0.3 + 0.1);

console.log(result);
// expected output: 2.7755575615628914e-17

console.log(result < Number.EPSILON);// expected output: true

好的,我知道我可以使用这个函数来查看两个浮点数之间的差异,但我看不到在网站中的用途

mqxuamgl

mqxuamgl1#

请不要按照已接受答案中的代码配方进行操作

(或原始问题)

我已经开始了一场圣战,以摆脱世界上的狡猾的“错误”的建议,所以我想我不妨在这里写一个答案,而不仅仅是在对原始答案的评论中附议塞缪尔的好建议。
这里的原始问题实际上是关于这个的:
EPSILON号码是用来做什么的?
公认的答案忽略了问题中引用的示例代码的意图,并假设它应该是一个“近似相等”的测试。这不是示例代码试图显示的内容!
然后,这个公认的答案继续提供一些关于如何滥用Number. EPSILON的危险建议。数字。EPSILON * 不得 * 用于任何类型的“近似相等”测试!
所以,现在我们似乎有四个问题......

(该死的,这些东西在成倍增长!)

我们从最初的问题中得到了两个问题...

  1. EPSILON号码是用来做什么的?
    1.为什么我要使用一些代码来比较近似误差和Number.EPSILON?
    ......还有两个被接受的答案......
    1.为什么要避免在真实的网站上将数字与=====进行比较?
    1.如果Number.EPSILON不适合作为“公差”,我应该使用什么?

Q1:Number. Epperly是做什么用的?

**简短回答:这只是超级计算机科学家在计算中可能会用到的东西。

它不是为凡人程序员准备的。数字。Epperiment是“近似误差”的量度。为了获得任何实际用途,你需要根据你正在处理的数字的大小来缩放它。
如果你不熟悉浮点数的所有内部工作原理,那么Number.EPSILON不适合你(坦率地说,我还没有发现它在我所做的任何事情中的用途,所以我认为自己是“普通人”)。

Q2:为什么我想使用一些代码来比较近似误差与Number.EPSILON?

  • 简短的回答?你真的不知道**

在最初的问题中显示的示例代码只是超级书呆子的概念证明类型的东西。它在真实的世界计划中没有实际应用(如果不加以扩展)。
Mozilla示例所做的一切就是证明,对于一些小于1的数字,精度损失比JavaScript的Number. EPSILON小。这并不意味着你应该使用Number.EPSILON作为大于1.0的近似误差的容差!

Q3:为什么在JS中用==或=比较数字会有bug?

简短回答:因为JavaScript使用浮点数,它们并不精确。通常会有小的“近似误差”,你会得到“假”的答案,你会期望是“真”

这方面的经典例子是:0.1 + 0.2 != 0.3(此表达式在JavaScript中为TRUE!)
我已经整理了一个相当不错的初级读本,解释为什么这个“事实”是这样的,这避免了过于技术化。如果你感兴趣,可以看看https://dev.to/alldanielscott/why-floating-point-numbers-are-so-weird-e03
在所有的“原因”结束时,它归结为这条实用的建议:
永远不要使用==或=来比较两个浮点数!相反,检查这两个数字是否“足够接近”。

Q4:比较两个浮点数时,什么样的容差比较好?

简短回答:您需要为应用程序选择合理的容差。在你认为两个数字“足够相等”之前,你需要两个数字有多接近?

在你的程序中,价值观需要有多接近?+/- 0.1?+/- 0.000001?+/- 0.000000001?所有这些值的数量级都大于Number. EPSILON。

**警告:如果你曾经看到一些非常聪明的代码,声称已经解决了所有浮点数的“不稳定相等”问题,并且不需要你指定自己的公差,那么这是一个坏建议(无论它有多聪明)。

我已经深入分析了其中的原因:https://dev.to/alldanielscott/how-to-compare-numbers-correctly-in-javascript-1l4i
简而言之,Number.EPSILON太小而不能用作固定公差,在实际应用中,您经常会遇到比Number.EPSILON大得多的近似误差。
另外,你不应该在你的“相等”测试中使用一个不断变化的“容差”,否则它们的行为就不像相等测试,你的程序最终会出现微妙的(和烦人的)bug。在整个程序中使用您决定的固定公差。**

  • 或者至少在程序的一个离散组件中进行-不要让两个不同的公差“混合”。*

BONUS:证明为什么Number.EPSILON是一个糟糕的“错误”?

想要证明Number.EPSILON是一个糟糕的选择吗?这个怎么样?

for (i = 1; i < 100000000000000000000; i *= 100) {
  a = i + 0.1;   // Base
  b = 0.2;       // Additional value

  c = i + 0.3;   // Expected result of a + b

  console.log(
    'is ' + a + ' + ' + b + ' near ' + c + '? ... ' +
    (
      Math.abs((a + b - c) < Number.EPSILON) ?
      'yes' :
      'NOPE! DANGIT!!! ... Missed by ' + Math.abs(a + b - c).toFixed(30) + '!'
    )
  );
}

这将输出以下内容:

is 1.1 + 0.2 near 1.3? ... yes
is 100.1 + 0.2 near 100.3? ... yes
is 10000.1 + 0.2 near 10000.3? ... NOPE! DANGIT!!! ... Missed by 0.000000000001818989403545856476!
is 1000000.1 + 0.2 near 1000000.3? ... yes
is 100000000.1 + 0.2 near 100000000.3? ... yes
is 10000000000.1 + 0.2 near 10000000000.3? ... NOPE! DANGIT!!! ... Missed by 0.000001907348632812500000000000!
is 1000000000000.1 + 0.2 near 1000000000000.3? ... yes
is 100000000000000.1 + 0.2 near 100000000000000.3? ... yes
is 10000000000000000 + 0.2 near 10000000000000000? ... yes
is 1000000000000000000 + 0.2 near 1000000000000000000? ... yes

哎哟!事情的表现很奇怪,没有明显的模式!

奖励二:浮点数的更多奇特之处

如果你是一个“注重细节”的人,你可能会注意到上面输出的最后几行在被计算的表达式中缺少.1和.3。
小数部分并没有在输出中被截断:他们并没有在实际的数字上工作。如果你认为最后两个表达式应该相差0.2,这是可以理解的--但浮点数不是这样工作的。
我将把它作为一个练习留给读者,让他们弄清楚为什么最后两个表达式是“almost-nearly-equal”:不是虫子!
欢迎来到精度有限的浮点数世界!

6za6bjd0

6za6bjd02#

它可以用来帮助避免舍入误差。
例如,打开控制台并尝试以下操作:

console.log(Math.round(1.005 * 100) / 100);

我们期望1.01,但实际上得到1。但现在试试这个:

console.log(Math.round((1.005 + Number.EPSILON) * 100) / 100);

这是我们期待的1.01。
计算机本身就有浮点运算的问题。值1.005实际上存储为略小于1.005。添加Number.EPSILON将其推向边缘:

console.log(1.005 + Number.EPSILON);

你可以看到我们得到1.00500000000001,这使得它正确地四舍五入。

相关问题