skip to Main Content

For example, originally I have code like this:

function(x,y){
  let z=x+y;
  .
  .
  .
}

later I found y must be the same as x, and want to refactor x+y to x * 2, but need to ensure the behaviour of whole program is the same before and after refactoring. Is x+x identical to x*2? I don’t know if + and * uses different calculation mechanisms and hence results in rounding to different results.

I tested:

for(let i=0.01;i<100;i++){
  if(i+i!=i*2){
    console.log(i);
    break;
  }
}

seems correct for some ranges of i, but don’t know if it is true for all float numbers.

2

Answers


  1. AFAICT, those expressions will always evaluate to the same values. This is given by the IEEE754 standard that specifies that the results of calculations should be the same as if the operations was carried out with infinite precision and then rounded to the nearest representable number.

    As an empirical sanity check I ran the following Python code:

    import numpy as np
    a = np.arange(2**24, dtype='uint32')
    for i in range(256):
        b = np.frombuffer(a + (i << 24), 'float32')
        np.testing.assert_equal(b+b, b*2)
    

    and only got a few warnings from when it tried to work with NaNs and infinities. This exhaustively tests all 32bit binary floats in ~20 seconds. Javascript uses 64bit floats, but given that they’re governed by the same rules it should be equivalent.

    Login or Signup to reply.
  2. JavaScript is an implementation of ECMAScript, and the ECMAScript specification says IEEE 754 arithmetic is used, with the IEEE-754 “double precision” (binary64) format. Clause 5.2.5 says “… When applied to Numbers, the operators refer to the relevant operations within IEEE 754-2019…”

    In IEEE 754, and in any reasonable floating-point system, the result of an operation is the exact mathematical result rounded according to whichever rounding rule is selected (such as round-to-nearest-ties-to-even, round toward zero, round upward, or round downward). IEEE 754-2019 4.3 says:

    … Except where stated otherwise, every operation shall be performed as if it first produced an intermediate result correct to infinite precision and with unbounded range, and then rounded that result according to one of the attributes in this clause…

    Since x+x and 2•x have the same mathematical result, the floating point operations x+x and 2*x must produce the same computed result. Both of them would have the same mathematical result with the same rounding rule applied, so the computed result must be the same.

    The above covers cases where x is a number, including +∞ and −∞. If x is a NaN, x+x and 2*x also produce a NaN, so the result is again the same. (Note that, in this case, x+x == 2*x would evaluate as false because a NaN is not equal to anything, not even itself. Nonetheless, the two operations produce the same result; the program behavior would be the same if 2*x were used in place of x+x or vice-versa.)

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search