Search code examples
rubyminitestapproximate

What is the difference between MiniTest's assert_in_delta and assert_in_epsilon methods?


Here is documentation for assert_in_delta:

assert_in_delta(exp, act, delta = 0.001, msg = nil) public

For comparing Floats. Fails unless exp and act are within delta of each other.

assert_in_delta Math::PI, (22.0 / 7.0), 0.01

And here is the documentation for assert_in_epsilon

assert_in_epsilon(a, b, epsilon = 0.001, msg = nil) public

For comparing Floats. Fails unless exp and act have a relative error less than epsilon.

These look very similar; what exactly is the difference? When would you use one method over the other?


Solution

  • The key difference is:

    • assert_in_delta is for absolute errors.
    • assert_in_epsilon is for relative errors.

    These are two different types of approximation error:

    The absolute error is the magnitude of the difference between the exact value and the approximation.

    The relative error is the absolute error divided by the magnitude of the exact value.


    assert_in_delta is easiest to understand, and will most commonly be used in tests.

    In the documentation's example: assert_in_delta Math::PI, (22.0 / 7.0), 0.01, this assertion will pass because 22.0/7 - Math::PI == 0.001264..., which is less than the allowed delta of 0.01.


    (From wikipedia)

    assert_in_epsilon is often used to compare approximations of numbers of wildly differing size.

    For example, approximating the number 1,000 with an absolute error of 3 is, in most applications, much worse than approximating the number 1,000,000 with an absolute error of 3; in the first case the relative error is 0.003 and in the second it is only 0.000003.

    To write this example in MiniTest, suppose we have an array of two values which we want to check are "approximately equal to" 1,000 and 1,000,000 respectively. We could write the following:

    # Using the default `epsilon` of 0.001
    assert_in_epsilon(1_000, actual[0])
    assert_in_epsilon(1_000_000, actual[1])
    

    This would be functionally equivalent to writing:

    assert_in_delta(1_000, actual[0], 1)
    assert_in_delta(1_000_000, actual[1], 1000)