It would be convenient to have an isapproxzero
method which is to ≈
what iszero
is to ==
.
In addition to being slighly more efficient than isapprox
, isapproxzero
would work out of the box with the default parameters.
Indeed, since atol
is zero by default we have for example:
julia> 1e-100 ≈ 0
false
An implementation if isapproxzero
could be
function isapproxzero(x::Number; rtol::Real=0, atol::Real=rtoldefault(typeof(x)), nans::Bool=false)
iszero(x) || (isfinite(x) && abs(x) <= atol) || (nans && isnan(x))
end
It might be helpful to accept an rtol
parameter even if it is not used since it allows to write functions like
function f(a, b, c; kws...)
... # do stuff
isapprox(a, b; kws...)
... # do stuff
isapproxzero(c; kws...)
... # do stuff
end
Indeed if isapproxzero
was not accepting rtol
, this function would fail when rtol
is given as a keyword to f
.
function isapproxzero(x::Number; rtol::Real=0, atol::Real=rtoldefault(x,y), nans::Bool=false)
y is not defined? Fundamentally what does it mean for a number to be small? Compared to what?
y is not defined?
Thanks ! I have corrected it
Fundamentally what does it mean for a number to be small? Compared to what?
We can say that isapproxzero(x::T)
is defined as the equivalent of isapprox(x, zero(x))
with atol
being rtoldefault(T)
. Being small here means being close to zero(x)
and close means with a small distance where the distance is the same than the one used for isapprox
, i.e. d(x, y) = abs(x - y)
for numbers and d(x, y) == norm(x - y)
for vectors.
Not sure that's a good idea, because isapprox(x,y) would be very different from isapproxzero(x-y).
isapprox(x, y)
would still correspond to isapproxzero(x-y, rtol=atol + rtol * max(abs(x), abs(y)))
. We need to manipulate the keyword arguments but that is to be expected for approximate comparison I suppose.
There is no nonzero default atol
that makes sense, because atol
is dimensionful (in that it depends on the overall scaling/units of the quantities under consideration).
Because of that, I don't think this function makes sense. If you want approximate equality to zero, you will always have to pass an application-appropriate atol
, in which case you might as well call norm(x) ≤ atol
.
What might make some sense is to implement something which effectively does isapproxzero(x) = isapprox(x + one(x), one(x))
?
So, the "absolute error for zero" compares to "the relative error for one" or something.
(Note: while it seems unintuitive for isapproxzero
require one()
to work, if one(x)
doesn't exist I can't see any sensible default "scale" to set the absolute tolerance to.)
From working with optimization algorithms, I have had many bitter experiences with code that assumes that all quantities are of order unity (oneunit(x)
) and does comparisons with that assumption in mind. I don't think we should build it into the standard library.
100% agree. If someone wants x + one(x) ≈ one(x)
they can write that.
Doesn't look like this will happen.
Most helpful comment
There is no nonzero default
atol
that makes sense, becauseatol
is dimensionful (in that it depends on the overall scaling/units of the quantities under consideration).Because of that, I don't think this function makes sense. If you want approximate equality to zero, you will always have to pass an application-appropriate
atol
, in which case you might as well callnorm(x) ≤ atol
.