Bug with isapprox?

Hi all,

I don’t understand the behavior of isapprox.

 julia> -3.03664471426105e-17 ≈ 0.0
  false

  julia>  1.0 - 3.03664471426105e-17 ≈ 1.0 - 0.0
  true

Can someone reproduce/explain what looks like a bug here?

Consider

julia> eps(0.0)
5.0e-324

julia> eps(1.0)
2.220446049250313e-16

and therefore

julia> 1.0 - 3.03664471426105e-17 == 1.0
true

I am very surprised that eps(0.0) is so small and I don’t understand why nextfloat(0.0) is 5.0e-324. Any hint?

4 Likes

This has nothing to do with the value of eps(0.0). x ≈ 0.0 will always give false for x ≠ 0, because tests only relative error. If x ≠ 0, then no significant digits of x match 0.0, so the result of x ≈ 0.0 is false.

In particular, x ≈ y tests norm(x-y) ≤ sqrt(eps(T))*max(norm(x),norm(y)) with T=typeof(real(x-y)), which tests whether about half of the significant digits match.

If you call isapprox(x,y) explicitly, you can pass an atol argument to instead pass an absolute tolerance, i.e. to test whether norm(x-y) ≤ atol. But since there is no reasonable way to pick a default value of atol (it is dimensionful, i.e. it depends on the scale of x and y), using sets atol to zero.

Note that 1.0 - 1e-10 ≈ 1.0 gives true, because more than half of the significant digits match 1.0.

9 Likes

I stand corrected. Thanks for chiming in! :slight_smile:

If you are writing tests with the standard Test module then you can write

@test x ≈ y atol=ε

The @test macro translates that to isapprox(x, y, atol=ε).

1 Like