Number.EPSILON可能有哪些使用方案?

时间:2018-06-25 08:47:42

标签: javascript

我看到了MZO上JavaScript的文档,并且阅读了以下内容:

  

Number.EPSILON属性表示1与大于1的最小浮点数之间的差。

我也在页面上看到了这个例子:

Org -OWNS-> Badges -IS_AWARDED_TO-> User -IS_AWARDED-> Badges -HAS-> Skill
//Now I have all skills for a specific or multiple User for every badge awarded

好的,我知道可以使用此功能查看两个浮点数之间的差异,但看不到网站中的用法

2 个答案:

答案 0 :(得分:3)

如示例所示,它可用于测试浮点数的(近似)相等性。在普通数学中,您期望0.2 - 0.3 + 0.1等于精确的0,但是在Javascript中情况并非如此,因为浮点数是如何实现的。假设您有三个变量,并且要检查三个变量加在一起是否等于三分之一。如果它们是浮点数,则不能简单地检查是否a + b === c-相反,请检查它们的差值是否小于Number.EPSILON

const a = 0.1;
const b = 0.2;
const c = 0.3;

// Need to verify whether a + b = c
// Won't work:
console.log(a + b === c);

// Will work:
console.log(Math.abs(a + b - c) < Number.EPSILON);

浮点加法并不少见,也不需要验证数据。

答案 1 :(得分:0)

请不要遵循已接受答案中的代码配方

(或原始问题)

我已经开始进行一些努力,以摆脱模糊的“ epsilon”建议,因此我认为我不妨在这里写一个答案,而不仅仅是在评论原始答案时引用Samuel的好建议。

这里的原始问题确实是关于这个的:

  

Number.EPSILON应该用于什么?

接受的答案错过了问题中引用的示例代码的意图,并假定它应该是“近似相等”的测试。这不是示例代码试图显示的内容!

然后,接受的答案就如何滥用Number.EPSILON提出了一些危险的建议。 Number.EPSILON 绝不能用于任何类型的“近似相等”测试!


所以,现在我们似乎有四个问题……

(该死,这些事情正在成倍增加!)

原始问题中有两个问题……

  1. Number.EPSILON应该用于什么?
  2. 我为什么要使用一些将近似误差与Number.EPSILON进行比较的代码?

...以及被接受的答案提出了另外两个...

  1. 为什么要避免在真实网站上将数字与=====进行比较?
  2. 如果Number.EPSILON不能作为“公差”使用,我应该使用什么


问题1:Number.Epsilon应该用于什么?

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

对于普通的程序员来说,不是。 Number.Epsilon是“近似误差”的量度。为了充分利用它,您需要根据要处理的数字的大小对其进行缩放。

如果您不太熟悉浮点数的所有内部工作原理,那么Number.EPSILON不适合您(坦白地说,我在做任何事情时都没有发现它的用处,因此我算一下我自己就是“凡人”。


Q2:为什么我要使用一些将近似误差与Number.EPSILON进行比较的代码?

答案简短?你真的不知道。

原始问题中显示的示例代码只是超级书呆子的概念证明类型的东西。它在实际程序中没有任何实际应用(无需扩展)。

Mozilla示例所做的所有事情都是证明,某些数字小于1所导致的精度损失比Javascript的Number.EPSILON少 NOT 并不意味着您应该使用Number.EPSILON作为大于1.0的数字的近似误差的容差!

对于那些继续阅读的人,原始问题是在Mozilla开发网络站点上引用此页面:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILON-该页面仅列出Number.EPSILON的技术属性,而对它应该用于什么。


Q3:为什么尝试用==或===比较JS中的数字是错误的?

简短的回答:因为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大得多的近似误差。

此外,您不应在“平等”测试中使用不断变化的“容忍度”,否则它们的行为将不像平等测试,并且最终会导致程序中出现细微(令人讨厌)的错误。在整个程序中使用您确定的固定公差。**

** ,或者至少贯穿整个程序的独立组件-不允许两个不同的容差“混合”。


奖金:为什么Number.epsilon不好的“ 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

哦!!!事情表现得很奇怪,没有明显的规律!


奖金2:更多的浮点奇数

如果您是“注重细节”的人,您可能会注意到上面输出中的最后两行在要求值的表达式中缺少.1和.3。

小数部分不仅在输出中被切掉:它们在实际的数字中不存在。您会以为最后两个表达式应该以0.2的比率“超出”是可以原谅的,但这并不是浮点数的工作原理。

我将把它留给读者作为练习,以弄清楚为什么最后两个表达式会以“几乎几乎相等”的形式出现:这不是一个错误!

欢迎以有限的精度进入浮点数的世界!