stdlib
stdlib copied to clipboard
A function to compare two floating-point numbers
Inspied by Julia, I would like to have a function to compare two floating-point numbers with a tolerance, useful for testing.
elemental function is_approximated_1(x) result(nearly_equal)
real(dp),intent(in) :: x
logical :: nearly_equal
nearly_equal = abs(x) < d_tol
end function is_approximated_1
elemental function is_approximated_2(x,y) result(nearly_equal)
real(dp),intent(in) :: x,y
logical :: nearly_equal
nearly_equal = abs(x-y) < d_tol
end function is_approximated_2
elemental function is_approximated_2_tol(x,y,tol) result(nearly_equal)
real(dp),intent(in) :: x,y,tol
logical :: nearly_equal
nearly_equal = abs(x-y) < tol
end function is_approximated_2
Defining a general name:
interface is_approximated
module procedure is_approximated_1, is_approximated_2, is_approximated_2_tol
end interface is_approximated
Usage:
real(real64) :: x(5),y(5)
print *,any(is_approximated(x,y))
I would propose the following API:
is_approximated( x [, tol])
is_approximated( x, y, [, tol])
where tol
is optional
for both functions. A default tol
can be determined with optval
.
So, something like:
elemental function is_approximated_2_tol_dp(x,y,tol) result(nearly_equal)
real(dp),intent(in) :: x,y
real(dp), intent(in), optional :: tol
logical :: nearly_equal
nearly_equal = abs(x-y) < optval(tol, d_tol)
end function is_approximated_2_tol_dp
I would also think that we can drop is_approaximated(x [, tol])
because the user would do explicitely what the second API does implicitely.
This function could be used in the tests of stdlib
. A bitwise check with (almost) the same API could also be implemented. See #142 for more discussion.
Finally I may envisage some rebuttals from the community regarding this function because it is a one-line function.
I agree with your suggestion. A simple API is good enough.
I like this function because this comparison always occurs in any tests. A function with a clear purpose makes the code readable. For more precise comparisons, a bit-wise approach is preferred.
I'd suggest to go with something more general, which allows also relative error. I like quite a lot Numpy's isclose() function which enables to specify both, absolute and relative error. So the interface could be like
elemental function is_close(x, y, reltol, abstol) result(isclosel)
real(dp),intent(in) :: x, y
real(dp), intent(in), optional :: reltol, abstol
logical :: isclose
isclose = abs(x - y) < reltol * abs(y) + atol
end function is_close
Also, the name is_close()
is much shorter than is_approximated()
.
@aradi Julia also uses a similar function. Personally, for a quick comparison, I am using the following function (as suggested by Tamas_Papp).
abs(x - y) < reltol * (1+abs(x)+abs(y))
I suggest is_within.
In #488 @bilderbuchi mentions the Python math.isclose
as another possible implementation. The choices behind the Python version (available with Python >= 3.5) are discussed in a Python Enhancement Proposal PEP 485 which also considers the numpy and Boost C++ implementations.
Tagging @zoziha, @milancurcic