skip to Main Content

I noticed that these evaluate to true:

  • (1 + Number.MIN_VALUE) === 1

  • Object.is(1 + Number.MIN_VALUE, 1)

From the documentation:

The Number.MIN_VALUE static data property represents the smallest positive numeric value representable in JavaScript.

My questions are:

  1. Since Number.MIN_VALUE is nonzero, why does adding it to a given number not result in a different number?

  2. What is the minimum value that can be added to a given number to result in a different number?

2

Answers


  1. For your questions:

    For more reliable comparisons, due to the nature of internal floating point representation, you can to compare like this:

    const x = 0.1, y = 0.2, expectedResult = 0.3;
    
    function equalNumber(a,b) {
      return Math.abs(a - b) < Number.EPSILON;
    }
    
    console.log('===', x + y === expectedResult);
    
    console.log('equalNumber', equalNumber((x+y), expectedResult));

    For your second question, that number you’re asking for is Number.EPSILON.

    Please note that with increasing numbers, the precision does decrease so this is not a very reliable way of testing for equality. For more information, read @Amadan’s answer, or read up on MDN.

    Login or Signup to reply.
  2. What is the minimum value that can be added to a given number to result in a different number?

    I am not sure there is an elegant way to do this in JavaScript. Fortunately, the way floating point numbers are represented is the same in most programming languages, so we can find out the answer elsewhere. Python, for example, has a method that reports the next representable floating point number after the given one, in a given direction. (C does as well; Python really just binds to the C one.) So, the first floating point number after 1.0 (in the direction of positive infinity) is:

    import math
    
    math.nextafter(1.0, math.inf)
    # => 1.0000000000000002
    

    The smallest number that you can add to 1.0 to change it should be somewhere around half of the difference, because of rounding:

    x1 = (math.nextafter(1.0, math.inf) - 1.0) / 2.0
    x1
    # => 1.1102230246251565e-16
    1.0 + x1
    # => 1.0
    
    x2 = math.nextafter(x1, math.inf)
    x2
    # => 1.1102230246251568e-16
    1.0 + x2
    # => 1.0000000000000002
    

    So x1 and x2 are neighbouring floating point numbers (i.e. there is no other floating point number between them), where one is too small to matter in addition to 1.0, and the other is just sufficient.

    We can bring it back to JavaScript to confirm:

    x1 = 1.1102230246251565e-16
    x2 = 1.1102230246251568e-16
    
    console.log(`1.0 + ${x1} = ${1.0 + x1}`)
    console.log(`1.0 + ${x2} = ${1.0 + x2}`)

    Because floating point numbers lose accuracy as they gain magnitude, "the minimum value that can be added to a given number to result in a different number" depends on the number: what works for 1.0 will not work for 100.0.

    Unfortunately, JavaScript does not have nextafter method. The question Fast nextafter function in JavaScript has a couple of answers that claim to implement it, but I am not mathematically strong enough to vouch for their correctness.

    From the above, it can also be seen that the smallest number that can be added to 1.0 to make a difference is not, in fact, Number.EPSILON, but just above half of it, and it is specific to the case of 1.0. Number.EPSILON is sufficiently large to change 2.0000000000000004, the next floating point number after 2.0:

    n1 = 2.0
    n2 = 2.0000000000000004
    
    console.log(`${n1} + Number.EPSILON = ${n1 + Number.EPSILON}`)
    console.log(`${n2} + Number.EPSILON = ${n2 + Number.EPSILON}`)
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search