nodeunit icon indicating copy to clipboard operation
nodeunit copied to clipboard

approx and deepApprox to safely compare numbers

Open josdejong opened this issue 12 years ago • 3 comments

Testing equallity of numbers is a tricky business because of possible round of errors in floating point numbers. For example the following test will unexpectedly fail as the result of the left expression is 0.22000000000000003 and not 0.22.

test.equal(2.2 / 10, 0.22);

It would be great to have functions like approx and deepApprox to safely compare numbers and objects/arrays containing numbers against each other. The function should compare whether the difference between the two numbers is at least a predefined factor epsilon smaller than the values itself (I guess there will be some edge cases when one of the values is zero, NaN, or Inf).

josdejong avatar Jul 16 '13 15:07 josdejong

I second this. I think this is really important.

Today I tried to have a crack at writing this, but I didn't get anywhere because I can't figure out how to build this library. make build fails on a fresh clone.

mdavis-xyz avatar Apr 15 '18 05:04 mdavis-xyz

What should the exact behaviour be when comparing near zero?

If we just test that the first n significant figures match, then that causes troubles near zero.

e.g. I think approx(1e-16,0) should pass.

But what about if both numbers are close to zero, but not exactly zero?

e.g. approx(1e-16,-1e-16). Should that pass? They're both approximately zero, but the difference between them is 100%.

mdavis-xyz avatar Apr 15 '18 05:04 mdavis-xyz

There are different strategies.

The simplest strategy is calculating the absolute difference.

nearlyEqual = Math.abs(a - b) < EPSILON

where:

  • EPSILON is the absolute difference between x and y.

Another common strategy is looking at the relative difference, which allows comparing values very close to zero too:

diff = Math.abs(x - y)
nearlyEqual = (diff <= Math.max(Math.abs(x), Math.abs(y)) * EPSILON) OR (diff < DBL_EPSILON)

where:

  • EPSILON is the relative difference between x and y.
  • DBL_EPSILON is the minimum positive floating point number such that 1.0 + DBL_EPSILON != 1.0. This is a constant with a value of approximately 2.2204460492503130808472633361816e-16

josdejong avatar Apr 15 '18 12:04 josdejong