最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

precision - Why is "(2.5 < 2.5 + Number.EPSILON)" false in JavaScript? - Stack Overflow

programmeradmin3浏览0评论

I want to find values less than a certain value in the array. I tried to use Number.EPSILON because the input value is not a definite value (eg 1.5000000000001).

I found something strange during the test:

>> (1.5 < 1.5 + Number.EPSILON) 
<- true 
>> (2.5 < 2.5 + Number.EPSILON)
<- false

Why is this? The test environment is the Chrome browser console.

I want to find values less than a certain value in the array. I tried to use Number.EPSILON because the input value is not a definite value (eg 1.5000000000001).

I found something strange during the test:

>> (1.5 < 1.5 + Number.EPSILON) 
<- true 
>> (2.5 < 2.5 + Number.EPSILON)
<- false

Why is this? The test environment is the Chrome browser console.

Share Improve this question edited Jun 4, 2019 at 12:12 Boann 50k16 gold badges124 silver badges152 bronze badges asked Jun 4, 2019 at 4:46 WakeupWakeup 1651 silver badge8 bronze badges 2
  • ((1.5 <1.5) + Number.EPSILON) === ((2.5 <2.5) + Number.EPSILON) true (1.5 <1.5 + Number.EPSILON) === (2.5 <2.5 + Number.EPSILON) false – Pandiyan Cool Commented Jun 4, 2019 at 4:53
  • It is related, in some way, to precision on floating point arithmetics. I believe next read can help to understand this concept: tutorialdocs./article/strange-javascript-number.html. There are a lot of articles about this. – Shidersz Commented Jun 4, 2019 at 5:26
Add a ment  | 

4 Answers 4

Reset to default 7

While Number.EPSILON itself can be represented precisely, this is no guarantee that adding values to it (or manipulating it any further at all) will result in perfect precision. In this case, 1.5 + Number.EPSILON results in a number slightly higher than 1.5:

console.log(1.5 + Number.EPSILON);

Which is clearly greater than 1.5. On the other hand, adding 2.5 to Number.EPSILON results in exactly 2.5 - the precision you were hoping for was lost during the addition process.

console.log(2.5 + Number.EPSILON);

2.5 < 2.5 evaluates to false, as expected.

Floating point numbers have a limited precision. Depending on the language and architecture, they are usually represented using 32 bits (float) or 64 bits (double, as of "double precision"). Although things bee blurry in an untyped language like JavaScript, there is still an actual machine underneath all this, and this machine has to perform floating point arithmetic.

The problem is that the results of certain putations cannot be represented accurately, given the limited precision. This is explained with some examples on the Wikipedia page about floating point artithmetic.

For people who want all the nitty-gritty details, the article about What Every Computer Scientist Should Know About Floating-Point Arithmetic is usually remended. But seriously: Not every puter scientist needs to know all this, and I'm pretty sure that only a handful people in the world have actually read the whole thing....

As an overly suggestive example: Imagine you had 5 digits to store a number. When you then have an addition like

  10000.
+     0.00001
--------------------
= 10000.

the .00001 part will basically be "truncated" because it does not fit into the 5 digits.

(That's not exactly how this works, but should get the idea across)

The actual value for Number.EPSILON, according to the documentation, is approximately 2.22 * 10-16, and is the "difference between 1 and the smallest floating point number greater than 1". (This is sometimes referred to as an ULP, Unit In The Last Place).

So adding this value to 1.0 will result in a different number. But adding it to 2.5 will not result in a different number, because the difference between 2.5 and the smallest floating point number greater than 2.5 is larger than this epsilon. The epsilon is thus truncated, like the .00001 in the example above.


Some languages/libraries may offer an "ulp" function that returns the difference between a given value and the next larger representable value. For example, in Java, you have

System.out.println(Math.ulp(1.0)); // Prints 2.220446049250313E-16
System.out.println(Math.ulp(2.5)); // Prints 4.440892098500626E-16

The first one obviously is what is stored in Number.EPSILON. The second one is the value that should yield a different value when added to 2.5. So

  • 2.5 < 2.5 + 4.4408E-16 would be false and
  • 2.5 < 2.5 + 4.4409E-16 would be true

Number.EPSILON is:

difference between 1 and the smallest floating point number greater than 1

Let's say this number is 0.00000000000000000000000001 for the argument's sake.

Now,

1.5 < 1.5 + 0.00000000000000000000000001 === true

and, when the base number which you are adding this extremely small fraction grows larger, the precision calculations of the JS math evaluation finds its boundary.

2 < 2 + 0.00000000000000000000000001 === false

/*
    ┌─────────────────────────────────────┐
    │ Number.EPSILON = 2¯⁵² ≈ 2.2 * 10¯¹⁶ │
    └─────────────────────────────────────┘

    Question 1: 2.5 < 2.5 + ε ?
                                                        2¯⁵¹
  2¹↴                                                   ⇩
    10100000000000000000000000000000000000000000000000000  = 2.5 (JS)
   +                                                     1 = ε
   ─────────────────────────────────────────────────────────────────────
                                                        ┌┐ (01, 1 truncated )
    101000000000000000000000000000000000000000000000000001
  = 10100000000000000000000000000000000000000000000000000  = 2.5 (JS)
     ╰──────────────────── 52-bit ──────────────────────╯

    ⭐️ Conclusion ❌: 2.5 === 2.5 + ε

    Question 2: 1.5 < 1.5 + ε ?
                                                        2¯⁵²
   2⁰↴                                                   ⇩
     11000000000000000000000000000000000000000000000000000 = 1.5 (JS)
   +                                                     1 = ε
   ─────────────────────────────────────────────────────────────────────
  =  11000000000000000000000000000000000000000000000000001 = 1.5 + ε (JS)
      ╰──────────────────── 52-bit ──────────────────────╯

    ⭐️ Conclusion ✅: 1.5 < 1.5 + ε

*/

// --------------- log ---------------

const ε = Number.EPSILON;

[
    2.5 < 2.5 + ε,      // false❗️
    1.5 < 1.5 + ε,      // true

].forEach(x => console.log(x))
发布评论

评论列表(0)

  1. 暂无评论