# How can I redefine the operator "≈" to my desired tolerance

Currently, “The binary operator ≈ is equivalent to isapprox with the default arguments”
Hence: `x ≈ y` is equivalent to `isapprox(x,y)`

How can I redefine the operator w/ my own custom tolerance:
such that: `x ≈ y` is equivalent to `isapprox(x,y,atol=.01)`

``````ε = .1;
≊(a,b;ε=ε) = isapprox(a,b;atol=ε)

julia> 4.9 ≊ 5.0
true
``````
5 Likes

`≈` is just a function in Base, so you can do

``````julia> import Base.≈

julia> ≈(a::Float64, b::Float64) = isapprox(a, b, atol = 0.1)
isapprox (generic function with 11 methods)

julia> 4.9 ≈ 5.0
true
``````

but I would be careful about redefining how basic functionality like this works, at a minimum it makes it harder for others to understand your code. Choosing your own alternative Unicode identifier as you do above is preferable in my opinion, in these situations where I modify a defined infix operator I often add suffixes to indicate what the modification is doing, e.g. in this case maybe `≈₀₁`

7 Likes

This looks like a decent application for a macro:

``````function _approx!(ex::Expr, kwargs)
_approx!.(ex.args, Ref(kwargs))
if ex.head == :call && ex.args[1] == :≈
append!(ex.args, kwargs)
end
end

_approx!(x, kwargs) = nothing

macro approx(args...)
kwargs = [Expr(:kw, arg.args...) for arg in args[1:end-1]]
ex = args[end]
_approx!(ex, kwargs)
return ex
end
``````

With this you can do:

``````julia> @approx atol=0.1 rtol=0.01 begin
@show 1 ≈ 1.05
@show 1 ≈ 2
end
≈(1, 1.05, atol = 0.1, rtol = 0.01) = true
≈(1, 2, atol = 0.1, rtol = 0.01) = false
``````
7 Likes

This is nice because it is consistent with the behavior in Test.jl:

``````julia> using Test

julia> @test 0.5 ≈ 0.6 atol=0.1
Test Passed
``````
5 Likes

Note that there are tons of unassigned operators, so you can do something like

``````≅(a, b) = isapprox(a, b; atol = 0.1)
``````

and not have to worry about type piracy.

You can always just redefine `≈` within your module:

``````≈(x,y) = isapprox(x,y,atol=0.01)
``````

This doesn’t affect `Base.≈` and is not type-piracy… it is defining a new module-local function of the same name. Of course, this could be confusing for someone reading your code, so it might be clearer to give it a different name like ` ≈₂` (which is a valid operator name in Julia).

But if you just want to change the tolerance in some `@test` calls, you can also use `@test x ≈ y atol=0.01` to pass keyword arguments to `≈`.

6 Likes

Another option if you really want to use `≈`, is to define it in a local scope just around where you are using it.

``````julia> let ≈(a,b;ε=0.1) = isapprox(a,b;atol=ε)
4.9 ≈ 5.0
end
true
``````

This may be clearer than defining it at the module level.

7 Likes